FileDocCategorySizeDatePackage
TouchDexLoader.javaAPI DocAndroid 1.5 API11013Wed May 06 22:41:02 BST 2009dalvik.system

TouchDexLoader

public class TouchDexLoader extends ClassLoader
Cloned out of PathClassLoader for TouchDex. This could be made substantially smaller, since we don't need most of this.

Fields Summary
private String
path
private boolean
initialized
private String[]
mPaths
private File[]
mFiles
private ZipFile[]
mZips
private dalvik.system.DexFile[]
mDexs
private String[]
mLibPaths
Constructors Summary
public TouchDexLoader(String path, ClassLoader parent)
Create a ClassLoader that finds files in the specified path.

        super(parent);

        if (path == null)
            throw new NullPointerException();

        this.path = path;
    
Methods Summary
private voidensureInit()

        if (initialized) {
            return;
        }
        
        initialized = true;
        
        mPaths = path.split(":");
        //System.out.println("TouchDexLoader: " + mPaths);
        mFiles = new File[mPaths.length];
        mZips = new ZipFile[mPaths.length];
        mDexs = new DexFile[mPaths.length];

        boolean wantDex = 
            System.getProperty("android.vm.dexfile", "").equals("true");

        /* open all Zip and DEX files up front */
        for (int i = 0; i < mPaths.length; i++) {
            //System.out.println("My path is: " + mPaths[i]);
            File pathFile = new File(mPaths[i]);
            mFiles[i] = pathFile;

            if (pathFile.isFile()) {
                if (false) {    //--------------------
                try {
                    mZips[i] = new ZipFile(pathFile);
                }
                catch (IOException ioex) {
                    // expecting IOException and ZipException
                    //System.out.println("Failed opening '" + archive + "': " + ioex);
                    //ioex.printStackTrace();
                }
                }               //--------------------
                if (wantDex) {
                    /* we need both DEX and Zip, because dex has no resources */
                    try {
                        mDexs[i] = new DexFile(pathFile);
                    }
                    catch (IOException ioex) {
                        System.err.println("Couldn't open " + mPaths[i]
                            + " as DEX");
                    }
                }
            } else {
                System.err.println("File not found: " + mPaths[i]);
            }
        }

        /*
         * Prep for native library loading.
         */
        String pathList = System.getProperty("java.library.path", ".");
        String pathSep = System.getProperty("path.separator", ":");
        String fileSep = System.getProperty("file.separator", "/");

        mLibPaths = pathList.split(pathSep);

        // Add a '/' to the end so we don't have to do the property lookup
        // and concatenation later.
        for (int i = 0; i < mLibPaths.length; i++) {
            if (!mLibPaths[i].endsWith(fileSep))
                mLibPaths[i] += fileSep;
            if (false)
                System.out.println("Native lib path:  " + mLibPaths[i]);
        }
    
