FileDocCategorySizeDatePackage
MemberLoader.javaAPI DocJ2ME CLDC 1.17349Wed Feb 05 15:56:02 GMT 2003jcc

MemberLoader.java

/*
 *    MemberLoader.java    1.8    99/02/11 SMI
 *
 * Copyright © 2003 Sun Microsystems, Inc. All rights reserved.
 * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 */

package jcc;

import java.io.PrintStream;
import java.io.InputStream;
import java.io.StreamTokenizer;
import java.io.IOException;
import java.util.Hashtable;
import java.util.Vector;
import java.util.Enumeration;
import util.*;
import components.*;
import util.ClassFile;

/*
 * MemberLoader is the Jld subsystem
 * which processes the -memberlist option.
 * It reads the named file,
 * it causes class files to be read if necessary,
 * it manipulates the ClassInfo structures
 * by marking members to be included.
 * and finally it expunges all references to unwanted members.
 */

public class MemberLoader {
    String fname;
    StreamTokenizer in;
    ClassFileFinder finder;
    ClassReader        rdr;

    public MemberLoader( ClassReader r, ClassFileFinder f ){
    rdr = r;
    finder = f;
    }

    private ClassInfo enterClass( String classname, Vector v ){
    ClassInfo ce;
    classname = classname.intern();
    ce = components.ClassInfo.lookupClass( classname );
    if ( ce != null ) return ce;

    if ( rdr.readClass( classname, finder, v ) != 1 ){
        //could not find anywhere.
        System.err.println(Localizer.getString(
                   "memberloader.could_not_find_class", 
                    classname));
        return null; // or worse...
    }
    ce = (ClassInfo)( v.lastElement() );
    //
    // we know that this was loaded on account of us.
    // unlike most classes, this one will start life
    // as empty, with no members assumed.
    ce.flags &= ~(ClassInfo.INCLUDE_ALL);
    ce.clearMemberFlags( ClassMemberInfo.INCLUDE );
    return ce;
    }

    private boolean
    enterMember( ClassInfo ce, String name ){
    if ( (ce.flags&ClassInfo.INCLUDE_ALL) != 0 ){
        return true; // doesn't matter what we do anyway!
    }
    ClassMemberInfo t[];
    String sig;
    // determine if this is data or method by looking
    // at the signature, or lack thereof.
    int sigstart = name.indexOf( '(' );
    if ( sigstart == -1 ){
        // this is data.
        // too bad we cannot use the standard procedure
        // that  components/FMIrefConstant.find() uses,
        // but we cannot because the hash ID requires
        // data type signature information, which we lack.
        t = ce.fields;
        sig = null;
    } else {
        // this is code.
        //
        sig = name.substring( sigstart );
        name = name.substring( 0, sigstart );
        t = ce.methods;
    }
    int l = t.length;
    for ( int i = 0; i < l ; i++ ){
        if ( t[i].name.string.equals( name ) ){
        if ( (sig == null) || sig.equals( t[i].type.string ) ){
            t[i].flags |= ClassMemberInfo.INCLUDE;
            return true; // done.
        }
        }
    }
    System.err.println(Localizer.getString(
                   "memberloader.could_not_find_member",
                    ce.className, name));
    return false;
    }

    private void openStream( String name ) throws IOException {
    fname = name;
    in = new StreamTokenizer(
        new java.io.BufferedInputStream(
        new java.io.FileInputStream( fname ) ) );
    in.resetSyntax();
    in.eolIsSignificant( true );
    in.whitespaceChars( 0, 0x20 );
    in.wordChars( '!', '~' );
    in.commentChar('#');
    in.ordinaryChar( '.' );

    }

    private void oops( String lmsg ) throws DataFormatException {
    String errmsg = Localizer.getString(
                "memberloader.dependence_file_error_near_line", 
                 fname, Integer.toString(in.lineno()));
    if ( lmsg != null ){
        errmsg += Localizer.getString(lmsg);
    }
    in = null; // when we bail, close the file.
    throw new DataFormatException( errmsg );
    }

    /*
     * Read output of JavaFilter
     */
    public void readFromFile( String fname, Vector classlist )throws DataFormatException, IOException{
    int t;
    openStream(fname);
    while ( (t = in.nextToken() ) != StreamTokenizer.TT_EOF ){
        /*
         * Process a line of input. It may be empty
         * or contain only a comment.
         * Else there must be a class name.
         * If the class name is followed by a .,
         * then a member name follows. The name
         * will include a signature, if a method is named.
         * No signature is needed for data members.
         */
        if ( t == StreamTokenizer.TT_EOL )
        continue;
        String className;
        String memberName;
        String sig;
        if ( t != StreamTokenizer.TT_WORD )
        oops("memberloader.missing_classname");
        className = in.sval;
        ClassInfo ce = enterClass( className, classlist );
        if ( (t=in.nextToken()) == StreamTokenizer.TT_EOL ){
        continue; // class name only
        }
        if ( t != '.' ){
        oops( "memberloader.syntax_error" );
        continue;
        }
        if ( (t=in.nextToken()) != StreamTokenizer.TT_WORD ){
        oops("memberloader.malformed_member_name");
        continue;
        }
        memberName = in.sval;
        /*
         * Now that we've read the names, process it.
         */
        if ( ce != null )
        enterMember( ce, memberName );

        if ( in.nextToken() != StreamTokenizer.TT_EOL )
        oops("memberloader.extra_material");
    }
    in = null; // close the file.
    }

    /*
     * Traverse the class list.
     * Delete unneeded methods!!
     */

    private int deleteMembers( ClassMemberInfo mlist[] ){
    if ( mlist == null || mlist.length == 0 )
        return 0; // trivial case.
    int n = mlist.length;
    int ndeleted = 0;
    for ( int i = 0; i < n; i++ ){
        if ( (mlist[i].flags&ClassMemberInfo.INCLUDE) == 0 ){
        mlist[i].index = -1; // obvious error value.
        mlist[i] = null;
        ndeleted+=1;
        }
    }
    return ndeleted;
    }

    private static void copyNonNull( ClassMemberInfo from[], ClassMemberInfo to[] ){
        int n = from.length;
        int j = 0;
        for ( int i = 0; i < n; i++ ){
        if ( from[i] != null ){
            from[i].index = j;
            to[j++] = from[i];
        }
        }
    }

    private void loadMembers( ClassInfo ci ){
    int ndeleted = deleteMembers( ci.methods );
    if ( ndeleted != 0 ){
        int n = ci.methods.length;
        MethodInfo newlist[] = new MethodInfo[ n-ndeleted ];
        copyNonNull( ci.methods, newlist );
        ci.methods = newlist;
    }
    ndeleted = deleteMembers( ci.fields );
    if ( ndeleted != 0 ){
        int n = ci.fields.length;
        FieldInfo newlist[] = new FieldInfo[ n-ndeleted ];
        copyNonNull( ci.fields, newlist );
        ci.fields = newlist;
    }
    }

    /*
     * This is serious!
     * Iterate through all our classes.
     * Look at all the members
     * When I see one that doesn't have isLoaded set,
     * just delete it! This could be very weird!!!
     */
    public void deleteUnwantedMembers( Vector classes )
    {
    Enumeration e = classes.elements();
    while ( e.hasMoreElements() ){
        ClassInfo ci = (ClassInfo) e.nextElement();
        if ( (ci.flags&ClassInfo.INCLUDE_ALL) != 0 )
        continue; // a fully-loaded class.
        loadMembers( ci );
    }
    }

}