Package soot

Source Code of soot.SourceLocator$FoundFile

/* Soot - a J*va Optimization Framework
* Copyright (C) 2004 Ondrej Lhotak
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/

package soot;
import soot.JavaClassProvider.JarException;
import soot.options.*;
import java.util.*;
import java.util.zip.*;
import java.io.*;

/** Provides utility methods to retrieve an input stream for a class name, given
* a classfile, or jimple or baf output files. */
public class SourceLocator
{
    public SourceLocator( Singletons.Global g ) {}
    public static SourceLocator v() { return G.v().soot_SourceLocator(); }

    protected Set<ClassLoader> additionalClassLoaders = new HashSet<ClassLoader>();
   
    /** Given a class name, uses the soot-class-path to return a ClassSource for the given class. */
    public ClassSource getClassSource(String className)
    {
        if( classPath == null ) {
            classPath = explodeClassPath(Scene.v().getSootClassPath());
        }
        if( classProviders == null ) {
            setupClassProviders();
        }
        JarException ex = null;
        for (ClassProvider cp : classProviders) {
            try {
            ClassSource ret = cp.find(className);
              if( ret != null ) return ret;
            } catch(JarException e) {
              ex = e;
            }
        }
        if(ex!=null) throw ex;
        for(final ClassLoader cl: additionalClassLoaders) {
            try {
              ClassSource ret = new ClassProvider() {
         
          public ClassSource find(String className) {
                String fileName = className.replace('.', '/') + ".class";
            return new CoffiClassSource(className, cl.getResourceAsStream(fileName));
          }

              }.find(className);
              if( ret != null ) return ret;
            } catch(JarException e) {
              ex = e;
            }
        }
        if(ex!=null) throw ex;
        return null;
    }
   
    public void additionalClassLoader(ClassLoader c) {
      additionalClassLoaders.add(c);
    }

    private void setupClassProviders() {
        classProviders = new LinkedList<ClassProvider>();
        switch( Options.v().src_prec() ) {
            case Options.src_prec_class:
                classProviders.add(new CoffiClassProvider());
                classProviders.add(new JimpleClassProvider());
                classProviders.add(new JavaClassProvider());
                break;
            case Options.src_prec_only_class:
                classProviders.add(new CoffiClassProvider());
                break;
            case Options.src_prec_java:
                classProviders.add(new JavaClassProvider());
                classProviders.add(new CoffiClassProvider());
                classProviders.add(new JimpleClassProvider());
                break;
            case Options.src_prec_jimple:
                classProviders.add(new JimpleClassProvider());
                classProviders.add(new CoffiClassProvider());
                classProviders.add(new JavaClassProvider());
                break;
            default:
                throw new RuntimeException("Other source precedences are not currently supported.");
        }
    }

    private List<ClassProvider> classProviders;
    public void setClassProviders( List<ClassProvider> classProviders ) {
        this.classProviders = classProviders;
    }

    private List<String> classPath;
    public List<String> classPath() { return classPath; }
    public void invalidateClassPath() {
        classPath = null;
    }

    private List<String> sourcePath;
    public List<String> sourcePath() {
        if( sourcePath == null ) {
            sourcePath = new ArrayList<String>();
            for (String dir : classPath) {
                if( !isJar(dir) ) sourcePath.add(dir);
            }
        }
        return sourcePath;
    }

    private boolean isJar(String path) {
  File f = new File(path)
  if(f.isFile() && f.canRead()) {    
      if(path.endsWith("zip") || path.endsWith("jar")) {
    return true;
      } else {
    G.v().out.println("Warning: the following soot-classpath entry is not a supported archive file (must be .zip or .jar): " + path);
      }
  } 
  return false;
    }