protected java.lang.ClassfindClass(java.lang.String name)
Find the class with the specified name. None of our ancestors were able to find it, so it's up to us now. "name" is a "binary name", e.g. "java.lang.String" or "java.net.URLClassLoader$3$1". This method will either return a valid Class object or throw an exception. Does not return null.

        ensureInit();
        
        byte[] data = null;
        int i;

        //System.out.println("TouchDexLoader " + this + ": findClass '" + name + "'");

        for (i = 0; i < mPaths.length; i++) {
            //System.out.println("My path is: " + mPaths[i]);

            if (mDexs[i] != null) {
                String slashName = name.replace('.", '/");
                Class clazz = mDexs[i].loadClass(slashName, this);
                if (clazz != null)
                    return clazz;
            } else if (mZips[i] != null) {
                String fileName = name.replace('.", '/") + ".class";
                data = loadFromArchive(mZips[i], fileName);
            } else {
                File pathFile = mFiles[i];
                if (pathFile.isDirectory()) {
                    String fileName =
                        mPaths[i] + "/" + name.replace('.", '/") + ".class";
                    data = loadFromDirectory(fileName);
                } else {
                    //System.out.println("TouchDexLoader: can't find '"
                    //    + mPaths[i] + "'");
                }

            }

            if (data != null) {
                //System.out.println("  found class " + name);
                int dotIndex = name.lastIndexOf('.");
                if (dotIndex != -1) {
                    String packageName = name.substring(0, dotIndex);
                    synchronized (this) {
                        Package packageObj = getPackage(packageName);
                        if (packageObj == null) {
                            definePackage(packageName, null, null,
                                    null, null, null, null, null);
                        }
                    }
                }
                
                return defineClass(name, data, 0, data.length);
            }
        }

        throw new ClassNotFoundException(name + " in loader " + this);
    
protected java.lang.StringfindLibrary(java.lang.String libname)
Find a native library. Return the full pathname of the first appropriate-looking file we find.

        ensureInit();

        String fileName = System.mapLibraryName(libname);
        for (int i = 0; i < mLibPaths.length; i++) {
            String pathName = mLibPaths[i] + fileName;
            File test = new File(pathName);

            if (test.exists())
                return pathName;
        }

        return null;
    
protected java.net.URLfindResource(java.lang.String name)

        ensureInit();
        
        byte[] data = null;
        int i;

        //System.out.println("TouchDexLoader: findResource '" + name + "'");

        for (i = 0; i < mPaths.length; i++) {
            File pathFile = mFiles[i];
            ZipFile zip = mZips[i];
            if (zip != null) {
                if (isInArchive(zip, name)) {
                    //System.out.println("  found " + name + " in " + pathFile);
                    // Create URL correctly - was XXX, new code should be ok.
                    try {
                        return new URL("jar:file://" + pathFile + "!/" + name);
                    }
                    catch (MalformedURLException e) {
                        throw new RuntimeException(e);
                    }
                }
            } else if (pathFile.isDirectory()) {
                File dataFile = new File(mPaths[i] + "/" + name);
                if (dataFile.exists()) {
                    //System.out.println("  found resource " + name);
                    // Create URL correctly - was XXX, new code should be ok.
                    try {
                        return new URL("file:" + name);
                    }
                    catch (MalformedURLException e) {
                        throw new RuntimeException(e);
                    }
                }
            } else if (pathFile.isFile()) {
            } else {
                System.err.println("TouchDexLoader: can't find '"
                    + mPaths[i] + "'");
            }
        }

        return null;
    
private booleanisInArchive(java.util.zip.ZipFile zip, java.lang.String name)

        return zip.getEntry(name) != null;
    
private byte[]loadFromArchive(java.util.zip.ZipFile zip, java.lang.String name)

        ZipEntry entry;

        entry = zip.getEntry(name);
        if (entry == null)
            return null;

        ByteArrayOutputStream byteStream;
        InputStream stream;
        int count;

        /*
         * Copy the data out of the stream.  Because we got the ZipEntry
         * from a ZipFile, the uncompressed size is known, and we can set
         * the initial size of the ByteArrayOutputStream appropriately.
         */
        try {
            stream = zip.getInputStream(entry);
            byteStream = new ByteArrayOutputStream((int) entry.getSize());
            byte[] buf = new byte[4096];
            while ((count = stream.read(buf)) > 0)
                byteStream.write(buf, 0, count);

            stream.close();
        }
        catch (IOException ioex) {
            //System.out.println("Failed extracting '" + archive + "': " +ioex);
            return null;
        }

        //System.out.println("  loaded from Zip");
        return byteStream.toByteArray();
    
private byte[]loadFromDirectory(java.lang.String path)

        RandomAccessFile raf;
        byte[] fileData;

        //System.out.println("Trying to load from " + path);
        try {
            raf = new RandomAccessFile(path, "r");
        }
        catch (FileNotFoundException fnfe) {
            //System.out.println("  Not found: " + path);
            return null;
        }

        try {
            fileData = new byte[(int) raf.length()];
            raf.read(fileData);
            raf.close();
        }
        catch (IOException ioe) {
            System.err.println("Error reading from " + path);
            // swallow it, return null instead
            fileData = null;
        }

        return fileData;