/* * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 flex2.compiler.io; import java.io.*; import java.util.List; /** * A helper class used by classes doing file operations. Part of it's * original purpose was to consolidate J# handling, but J# support was * dropped many years ago. * * @author Clement Wong */ public final class FileUtil { public static final boolean caseInsensitive = (System.getProperty("os.name").toLowerCase().startsWith("windows") || System.getProperty("os.name").toLowerCase().startsWith("mac")); /** * Return an instance of File... * * @param path * @return File */ public static File openFile(String path) { try { return new File(path); } catch (Exception e) // J#.NET throws an error if the file is not found... { return null; } } public static File openFile(String path, boolean mkdir) { File f = new File(path).getAbsoluteFile(); if (mkdir) { new File(f.getParent()).mkdirs(); } return f; } /** * Return an instance of File... * * @param parentPath * @param fileName * @return File */ public static File openFile(File parentPath, String fileName) { try { return new File(parentPath, fileName); } catch (Exception e) // J#.NET throws an error if the file is not found... { return null; } } /** * Create a temp file. Write the input stream to the file... * * @param in * @return * @throws IOException */ public static File createTempFile(InputStream in) throws IOException { File temp = File.createTempFile("Flex2_", ""); writeBinaryFile(temp, in); return temp; } /** * Return an input stream with BOM consumed... * * @param file * @return * @throws FileNotFoundException * @throws IOException */ public static InputStream openStream(File file) throws FileNotFoundException, IOException { return openStream(file.getAbsolutePath()); } /** * Return an input stream with BOM consumed... * * @param path * @return * @throws FileNotFoundException * @throws IOException */ public static InputStream openStream(String path) throws FileNotFoundException, IOException { return openStream(new FileInputStream(path)); } /** * Return an input stream with BOM consumed... * * @param in * @return * @throws IOException */ public static InputStream openStream(InputStream in) throws IOException { byte[] bom = new byte[3]; in.read(bom, 0, 3); if (bom[0] == 0xef && bom[1] == 0xbb && bom[2] == 0xbf) { return in; } // else if (bom[0] == 0xff && bom[1] == 0xfe || bom[0] == 0xfe && bom[1] == 0xff) else { return new BOMInputStream(bom, in); } } /** * It's a normal input stream but it serves BOM before bytes in the stream... */ //TODO make a reader version of this class so calls like // > new BufferedReader(new InputStreamReader(FileUtil.openStream(f))) // don't have so many levels of indirection to get to the stream private static final class BOMInputStream extends InputStream { private BOMInputStream(byte[] bom, InputStream in) { this.bom = bom; bomSize = bom.length; this.in = in; index = 0; } private byte[] bom; private final int bomSize; private final InputStream in; private int index; public int read() throws IOException { if (bom == null) { return in.read(); } else { int c = bom[index]; if (index == bomSize - 1) { bom = null; } index += 1; return c; } } public int read(byte b[], int off, int len) throws IOException { if (bom == null) { return in.read(b, off, len); } int count = 0; while ((index < 3) && (count < len)) { b[off+count] = bom[index++]; ++count; } if (index == 3) { bom = null; } if (len <= count) return count; int r = in.read(b, off+count, len-count); return (r == -1)? -1 : r + count; } public long skip(long n) throws IOException { throw new UnsupportedOperationException("supports read() and close() only..."); } public int available() throws IOException { int num = in.available(); if (bom == null) { return num; } else { return (bomSize - index) + num; } } public void close() throws IOException { in.close(); } public synchronized void mark(int readlimit) { throw new UnsupportedOperationException("supports read() and close() only..."); } public synchronized void reset() throws IOException { throw new UnsupportedOperationException("supports read() and close() only..."); } public boolean markSupported() { return false; } } /** * Write a stream of binary data to a file. * @param file * @param in * @throws IOException */ public static void writeBinaryFile(File file, InputStream in) throws IOException { OutputStream out = new BufferedOutputStream(new FileOutputStream(file)); in = new BufferedInputStream(in); try { streamOutput(in, out); } finally { out.close(); } } public static void streamOutput(InputStream in, OutputStream out) throws IOException { int len = 8192; byte[] bytes = new byte[len]; while ((len = in.read(bytes, 0, len)) != -1) { out.write(bytes, 0, len); } // C: caller is responsible for closing the streams. out.flush(); } /** * Write a String to a file * @param fileName * @param output * @throws java.io.IOException */ public static void writeFile(String fileName, String output) throws FileNotFoundException, IOException { File file = openFile(fileName); if (file == null) { throw new FileNotFoundException(fileName); } Writer out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), "UTF8")); try { out.write(output); out.flush(); } finally { out.close(); } } public static void writeBinaryFile(String fileName, byte[] output) throws FileNotFoundException, IOException { File file = openFile(fileName); if (file == null) { throw new FileNotFoundException(fileName); } OutputStream out = new BufferedOutputStream(new FileOutputStream(file)); try { out.write(output); out.flush(); } finally { out.close(); } } public static String getCanonicalPath(String path) { File f = openFile(path); return (f == null) ? null : getCanonicalPath(f); } public static String getCanonicalPath(File f) { try { return f.getCanonicalPath(); } catch (IOException ex) { return f.getAbsolutePath(); } } public static File getCanonicalFile(File f) { try { return f.getCanonicalFile(); } catch (IOException ex) { return f.getAbsoluteFile(); } } public static String readFile(File f) { BufferedReader file = null; StringBuilder buffer = new StringBuilder((int) f.length()); String lineSep = System.getProperty("line.separator"); try { /* TODO * Do we need a BufferedReader layered on a BufferedInputStream? * There are so many levels of indirection here that it would be a good idea * to have an InputBufferReader (like InputBufferStream) and openReader() */ file = new BufferedReader(new InputStreamReader(FileUtil.openStream(f))); String s = null; while ((s = file.readLine()) != null) { buffer.append(s); buffer.append(lineSep); } return buffer.toString(); } catch (FileNotFoundException ex) { return null; } catch (IOException ex) { return null; } finally { if (file != null) { try { file.close(); } catch (IOException ex) { } } } } public static String readLine(String f, int line) { BufferedReader file = null; try { file = new BufferedReader(new InputStreamReader(FileUtil.openStream(f), "UTF8")); for (int i = 0; i < line - 1 && file.readLine() != null; i++); return file.readLine(); } catch (FileNotFoundException ex) { return null; } catch (IOException ex) { return null; } finally { if (file != null) { try { file.close(); } catch (IOException ex) { } } } } public static byte[] readBytes(String f, int line) { BufferedInputStream in = null; ByteArrayOutputStream baos = new ByteArrayOutputStream(); boolean lastIsCR = false; int pos = 0, ch = 0, count = 0; try { in = new BufferedInputStream(FileUtil.openStream(f)); while ((ch = in.read()) != -1) { if (lastIsCR) { count++; if (line == count) { return baos.toByteArray(); } else { baos.reset(); } if (ch == '\n') { lastIsCR = false; } else if (ch == '\r') { lastIsCR = true; } else { baos.write(ch); lastIsCR = false; } } else { if (ch == '\n') { count++; if (line == count) { return baos.toByteArray(); } else { baos.reset(); } lastIsCR = false; } else if (ch == '\r') { lastIsCR = true; } else { baos.write(ch); lastIsCR = false; } } pos++; } return null; } catch (FileNotFoundException ex) { return null; } catch (IOException ex) { return null; } finally { if (in != null) { try { in.close(); } catch (IOException ex) {} } } } /** * check whether the provided path is a subdirectory of the list of directories and vice versa. * @param path * @param directories * @return -1 if not */ public static int isSubdirectoryOf(File pathFile, List directories) { String path = pathFile.toString(); for (int j = 0, size = directories.size(); j < size; j++) { File dirFile = FileUtil.getCanonicalFile((File) directories.get(j)); String dir = dirFile.toString(); if (! pathFile.getParent().equals(dirFile.getParent()) && (path.length() > dir.length() && path.startsWith(dir) || dir.length() > path.length() && dir.startsWith(path))) { return j; } } return -1; } /** * check whether the provided directory is a subdirectory of the list of directories. * @param directory * @param directories * @return -1 if not */ public static int isSubdirectoryOf(String directory, VirtualFile[] directories) { File pathFile = FileUtil.openFile(directory); String path = pathFile.toString(); for (int j = 0, size = directories == null ? 0 : directories.length; j < size; j++) { File dirFile = FileUtil.openFile(directories[j].getName()); String dir = dirFile.toString(); if (!pathFile.getParent().equals(dirFile.getParent()) && path.length() > dir.length() && path.startsWith(dir)) { return j; } } return -1; } public static String getExceptionMessage(Exception ex) { return getExceptionMessage(ex, true); } public static String getExceptionMessage(Exception ex, boolean stackDump) { String m = ex.getMessage(); if (m == null) { m = ex.getLocalizedMessage(); } if (m == null) { m = "(" + ex.getClass().getName() + ")"; if (stackDump) { StringWriter s = new StringWriter(); PrintWriter p = new PrintWriter(s, true); ex.printStackTrace(p); m += s.getBuffer().toString(); } } return m; } }