    public List<String> getClassesUnder(String aPath) {
        List<String> fileNames = new ArrayList<String>();

  if (isJar(aPath)) {
      List inputExtensions = new ArrayList(2);
            inputExtensions.add(".class");
            inputExtensions.add(".jimple");
            inputExtensions.add(".java");

      try {
    ZipFile archive = new ZipFile(aPath);
    for (Enumeration entries = archive.entries();
         entries.hasMoreElements(); ) {
        ZipEntry entry = (ZipEntry) entries.nextElement();
        String entryName = entry.getName();
        int extensionIndex = entryName.lastIndexOf('.');
        if (extensionIndex >= 0) {
      String entryExtension = entryName.substring(extensionIndex);
      if (inputExtensions.contains(entryExtension)) {
          entryName = entryName.substring(0, extensionIndex);
          entryName = entryName.replace('/', '.');
          fileNames.add(entryName);
      }
        }
    }
      } catch(IOException e) {
    G.v().out.println("Error reading " + aPath + ": "
          + e.toString());
    throw new CompilationDeathException(CompilationDeathException.COMPILATION_ABORTED);
      }
  } else {
      File file = new File(aPath);

      File[] files = file.listFiles();
      if (files == null) {
    files = new File[1];
    files[0] = file;
      }

      for (File element : files) {
    if (element.isDirectory()) {
        List<String> l =
      getClassesUnder(
          aPath + File.separatorChar + element.getName());
        Iterator<String> it = l.iterator();
        while (it.hasNext()) {
      String s = it.next();
      fileNames.add(element.getName() + "." + s);
        }
    } else {
        String fileName = element.getName();

        if (fileName.endsWith(".class")) {
      int index = fileName.lastIndexOf(".class");
      fileNames.add(fileName.substring(0, index));
        }

        if (fileName.endsWith(".jimple")) {
      int index = fileName.lastIndexOf(".jimple");
      fileNames.add(fileName.substring(0, index));
        }

        if (fileName.endsWith(".java")) {
      int index = fileName.lastIndexOf(".java");
      fileNames.add(fileName.substring(0, index));
        }
    }
      }
  }
        return fileNames;
    }

    public String getFileNameFor(SootClass c, int rep) {
        if (rep == Options.output_format_none)
            return null;

        StringBuffer b = new StringBuffer();

        if( !Options.v().output_jar() ) {
            b.append(getOutputDir());
        }

        if ((b.length() > 0) && (b.charAt(b.length() - 1) != File.separatorChar))
            b.append(File.separatorChar);

        if (rep != Options.output_format_dava) {
            if(rep == Options.output_format_class) {
                b.append(c.getName().replace('.', File.separatorChar));
            } else {
                b.append(c.getName());
            }
            b.append(getExtensionFor(rep));

            return b.toString();
        }

        b.append("dava");
        b.append(File.separatorChar);
        {
            String classPath = b.toString() + "classes";
            File dir = new File(classPath);

            if (!dir.exists())
                try {
                    dir.mkdirs();
                } catch (SecurityException se) {
                    G.v().out.println("Unable to create " + classPath);
                    throw new CompilationDeathException(CompilationDeathException.COMPILATION_ABORTED);
                }
        }

        b.append("src");
        b.append(File.separatorChar);

        String fixedPackageName = c.getJavaPackageName();
        if (fixedPackageName.equals("") == false) {
            b.append(fixedPackageName.replace('.', File.separatorChar));
            b.append(File.separatorChar);
        }

        {
            String path = b.toString();
            File dir = new File(path);

            if (!dir.exists())
                try {
                    dir.mkdirs();
                } catch (SecurityException se) {
                    G.v().out.println("Unable to create " + path);
                    throw new CompilationDeathException(CompilationDeathException.COMPILATION_ABORTED);
                }
        }

        b.append(c.getShortJavaStyleName());
        b.append(".java");

        return b.toString();
    }

    /* This is called after sootClassPath has been defined. */
    public Set<String> classesInDynamicPackage(String str) {
        HashSet<String> set = new HashSet<String>(0);
        StringTokenizer strtok = new StringTokenizer(
                Scene.v().getSootClassPath(), String.valueOf(File.pathSeparatorChar));
        while (strtok.hasMoreTokens()) {
            String path = strtok.nextToken();

            // For jimple files
            List<String> l = getClassesUnder(path);
            for (String filename : l) {
                if (filename.startsWith(str))
                    set.add(filename);
            }

            // For class files;
            path = path + File.pathSeparatorChar;
            StringTokenizer tokenizer = new StringTokenizer(str, ".");
            while (tokenizer.hasMoreTokens()) {
                path = path + tokenizer.nextToken();
                if (tokenizer.hasMoreTokens())
                    path = path + File.pathSeparatorChar;
            }
            l = getClassesUnder(path);
            for (String string : l)
        set.add(str + "." + string);
        }
        return set;
    }

    public String getExtensionFor(int rep) {
        switch (rep) {
            case Options.output_format_baf:      return ".baf";
            case Options.output_format_b:        return ".b";
            case Options.output_format_jimple:   return ".jimple";
            case Options.output_format_jimp:     return ".jimp";
            case Options.output_format_shimple:  return ".shimple";
            case Options.output_format_shimp:    return ".shimp";
            case Options.output_format_grimp:    return ".grimp";
            case Options.output_format_grimple:  return ".grimple";
            case Options.output_format_class:    return ".class";
            case Options.output_format_dava:     return ".java";
            case Options.output_format_jasmin:   return ".jasmin";
            case Options.output_format_xml:      return ".xml";
            default:
                throw new RuntimeException();
        }
    }

