// Copyright (c) Corporation for National Research Initiatives // Copyright 2000 Samuele Pedroni package org.python.core; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.net.MalformedURLException; import java.net.URL; import java.util.StringTokenizer; import java.util.zip.ZipEntry; import org.python.core.util.RelativeFile; public class SyspathJavaLoader extends ClassLoader { private static final char SLASH_CHAR = '/'; public SyspathJavaLoader(ClassLoader parent) { super(parent); } /** * Returns a byte[] with the contents read from an InputStream. * * The stream is closed after reading the bytes. * * @param input The input stream * @param size The number of bytes to read * * @return an array of byte[size] with the contents read * */ private byte[] getBytesFromInputStream(InputStream input, int size) { try { byte[] buffer = new byte[size]; int nread = 0; while(nread < size) { nread += input.read(buffer, nread, size - nread); } return buffer; } catch (IOException exc) { return null; } finally { try { input.close(); } catch (IOException e) { // Nothing to do } } } private byte[] getBytesFromDir(String dir, String name) { try { File file = getFile(dir, name); if (file == null) { return null; } return getBytesFromInputStream(new FileInputStream(file), (int)file.length()); } catch (FileNotFoundException e) { return null; } catch(SecurityException e) { return null; } } private byte[] getBytesFromArchive(SyspathArchive archive, String name) { String entryname = name.replace('.', SLASH_CHAR) + ".class"; ZipEntry ze = archive.getEntry(entryname); if (ze == null) { return null; } try { return getBytesFromInputStream(archive.getInputStream(ze), (int)ze.getSize()); } catch (IOException e) { return null; } } protected Package definePackageForClass(String name) { int lastDotIndex = name.lastIndexOf('.'); if (lastDotIndex < 0) { return null; } String pkgname = name.substring(0, lastDotIndex); Package pkg = getPackage(pkgname); if (pkg == null) { pkg = definePackage(pkgname, null, null, null, null, null, null, null); } return pkg; } @Override protected Class<?> findClass(String name) throws ClassNotFoundException { PySystemState sys = Py.getSystemState(); ClassLoader sysClassLoader = sys.getClassLoader(); if (sysClassLoader != null) { // sys.classLoader overrides this class loader! return sysClassLoader.loadClass(name); } // Search the sys.path for a .class file matching the named class. PyList path = sys.path; for (int i = 0; i < path.__len__(); i++) { byte[] buffer; PyObject entry = replacePathItem(sys, i, path); if (entry instanceof SyspathArchive) { SyspathArchive archive = (SyspathArchive)entry; buffer = getBytesFromArchive(archive, name); } else { if (!(entry instanceof PyUnicode)) { entry = entry.__str__(); } String dir = entry.toString(); buffer = getBytesFromDir(dir, name); } if (buffer != null) { definePackageForClass(name); return defineClass(name, buffer, 0, buffer.length); } } // couldn't find the .class file on sys.path throw new ClassNotFoundException(name); } @Override protected URL findResource(String res) { PySystemState sys = Py.getSystemState(); if (res.charAt(0) == SLASH_CHAR) { res = res.substring(1); } String entryRes = res; if (File.separatorChar != SLASH_CHAR) { res = res.replace(SLASH_CHAR, File.separatorChar); entryRes = entryRes.replace(File.separatorChar, SLASH_CHAR); } PyList path = sys.path; for (int i = 0; i < path.__len__(); i++) { PyObject entry = replacePathItem(sys, i, path); if (entry instanceof SyspathArchive) { SyspathArchive archive = (SyspathArchive) entry; ZipEntry ze = archive.getEntry(entryRes); if (ze != null) { try { return new URL("jar:file:" + entry.__str__().toString() + "!/" + entryRes); } catch (MalformedURLException e) { throw new RuntimeException(e); } } continue; } if (!(entry instanceof PyUnicode)) { entry = entry.__str__(); } String dir = sys.getPath(entry.toString()); try { File resource = new File(dir, res); if (!resource.exists()) { continue; } return resource.toURI().toURL(); } catch (MalformedURLException e) { throw new RuntimeException(e); } } return null; } static PyObject replacePathItem(PySystemState sys, int idx, PyList paths) { PyObject path = paths.__getitem__(idx); if (path instanceof SyspathArchive) { // already an archive return path; } try { // this has the side affect of adding the jar to the PackageManager during the // initialization of the SyspathArchive path = new SyspathArchive(sys.getPath(path.toString())); } catch (Exception e) { return path; } paths.__setitem__(idx, path); return path; } private File getFile(String dir, String name) { String accum = ""; boolean first = true; for (StringTokenizer t = new StringTokenizer(name, "."); t .hasMoreTokens();) { String token = t.nextToken(); if (!first) { accum += File.separator; } accum += token; first = false; } return new RelativeFile(dir, accum + ".class"); } }