/* * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.devtools.j2objc.util; import com.google.common.collect.Lists; import com.google.common.io.CharStreams; import com.google.common.io.Files; import com.google.devtools.j2objc.J2ObjC; import com.google.devtools.j2objc.ast.CompilationUnit; import com.google.devtools.j2objc.ast.PackageDeclaration; import com.google.devtools.j2objc.file.InputFile; import com.google.devtools.j2objc.file.JarredInputFile; import com.google.devtools.j2objc.file.RegularInputFile; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.nio.charset.Charset; import java.util.HashSet; import java.util.List; import java.util.Properties; import java.util.Set; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import javax.annotation.Nullable; import javax.tools.JavaFileObject; /** * Utilities for reading {@link com.google.devtools.j2objc.file.InputFile}s. * * @author Tom Ball, Keith Stanger, Mike Thvedt, Tim Gao */ public class FileUtil { private Set<String> tempDirs = new HashSet<>(); private List<String> sourcePathEntries = Lists.newArrayList("."); private List<String> classPathEntries = Lists.newArrayList("."); private File outputDirectory = new File("."); private String fileEncoding = System.getProperty("file.encoding", "UTF-8"); private Charset charset = Charset.forName(fileEncoding); public void setSourcePathEntries(List<String> sourcePathEntries) { this.sourcePathEntries = sourcePathEntries; } public List<String> getSourcePathEntries() { return sourcePathEntries; } public void appendSourcePath(String entry) { sourcePathEntries.add(entry); } public void insertSourcePath(int index, String entry) { sourcePathEntries.add(index, entry); } public List<String> getClassPathEntries() { return classPathEntries; } public void setOutputDirectory(File outputDirectory) { this.outputDirectory = outputDirectory; } public File getOutputDirectory() { if (!outputDirectory.exists()) { outputDirectory.mkdirs(); } return outputDirectory; } public void setFileEncoding(String fileEncoding) { this.fileEncoding = fileEncoding; charset = Charset.forName(fileEncoding); } public String getFileEncoding() { return fileEncoding; } public Charset getCharset() { return charset; } public void addTempDir(String tempDir) { tempDirs.add(tempDir); } public Set<String> getTempDirs() { return tempDirs; } public static String getMainTypeName(InputFile file) { String basename = file.getBasename(); return removeFileSuffix(basename); } public static String getMainTypeName(JavaFileObject file) { String path = file.getName(); String basename = path.substring(path.lastIndexOf('/') + 1); return removeFileSuffix(basename); } private static String removeFileSuffix(String basename) { int end = basename.lastIndexOf(".java"); if (end == -1) { end = basename.lastIndexOf(".class"); } return end != -1 ? basename.substring(0, end) : basename; } // TODO(tball): remove when Parser extraction is complete. public static String getQualifiedMainTypeName(InputFile file, org.eclipse.jdt.core.dom.CompilationUnit unit) { String qualifiedName = getMainTypeName(file); org.eclipse.jdt.core.dom.PackageDeclaration packageDecl = unit.getPackage(); if (packageDecl != null) { String packageName = packageDecl.getName().getFullyQualifiedName(); qualifiedName = packageName + "." + qualifiedName; } return qualifiedName; } public static String getQualifiedMainTypeName(InputFile file, CompilationUnit unit) { String qualifiedName = getMainTypeName(file); PackageDeclaration packageDecl = unit.getPackage(); if (packageDecl != null) { String packageName = packageDecl.getName().getFullyQualifiedName(); qualifiedName = packageName + "." + qualifiedName; } return qualifiedName; } /** * Find a {@link com.google.devtools.j2objc.file.InputFile} on the source path, * either in a directory or a jar. * Returns a file guaranteed to exist, or null. */ @Nullable public InputFile findOnSourcePath(String qualifiedName) throws IOException { return findOnPaths(qualifiedName, sourcePathEntries, ".java"); } /** * Find a {@link com.google.devtools.j2objc.file.InputFile} on the class path, * either in a directory or a jar. * Returns a file guaranteed to exist, or null. */ @Nullable public InputFile findOnClassPath(String qualifiedName) throws IOException { return findOnPaths(qualifiedName, classPathEntries, ".class"); } private static InputFile findOnPaths( String qualifiedName, List<String> paths, String extension) throws IOException { String sourceFileName = qualifiedName.replace('.', File.separatorChar) + extension; // Zip/jar files always use forward slashes. String jarEntryName = qualifiedName.replace('.', '/') + extension; for (String pathEntry : paths) { File f = new File(pathEntry); if (f.isDirectory()) { RegularInputFile regularFile = new RegularInputFile( pathEntry + File.separatorChar + sourceFileName, sourceFileName); if (regularFile.exists()) { return regularFile; } } else { // Assume it's a jar file JarredInputFile jarFile = new JarredInputFile(pathEntry, jarEntryName); if (jarFile.exists()) { return jarFile; } } } return null; } public String readFile(InputFile file) throws IOException { return CharStreams.toString(file.openReader(charset)); } private static InputStream streamForFile(String filename) throws IOException { File f = new File(filename); if (f.exists()) { return new FileInputStream(f); } else { InputStream stream = J2ObjC.class.getResourceAsStream(filename); if (stream == null) { throw new FileNotFoundException(filename); } return stream; } } /** * Reads the given properties file. */ public static Properties loadProperties(String resourceName) throws IOException { return loadProperties(streamForFile(resourceName)); } public static Properties loadProperties(InputStream in) throws IOException { try { Properties p = new Properties(); p.load(in); return p; } finally { in.close(); } } public static File createTempDir(String dirname) throws IOException { File tmpDirectory = File.createTempFile(dirname, ".tmp"); tmpDirectory.delete(); if (!tmpDirectory.mkdir()) { throw new IOException("Could not create tmp directory: " + tmpDirectory.getPath()); } tmpDirectory.deleteOnExit(); return tmpDirectory; } /** * Recursively delete specified directory. */ public static void deleteTempDir(File dir) { // TODO(cpovirk): try Directories.deleteRecursively if a c.g.c.unix dep is OK if (dir != null && dir.exists()) { for (File f : dir.listFiles()) { if (f.isDirectory()) { deleteTempDir(f); } else { f.delete(); } } dir.delete(); } } /** * Extract a ZipEntry to the specified directory. */ public File extractZipEntry(File dir, ZipFile zipFile, ZipEntry entry) throws IOException { File outputFile = new File(dir, entry.getName()); File parentFile = outputFile.getParentFile(); if (!parentFile.isDirectory() && !parentFile.mkdirs()) { throw new IOException("Could not extract file to " + dir.getPath()); } try (InputStream inputStream = zipFile.getInputStream(entry); InputStreamReader reader = new InputStreamReader(inputStream, charset)) { String source = CharStreams.toString(reader); Files.write(source, outputFile, charset); } return outputFile; } }