    public String getOutputDir() {
        String ret = Options.v().output_dir();
        if( ret.length() == 0 ) ret = "sootOutput";
        File dir = new File(ret);

        if (!dir.exists()) {
            try {
                if( !Options.v().output_jar() ) {
                    dir.mkdirs();
                }
            } catch (SecurityException se) {
                G.v().out.println("Unable to create " + ret);
                throw new CompilationDeathException(CompilationDeathException.COMPILATION_ABORTED);
            }
        }
        return ret;
    }

    /** Explodes a class path into a list of individual class path entries. */
    protected List<String> explodeClassPath( String classPath ) {
        List<String> ret = new ArrayList<String>();

        StringTokenizer tokenizer =
            new StringTokenizer(classPath, File.pathSeparator);
        while( tokenizer.hasMoreTokens() ) {
            String originalDir = tokenizer.nextToken();
            String canonicalDir;
            try {
                canonicalDir = new File(originalDir).getCanonicalPath();
                ret.add(canonicalDir);
            } catch( IOException e ) {
                throw new CompilationDeathException( "Couldn't resolve classpath entry "+originalDir+": "+e );
            }
        }
        return ret;
    }
    public static class FoundFile {
        FoundFile( ZipFile zipFile, ZipEntry entry ) {
            this.zipFile = zipFile;
            this.entry = entry;
        }
        FoundFile( File file ) {
            this.file = file;
        }
        public File file;
        public ZipFile zipFile;
        public ZipEntry entry;
        public InputStream inputStream() {
            try {
                if( file != null ) return new FileInputStream(file);
                return doJDKBugWorkaround(zipFile.getInputStream(entry),
                        entry.getSize());
            } catch( IOException e ) {
                throw new RuntimeException( "Caught IOException "+e );
            }
        }
    }

    private static InputStream doJDKBugWorkaround(InputStream is, long size) throws IOException {
 
  int sz = (int) size;
  byte[] buf = new byte[sz];         
       
           
  final int N = 1024;
  int ln = 0;
  int count = 0;
  while (sz > 0 && 
         (ln = is.read(buf, count, Math.min(N, sz))) != -1) {
      count += ln;
      sz -= ln;
  }
  return  new ByteArrayInputStream(buf);   
    }


    /** Searches for a file with the given name in the exploded classPath. */
    public FoundFile lookupInClassPath( String fileName ) {
        for (String dir : classPath) {
            FoundFile ret;
            if(isJar(dir)) {
                ret = lookupInJar(dir, fileName);
            } else {
                ret = lookupInDir(dir, fileName);
            }
            if( ret != null ) return ret;
        }
        return null;
    }
    private FoundFile lookupInDir(String dir, String fileName) {
        File f = new File( dir+File.separatorChar+fileName );
        if( f.canRead() ) {
            return new FoundFile(f);
        }
        return null;
    }
    private FoundFile lookupInJar(String jar, String fileName) {
        try {
            ZipFile jarFile = new ZipFile(jar);
            ZipEntry entry = jarFile.getEntry(fileName);
            if( entry == null ) return null;
            return new FoundFile(jarFile, entry);
        } catch( IOException e ) {
            throw new RuntimeException( "Caught IOException "+e+" looking in jar file "+jar+" for file "+fileName );
        }
    }
    private HashMap<String, String> sourceToClassMap;

    public HashMap<String, String> getSourceToClassMap(){
        return sourceToClassMap;
    }
    public void setSourceToClassMap(HashMap<String, String> map){
        sourceToClassMap = map;
    }
    public void addToSourceToClassMap(String key, String val) {
        sourceToClassMap.put(key, val);
    }
    /** Returns the name of the class in which the (possibly inner) class
     * className appears. */
    public String getSourceForClass( String className ) {
        String javaClassName = className;
        if (className.indexOf("$") != -1) {
            // class is an inner class and will be in
            // Outer of Outer$Inner
            javaClassName = className.substring(0, className.indexOf("$"));
            //System.out.println("cut off inner class: look for: "+javaClassName);
        }
        // always do this because an inner class could be in a class
        // thats in the map
        if (sourceToClassMap != null) {
            //System.out.println("in source map: "+sourceToClassMap);
            if (sourceToClassMap.get(javaClassName) != null) {
                javaClassName = sourceToClassMap.get(javaClassName);
            }
        }
        return javaClassName;
    }
}
TOP

Related Classes of soot.SourceLocator$FoundFile

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.