blob: 132c2b81847512888f26f1ee58e3e77cf31dd271 [file] [log] [blame]
/*
*
* 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 flash.util;
import java.io.*;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
/**
* A collection of file related utilities.
*/
public final class FileUtils
{
public static final String canonicalPath(String rootPath)
{
if (rootPath == null)
return null;
return canonicalPath(new File(rootPath));
}
public static String canonicalPath(File file)
{
return canonicalFile(file).getPath();
}
public static File canonicalFile(File file)
{
try
{
return file.getCanonicalFile();
}
catch (IOException e)
{
return file.getAbsoluteFile();
}
}
static private HashMap<String, String> filemap = null;
static private boolean checkCase = false;
/**
* Canonicalize on Win32 doesn't fix the case of the file to match what is on disk.
* Its annoying that this exists. It will be very slow until the server stabilizes.
* If this is called with a pattern where many files from the same directory will be
* needed, then the cache should be changed to hold the entire directory contents
* and check the modtime of the dir. It didn't seem like this was worth it for now.
* @param f
* @return
*/
public static synchronized String getTheRealPathBecauseCanonicalizeDoesNotFixCase( File f )
{
if (filemap == null)
{
filemap = new HashMap<String, String>();
checkCase = System.getProperty("os.name").toLowerCase().startsWith("windows");
}
String path = FileUtils.canonicalPath( f );
if (!checkCase || !f.exists()) // if the file doesn't exist, then we can't do anything about it.
return path;
// We're going to ignore the issue where someone changes the capitalization of a file on the fly.
// If this becomes an important issue we'll have to make this cache smarter.
if (filemap.containsKey( path ))
return filemap.get( path );
String file = f.getName();
File canonfile = new File(path);
File dir = new File(canonfile.getParent());
// removing dir.listFiles() because it is not supproted in .NET
String[] ss = dir.list();
if (ss != null)
{
int n = ss.length;
File[] files = new File[n];
for (int i = 0; i < n; i++)
{
files[i] = new File(canonfile.getPath(), ss[i]);
}
for (int i = 0; i < files.length; ++i)
{
if (files[i].getName().equalsIgnoreCase( file ))
{
filemap.put( path, files[i].getAbsolutePath() );
return files[i].getAbsolutePath();
}
}
}
// If we got here, it must be because we can't read the directory?
return path;
}
public static String readFile(File file, String default_encoding) throws IOException
{
FileInputStream fileInputStream = new FileInputStream(file);
try
{
StringBuilder returnVal = new StringBuilder((int) file.length() );
BufferedInputStream in = new BufferedInputStream(fileInputStream);
in.mark(3);
Reader reader = new InputStreamReader(in, consumeBOM(in, default_encoding));
char[] line = new char[2000];
int count = 0;
while ((count = reader.read(line, 0, line.length)) >= 0)
{
returnVal.append(line, 0, count);
}
return returnVal.toString();
}
finally
{
fileInputStream.close();
}
}
public static String readFile(String filename, String default_encoding) throws IOException
{
return readFile(new File(filename), default_encoding);
}
/**
* @param in input stream
* @param default_encoding default encoding. null or "" => system default
* @return file encoding..
* @throws IOException
*/
public static final String consumeBOM(InputStream in, String default_encoding) throws IOException
{
return consumeBOM(in, default_encoding, false);
}
/**
* @param in input stream
* @param default_encoding default encoding. null or "" => system default
* @param alwaysConsumeBOM If true, then consume the UTF-16 BOM.
* If false use the previous behavior that consumes
* a UTF-8 BOM but not a UTF-16 BOM.
* This flag is useful when reading a file into
* a string that is then passed to a parser. The parser may
* not know to strip out the BOM.
* @return file encoding..
* @throws IOException
*/
public static final String consumeBOM(InputStream in,
String default_encoding,
boolean alwaysConsumeBOM) throws IOException
{
in.mark(3);
// Determine file encoding...
// ASCII - no header (use the supplied encoding)
// UTF8 - EF BB BF
// UTF16 - FF FE or FE FF (decoder chooses endian-ness)
if (in.read() == 0xef && in.read() == 0xbb && in.read() == 0xbf)
{
// UTF-8 reader does not consume BOM, so do not reset
if (System.getProperty("flex.platform.CLR") != null)
{
return "UTF8";
}
else
{
return "UTF-8";
}
}
else
{
in.reset();
int b0 = in.read();
int b1 = in.read();
if (b0 == 0xff && b1 == 0xfe || b0 == 0xfe && b1 == 0xff)
{
// If we don't consume the BOM is its assumed a
// UTF-16 reader will consume BOM
if (!alwaysConsumeBOM)
{
in.reset();
}
if (System.getProperty("flex.platform.CLR") != null)
{
return "UTF16";
}
else
{
return "UTF-16";
}
}
else
{
// no BOM found
in.reset();
if (default_encoding != null && default_encoding.length() != 0)
{
return default_encoding;
}
else
{
return System.getProperty("file.encoding");
}
}
}
}
/* post-1.2 File methods */
public static File getAbsoluteFile(File f)
{
File absolute = null;
try
{
absolute = f == null ? null : f.getAbsoluteFile();
}
catch (SecurityException se)
{
if (Trace.pathResolver)
{
Trace.trace(se.getMessage());
}
}
return absolute;
}
public static File getCanonicalFile(File f)
throws IOException
{
return new File(f.getCanonicalPath());
}
public static File getParentFile(File f)
{
String p = f.getParent();
if (p == null)
{
return null;
}
return new File(p);
}
public static File[] listFiles(File dir)
{
String[] fileNames = dir.list();
if (fileNames == null)
{
return null;
}
File[] fileList = new File[fileNames.length];
for (int i=0; i<fileNames.length; i++)
{
fileList[i] = new File(dir.getPath(), fileNames[i]);
}
return fileList;
}
public static File[] listFiles(File dir, FilenameFilter filter)
{
String[] fileNames = dir.list();
if (fileNames == null)
{
return null;
}
ArrayList<File> filteredFiles = new ArrayList<File>();
for (int i=0; i < fileNames.length; i++)
{
if ((filter == null) || filter.accept(dir, fileNames[i]))
{
filteredFiles.add(new File(dir.getPath(), fileNames[i]));
}
}
return (filteredFiles.toArray(new File[0]));
}
public static URL toURL(File f)
throws MalformedURLException
{
String s = f.getAbsolutePath();
if (File.separatorChar != '/')
{
s = s.replace(File.separatorChar, '/');
}
if (!s.startsWith("/"))
{
s = "/" + s;
}
if (!s.endsWith("/") && f.isDirectory())
{
s = s + "/";
}
return new URL("file", "", s);
}
public static String addPathComponents(String p1, String p2, char sepchar)
{
if (p1 == null)
p1 = "";
if (p2 == null)
p2 = "";
int r1 = p1.length() - 1;
while ((r1 >= 0) && ((p1.charAt( r1 ) == sepchar)))
--r1;
int r2 = 0;
while ((r2 < p2.length()) && (p2.charAt( r2 ) == sepchar ))
++r2;
String left = p1.substring( 0, r1 + 1 );
String right = p2.substring( r2 );
String sep = "";
if ((left.length() > 0) && (right.length() > 0))
sep += sepchar;
return left + sep + right;
}
/**
* Java's File.renameTo doesn't try very hard.
* @param from absolute origin
* @param to absolute target
* @return true if rename succeeded
*/
public static boolean renameFile( File from, File to)
{
if (!from.exists())
{
return false;
}
long length = from.length();
try
{
if (to.exists())
{
if (!to.delete())
{
File old = new File( to.getAbsolutePath() + ".old" );
if (old.exists())
{
old.delete();
}
if (to.renameTo( old ) && !old.delete())
{
// unbefrickinlievable
// TODO - this isn't supported on .Net, write a replacement FileUtils.rename!!
// old.deleteOnExit();
}
}
}
}
catch (Exception e)
{
// eat exception, keep on going...
}
try
{
if (from.renameTo( to ))
{
return true;
}
// everything seems to have failed. copy the bits.
BufferedInputStream in = new BufferedInputStream(new FileInputStream( from ));
BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream( to ));
byte[] buf = new byte[8 * 1024];
long remain = from.length();
try
{
while ( remain > 0 )
{
int r = in.read( buf );
if (r < 0)
{
return false;
}
remain -= r;
out.write( buf, 0, r );
out.flush();
}
}
finally
{
in.close();
out.close();
}
long tolength = to.length();
if (tolength == length)
{
from.delete();
// TODO - .Net doesn't support this!!!
//to.setLastModified( from.lastModified() );
return true;
}
else
{
return false;
}
}
catch (Exception e)
{
return false;
}
}
public static byte[] toByteArray(InputStream in)
{
ByteArrayOutputStream baos = new ByteArrayOutputStream(8192);
byte[] buffer = new byte[8192];
int num = 0;
InputStream inputStream = new BufferedInputStream(in);
try
{
while ((num = inputStream.read(buffer)) != -1)
{
baos.write(buffer, 0, num);
}
}
catch (IOException ex)
{
if (Trace.error)
ex.printStackTrace();
// FIXME: do we really want to catch this without an exception?
}
finally
{
try
{
if (in != null)
in.close();
}
catch (IOException ex)
{
}
}
return baos.toByteArray();
}
public static byte[] toByteArray(InputStream in, int length) throws IOException
{
BufferedInputStream inputStream = new BufferedInputStream(in);
byte[] buffer = new byte[length];
try
{
int bytesRead = 0;
int index = 0;
while ((bytesRead >= 0) && (index < buffer.length))
{
bytesRead = inputStream.read(buffer, index, buffer.length - index);
index += bytesRead;
}
}
finally
{
inputStream.close();
}
return buffer;
}
public static void writeClassToFile(String baseDir, String packageName, String className, String str)
throws IOException
{
String reldir = packageName.replace( '.', File.separatorChar );
String dir = FileUtils.addPathComponents( baseDir, reldir, File.separatorChar );
new File( dir ).mkdirs();
String generatedName = FileUtils.addPathComponents( dir, className, File.separatorChar );
BufferedWriter fileWriter = null;
try
{
fileWriter = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(generatedName), "UTF-8"));
fileWriter.write( str );
fileWriter.flush();
}
finally
{
if (fileWriter != null)
{
try
{
fileWriter.close();
}
catch (IOException ex)
{
}
}
}
}
/**
* returns whether the file is absolute
* if a security exception is thrown, always returns false
*/
public static boolean isAbsolute(File f)
{
boolean absolute = false;
try
{
absolute = f.isAbsolute();
}
catch (SecurityException se)
{
if (Trace.pathResolver)
{
Trace.trace(se.getMessage());
}
}
return absolute;
}
/**
* returns whether the file is absolute
* if a security exception is thrown, always returns false
*/
public static boolean exists(File f)
{
boolean exists = false;
try
{
exists = f.exists();
}
catch (SecurityException se)
{
if (Trace.pathResolver)
{
Trace.trace(se.getMessage());
}
}
return exists;
}
/**
* returns whether it's a file
* if a security exception is thrown, always returns false
*/
public static boolean isFile(File f)
{
boolean isFile = false;
try
{
isFile = f.isFile();
}
catch (SecurityException se)
{
if (Trace.pathResolver)
{
Trace.trace(se.getMessage());
}
}
return isFile;
}
/**
* returns whether it's a directory
* if a security exception is thrown, always returns false
*/
public static boolean isDirectory(File f)
{
boolean isDirectory = false;
try
{
isDirectory = f.isDirectory();
}
catch (SecurityException se)
{
if (Trace.pathResolver)
{
Trace.trace(se.getMessage());
}
}
return isDirectory;
}
}