blob: a3126fba4f8594010863fb85ee39bee38360c44a [file] [log] [blame]
/*
* Copyright (C) 2012 The Android Open Source Project
*
* 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.motorola.studio.android.common.utilities;
import static com.motorola.studio.android.common.log.StudioLogger.warn;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.LineNumberReader;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.nio.channels.FileChannel;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.LinkedList;
import java.util.List;
import java.util.StringTokenizer;
import java.util.zip.CRC32;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.SubMonitor;
import org.eclipse.core.runtime.SubProgressMonitor;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.text.Document;
import org.eclipse.jface.text.IDocument;
import org.eclipse.osgi.util.NLS;
import org.eclipse.ui.editors.text.TextFileDocumentProvider;
import com.motorola.studio.android.common.CommonPlugin;
import com.motorola.studio.android.common.log.StudioLogger;
import com.motorola.studio.android.common.utilities.i18n.UtilitiesNLS;
/**
* DESCRIPTION: This class provides utility methods to handle files, like
* copying and deleting directories sub-trees.
*
* USAGE: See public methods
*/
public class FileUtil
{
public static final int OS_WINDOWS = 0;
public static final int OS_LINUX = 1;
public static final char[] MAC_SPECIAL_CHAR =
{
'\\', ' ', '\'', '"', '!', '@', '$', '&', '*', '(', ')', '=', '`', '[', ']', '{', '}',
'^', '<', '>', ':', ';', '?', '|'
};
public static final char[] LINUX_SPECIAL_CHAR =
{
'\\', ' ', '\'', '"', '!', '$', '&', '*', '(', ')', '=', '`', '[', ']', '{', '}', '^',
'<', '>', ':', ';', '?', '|'
};
public static final char ESCAPE_CHAR = '\\';
private static final int BUFFER_SIZE = 1024;
/**
* Copy full list of contents from a directory to another. The source
* directory is not created within the target one.
*
* @param fromDir
* Source directory.
* @param toDir
* Target directory.
*
* @param IOException if I/O occurs
*/
public static void copyDir(File fromDir, File toDir) throws IOException
{
if ((fromDir != null) && fromDir.isDirectory() && fromDir.canRead() && (toDir != null)
&& toDir.isDirectory() && toDir.canWrite())
{
for (File child : fromDir.listFiles())
{
if (child.isFile())
{
copyFile(child, new File(toDir, child.getName()));
}
else
{
// create directory and copy its children recursively
File newDir = new File(toDir.getAbsolutePath(), child.getName());
newDir.mkdir();
copyDir(child, newDir);
}
}
StudioLogger.info("The directory " + fromDir.getName() + " was successfully copied to " //$NON-NLS-1$ //$NON-NLS-2$
+ toDir.getName() + "."); //$NON-NLS-1$
}
else
{
//error detected
String errorMessage = ""; //$NON-NLS-1$
if (fromDir == null)
{
errorMessage = "Null pointer for source directory."; //$NON-NLS-1$
}
else
{
if (!fromDir.isDirectory())
{
errorMessage = fromDir.getName() + " is not a directory."; //$NON-NLS-1$
}
else
{
if (!fromDir.canRead())
{
errorMessage = "Cannot read from " + fromDir.getName() + "."; //$NON-NLS-1$ //$NON-NLS-2$
}
else
{
if (toDir == null)
{
errorMessage = "Null pointer for destination directory."; //$NON-NLS-1$
}
else
{
if (!toDir.isDirectory())
{
errorMessage = toDir.getName() + " is not a directory."; //$NON-NLS-1$
}
else
{
if (!toDir.canWrite())
{
errorMessage = "Cannot write to" + toDir.getName() + "."; //$NON-NLS-1$ //$NON-NLS-2$
}
}
}
}
}
}
StudioLogger.error(errorMessage);
throw new IOException("Error copying directory: " + errorMessage); //$NON-NLS-1$
}
}
/**
* Copies the source file to the given target.
*
* @param source -
* the absolute path of the source file.
* @param target -
* the absolute path of the target file.
*/
public static void copyFile(File source, File target) throws IOException
{
copyFile(source.getAbsolutePath(), target.getAbsolutePath());
}
/**
* Copies the source file to the given target.
*
* @param source -
* the absolute path of the source file.
* @param target -
* the absolute path of the target file.
*/
private static void copyFile(String source, String target) throws IOException
{
FileChannel sourceFileChannel = null;
FileChannel targetFileChannel = null;
FileInputStream sourceFileInStream = null;
FileOutputStream targetFileOutStream = null;
try
{
sourceFileInStream = new FileInputStream(source);
sourceFileChannel = sourceFileInStream.getChannel();
targetFileOutStream = new FileOutputStream(target);
targetFileChannel = targetFileOutStream.getChannel();
targetFileChannel.transferFrom(sourceFileChannel, 0, sourceFileChannel.size());
StudioLogger.info("The file " + source + " was successfully copied to " + target + "."); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
}
catch (IOException e)
{
StudioLogger.error("Error copying file" + source + "to " + target + "."); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
throw e;
}
finally
{
try
{
if (sourceFileChannel != null)
{
sourceFileChannel.close();
}
}
catch (IOException e)
{
StudioLogger.error("Error closing file " + source + "."); //$NON-NLS-1$ //$NON-NLS-2$
throw e;
}
try
{
if (targetFileChannel != null)
{
targetFileChannel.close();
}
}
catch (IOException e)
{
StudioLogger.error("Error closing file" + target + "."); //$NON-NLS-1$ //$NON-NLS-2$
throw e;
}
try
{
if (sourceFileInStream != null)
{
sourceFileInStream.close();
}
}
catch (IOException e)
{
StudioLogger.error("Error closing file" + source + "."); //$NON-NLS-1$ //$NON-NLS-2$
throw e;
}
try
{
if (targetFileOutStream != null)
{
targetFileOutStream.close();
}
}
catch (IOException e)
{
StudioLogger.error("Error closing file" + target + "."); //$NON-NLS-1$ //$NON-NLS-2$
throw e;
}
}
}
/**
* This method deletes the directory, all files and all subdirectories under
* it. If a deletion fails, the method stops attempting to delete and
* returns false.
*
* @param directory
* The directory to be deleted
* @return Returns true if all deletions were successful. If the directory
* doesn't exist returns false.
* @throws IOException
* When the parameter isn't a directory
*/
public static boolean deleteDirRecursively(File directory) throws IOException
{
String dirName = ""; //$NON-NLS-1$
boolean success = true;
if (directory.exists())
{
if (directory.isDirectory())
{
dirName = directory.getName();
File[] children = directory.listFiles();
for (File element : children)
{
if (element.isFile())
{
success = success && element.delete();
}
else
{
success = success && deleteDirRecursively(element);
}
}
success = success && directory.delete();
}
else
{
String errorMessage = directory.getName() + " is not a diretory."; //$NON-NLS-1$
StudioLogger.error(errorMessage);
throw new IOException(errorMessage);
}
}
else
{
String errorMessage = "The directory does not exist."; //$NON-NLS-1$
StudioLogger.error(errorMessage);
success = false;
throw new IOException(errorMessage);
}
if ((success) && (!dirName.equals(""))) //$NON-NLS-1$
{
StudioLogger.info("The directory " + dirName + "was successfully deleted."); //$NON-NLS-1$ //$NON-NLS-2$
}
return success;
}
/**
* Delete a single file from the filesystem.
*
* @param fileToDelete
* A <code>File</code> object representing the file to be
* deleted.
* @throws IOException
* if any problem occurs deleting the file.
*/
public static void deleteFile(File fileToDelete) throws IOException
{
if ((fileToDelete != null) && fileToDelete.exists() && fileToDelete.isFile()
&& fileToDelete.canWrite())
{
fileToDelete.delete();
StudioLogger.info("The file " + fileToDelete.getName() + "was successfully deleted."); //$NON-NLS-1$ //$NON-NLS-2$
}
else
{
String errorMessage = ""; //$NON-NLS-1$
if (fileToDelete == null)
{
errorMessage = "Null pointer for file to delete."; //$NON-NLS-1$
}
else
{
if (!fileToDelete.exists())
{
errorMessage = "The file " + fileToDelete.getName() + " does not exist."; //$NON-NLS-1$ //$NON-NLS-2$
}
else
{
if (!fileToDelete.isFile())
{
errorMessage = fileToDelete.getName() + " is not a file."; //$NON-NLS-1$
}
else
{
if (!fileToDelete.canWrite())
{
errorMessage = "Cannot write to " + fileToDelete.getName(); //$NON-NLS-1$
}
}
}
}
StudioLogger.error(errorMessage);
throw new IOException("Cannot delete file: " + errorMessage); //$NON-NLS-1$
}
}
/**
* Delete a list of files from the filesystem.
*
* @param filesToDelete
* A list of <code>File</code> objects representing the files
* to be deleted.
* @throws IOException
* if any problem occurs deleting the files.
*/
public static void deleteFilesOnList(List<File> filesToDelete) throws IOException
{
for (File element : filesToDelete)
{
if (element.exists())
{
deleteFile((element));
}
}
}
/**
* Return the File Size in Bytes.
*
* @param root The root File, it can be a directory
* @return The size of the file in bytes
* @throws IOException
*/
public static int getFileSize(File root) throws IOException
{
int size = 0;
if (root.isDirectory())
{
for (File child : root.listFiles())
{
size += FileUtil.getFileSize(child);
}
}
else if (root.isFile())
{
FileInputStream fis = new FileInputStream(root);
int available;
try
{
available = fis.available();
}
finally
{
try
{
fis.close();
}
catch (IOException e)
{
//Do thing.
}
}
size = available;
}
return size;
}
/**
* getExtension(String fileName)
*
* @param fileName
* returns the extension of a given file. "extension" here means
* the final part of the string after the last dot.
*
* @return String containing the extension
*/
public static String getExtension(String fileName)
{
if (fileName != null)
{
int i = fileName.lastIndexOf(".") + 1; //$NON-NLS-1$
return (i == 0) ? "" : fileName.substring(i); //$NON-NLS-1$
}
else
{
StudioLogger.error("The file " + fileName + " does not exist."); //$NON-NLS-1$ //$NON-NLS-2$
return null;
}
}
/**
* Get the list of all File objects that compose the path to the given File
* object
*
* @param aFile
* the file whose path must be retrieved.
* @return a List with all the File objects that compose the path to the
* given File object.
*/
public static List<File> getFilesComposingPath(File aFile)
{
List<File> fileList;
if (aFile == null)
{
fileList = new ArrayList<File>();
}
else
{
fileList = getFilesComposingPath(aFile.getParentFile());
fileList.add(aFile);
}
return fileList;
}
/**
* Retrieve the relative filename to access a targetFile from a homeFile
* parent directory. Notice that to actualy use a relative File object you
* must use the following new File(homeDir, relativeFilename) because using
* only new File(relativeFilename) would give you a file whose directory is
* the one set in the "user.dir" property.
*
* @param homeDir
* the directory from where you want to access the targetFile
* @param targetFile
* the absolute file or dir that you want to access via relative
* filename from the homeFile
* @return the relative filename that describes the location of the
* targetFile referenced from the homeFile dir
* @throws IOException
*/
public static String getRelativeFilename(File homeDir, File targetFile) throws IOException
{
StringBuffer relativePath = new StringBuffer();
List<File> homeDirList = getFilesComposingPath(getCanonicalFile(homeDir));
List<File> targetDirList = getFilesComposingPath(getCanonicalFile(targetFile));
if (homeDirList.size() == 0)
{
StudioLogger.info("Home Dir has no parent."); //$NON-NLS-1$
}
if (targetDirList.size() == 0)
{
StudioLogger.info("Target Dir has no parent."); //$NON-NLS-1$
}
// get the index of the last common directory between sourceFile and
// targetFile
int commonIndex = -1;
for (int i = 0; (i < homeDirList.size()) && (i < targetDirList.size()); i++)
{
File aHomeDir = homeDirList.get(i);
File aTargetDir = targetDirList.get(i);
if (aHomeDir.equals(aTargetDir))
{
commonIndex = i;
}
else
{
break;
}
}
// return from all remaining directories of the homeFile
for (int i = commonIndex + 1; i < homeDirList.size(); i++)
{
relativePath.append(".."); //$NON-NLS-1$
relativePath.append(File.separatorChar);
}
// enter into all directories of the target file
// stops when reachs the file name and extension
for (int i = commonIndex + 1; i < targetDirList.size(); i++)
{
File targetDir = targetDirList.get(i);
relativePath.append(targetDir.getName());
if (i != (targetDirList.size() - 1))
{
relativePath.append(File.separatorChar);
}
}
return relativePath.toString();
}
/**
* Return a list of file absolute paths under "baseDir" and under its subdirectories,
* recursively.
*
* @param baseDirToList
* A string that represents the BaseDir to initial search.
* @return A List of filepaths of files under the "baseDir".
* @throws IOException
* If the "baseDir" can not be read.
*/
public static List<String> listFilesRecursively(String baseDirToList) throws IOException
{
File baseDirToListFiles = new File(baseDirToList);
List<String> listOfFiles = listFilesRecursively(baseDirToListFiles);
return listOfFiles;
}
/**
* Return a list of file absolute paths under "baseDir" and under its subdirectories,
* recursively.
*
* @param baseDirToList
* A file object that represents the "baseDir".
* @return A List of filepaths of files under the "baseDir".
* @throws IOException
* If the "baseDir" can not be read.
*/
public static List<String> listFilesRecursively(File baseDirToList) throws IOException
{
List<String> listOfFiles = new ArrayList<String>();
if (baseDirToList.exists() && baseDirToList.isDirectory() && baseDirToList.canRead())
{
File[] children = baseDirToList.listFiles();
for (File child : children)
{
if (child.isFile())
{
listOfFiles.add(child.getAbsolutePath());
}
else
{
List<String> temporaryList = listFilesRecursively(child);
listOfFiles.addAll(temporaryList);
}
}
}
else
{
String errorMessage = ""; //$NON-NLS-1$
if (!baseDirToList.exists())
{
errorMessage = "The base dir does not exist."; //$NON-NLS-1$
}
else
{
if (!baseDirToList.isDirectory())
{
errorMessage = baseDirToList.getName() + "is not a directory."; //$NON-NLS-1$
}
else
{
if (!baseDirToList.canRead())
{
errorMessage = "Cannot fread from " + baseDirToList.getName() + "."; //$NON-NLS-1$ //$NON-NLS-2$
}
}
}
StudioLogger.error(errorMessage);
throw new IOException("Error listing files: " + errorMessage); //$NON-NLS-1$
}
return listOfFiles;
}
/**
* Calculate the canonical (an absolute filename without "\.\" and "\..\")
* that describe the file described by the absoluteFilename.
* @param absoluteFilename a file name that describe the full path of the file to use.
* @return the canonical File objecta
*/
public static File getCanonicalFile(String absoluteFilename)
{
return getCanonicalFile(new File(absoluteFilename));
}
/**
* Calculate the canonical (an absolute filename without "\.\" and "\..\")
* that describe the file described by the given location and filename.
* @param location the directory of the file to be used
* @param filename (or a relative filename) of the file to be used
* @return the canonical File objecta
*/
public static File getCanonicalFile(File location, String filename)
{
return getCanonicalFile(new File(location, filename));
}
/**
* Calculate the canonical (an absolute filename without "\.\" and "\..\")
* that describe the given file.
* @param aFile the file whose cannonical path will be calculated
* @return the canonical File objecta
*/
public static File getCanonicalFile(File aFile)
{
File f = null;
try
{
f = aFile.getCanonicalFile();
}
catch (IOException e)
{
// this should never happens
StudioLogger.error(FileUtil.class, "FileUtil.getCanonicalFile: IOException e", e); //$NON-NLS-1$
// since it's not possible to read from filesystem, return a File using String
String filename = aFile.getAbsolutePath();
StringTokenizer st = new StringTokenizer(filename, File.separator);
StringBuffer sb = new StringBuffer();
while (st.hasMoreTokens())
{
String token = (String) st.nextElement();
if (token.equals("..")) //$NON-NLS-1$
{
int lastDirIndex = sb.lastIndexOf(File.separator);
// do not go back currently on the root directory
if (lastDirIndex > 2)
{
sb.delete(lastDirIndex, sb.length());
}
}
else if (!token.equals(".")) //$NON-NLS-1$
{
if (sb.length() > 0)
{
sb.append(File.separator);
}
sb.append(token);
if (token.endsWith(":")) //$NON-NLS-1$
{
sb.append(File.separator);
}
}
}
f = new File(sb.toString());
}
return f;
}
/**
* Returns which is the OS.
* @return
* a code corresponding to the proper OS
*/
public static int getOS()
{
int result = -1;
String osName = System.getProperty("os.name").toLowerCase(); //$NON-NLS-1$
if (osName.indexOf("linux") > -1) //$NON-NLS-1$
{
result = OS_LINUX;
}
else if (osName.indexOf("windows") > -1) //$NON-NLS-1$
{
result = OS_WINDOWS;
}
return result;
}
/**
* Returns true if the OS is windows
* @return true if the OS is windows
*/
public static boolean isWindows()
{
return getOS() == OS_WINDOWS;
}
/**
* Opens the stream;
*
* @param stream File Stream
*
* @return StringBuffer with the file content
*
* @throws IOException
*/
public static StringBuffer openFile(InputStream stream) throws IOException
{
InputStreamReader streamReader = null;
StringBuffer fileBuffer = new StringBuffer();
BufferedReader reader = null;
try
{
streamReader = new InputStreamReader(stream);
reader = new BufferedReader(streamReader);
char[] buffer = new char[1024];
int line = reader.read(buffer);
while (line > 0)
{
fileBuffer.append(buffer, 0, line);
line = reader.read(buffer);
}
}
finally
{
if (streamReader != null)
{
try
{
streamReader.close();
}
catch (Exception e)
{
//Do nothing.
}
}
if (reader != null)
{
try
{
reader.close();
}
catch (Exception e)
{
//Do nothing.
}
}
}
return fileBuffer;
}
/**
* Reads a file into a string array
*
* @param filename The file name
* @return The file contents as a string array
* @throws IOException
*/
public static String[] readFileAsArray(String filename) throws IOException
{
LinkedList<String> file = new LinkedList<String>();
String[] lines = new String[0];
String line;
FileReader reader = null;
LineNumberReader lineReader = null;
try
{
reader = new FileReader(filename);
lineReader = new LineNumberReader(reader);
while ((line = lineReader.readLine()) != null)
{
file.add(line);
}
lines = new String[file.size()];
lines = file.toArray(lines);
}
finally
{
try
{
lineReader.close();
reader.close();
}
catch (Exception e)
{
// Do nothing
}
}
return lines;
}
/**
* Reads a file on workspace and returns an IDocument object with its content
*
* @param file The file to read
* @return The IDocument object containing the file contents
*
* @throws CoreException
*/
public static IDocument readFile(IFile file) throws CoreException
{
if (!canRead(file))
{
String errMsg = NLS.bind(UtilitiesNLS.EXC_FileUtil_TheFileCannotBeRead, file.getName());
IStatus status = new Status(IStatus.ERROR, CommonPlugin.PLUGIN_ID, errMsg);
throw new CoreException(status);
}
TextFileDocumentProvider documentProvider = new TextFileDocumentProvider();
IDocument document = new Document();
documentProvider.connect(file);
document = documentProvider.getDocument(file);
documentProvider.disconnect(file);
return document;
}
/**
* Saves the content of an IDocument object to a file on workspace
* @param file The file
* @param document The IDocument object
* @param encoding The file encoding
* @param overwrite If the file can be overwritten
* @throws CoreException
*/
public static void saveFile(IFile file, IDocument document, String encoding, boolean overwrite)
throws CoreException
{
if (file.exists() && !overwrite)
{
String errMsg =
NLS.bind(UtilitiesNLS.EXC_FileUtil_CannotOverwriteTheFile, file.getName());
IStatus status = new Status(IStatus.ERROR, CommonPlugin.PLUGIN_ID, errMsg);
throw new CoreException(status);
}
if (!canWrite(file))
{
String errMsg = NLS.bind(UtilitiesNLS.EXC_FileUtil_ErrorWritingTheFile, file.getName());
IStatus status = new Status(IStatus.ERROR, CommonPlugin.PLUGIN_ID, errMsg);
throw new CoreException(status);
}
ByteArrayInputStream bais = null;
try
{
bais = new ByteArrayInputStream(document.get().getBytes(encoding));
file.setCharset(encoding, new NullProgressMonitor());
file.setContents(bais, true, false, new NullProgressMonitor());
}
catch (UnsupportedEncodingException e1)
{
String errMsg =
NLS.bind(UtilitiesNLS.EXC_FileUtil_ErrorSettingTheFileEncoding, file.getName());
IStatus status = new Status(IStatus.ERROR, CommonPlugin.PLUGIN_ID, errMsg);
throw new CoreException(status);
}
finally
{
if (bais != null)
{
try
{
bais.close();
}
catch (IOException e)
{
// Do nothing.
}
}
}
}
/**
* Checks if a file can be read
*
* @param file The file to be checked
* @return true if the file can be read or false otherwise
*/
public static boolean canRead(IFile file)
{
boolean canRead = true;
InputStream is = null;
try
{
if (file.exists())
{
file.refreshLocal(IResource.DEPTH_ZERO, new NullProgressMonitor());
is = file.getContents();
is.read();
}
}
catch (CoreException e)
{
canRead = false;
}
catch (IOException e)
{
canRead = false;
}
finally
{
if (is != null)
{
try
{
is.close();
}
catch (IOException e)
{
// do nothing
}
}
}
return canRead;
}
/**
* Checks if a file can be written
*
* @param file the file to be checked
* @return true if the file can be written or false otherwise
*/
public static boolean canWrite(IFile file)
{
boolean canWrite = true;
if (file.exists() && canRead(file))
{
canWrite = !file.isReadOnly();
}
else
{
IFolder parent = (IFolder) file.getParent();
if (!parent.isAccessible())
{
canWrite = false;
}
else
{
try
{
if (parent.members() == null)
{
canWrite = false;
}
else
{
NullProgressMonitor nullProgressMonitor = new NullProgressMonitor();
file.create(null, true, nullProgressMonitor);
file.refreshLocal(IResource.DEPTH_ZERO, nullProgressMonitor);
file.delete(true, nullProgressMonitor);
}
}
catch (CoreException e)
{
canWrite = false;
}
}
}
return canWrite;
}
/**
* Checks if a File object can be read
*
* @param file the File object
*
* @return true if the File object can be read or false otherwise
*/
public static boolean canRead(File file)
{
boolean canRead = false;
if ((file != null) && file.exists())
{
FileInputStream fis = null;
try
{
if (file.isFile())
{
fis = new FileInputStream(file);
fis.read();
canRead = true;
}
else
{
String[] children = file.list();
if (children != null)
{
canRead = true;
}
}
}
catch (Exception e)
{
// Do nothing. canRead is false already
}
finally
{
try
{
if (fis != null)
{
fis.close();
}
}
catch (IOException e)
{
// Do nothing
}
}
}
return canRead;
}
/**
* Checks if a File object can be written
*
* @param file the File object
*
* @return true if the File object can be written or false otherwise
*/
public static boolean canWrite(File file)
{
boolean canWrite = false;
if (file != null)
{
FileOutputStream fos = null;
try
{
if (!file.exists())
{
canWrite = file.createNewFile();
if (canWrite)
{
file.delete();
}
}
else if (file.isDirectory())
{
File tempFile = File.createTempFile("StudioForAndroidFSChecking", null, file); //$NON-NLS-1$
if (tempFile.exists())
{
canWrite = true;
tempFile.delete();
}
}
else if (file.isFile())
{
fos = new FileOutputStream(file);
fos.getFD();
canWrite = true;
}
}
catch (Exception e)
{
// Do nothing. canWrite is false already
}
finally
{
if (fos != null)
{
try
{
fos.close();
}
catch (IOException e)
{
// Do nothing
}
}
}
}
return canWrite;
}
/**
* Unpack a zip file.
*
* @param file the file
* @param destination the destination path or null to unpack at the same directory of file
* @return true if unpacked, false otherwise
*/
public static boolean unpackZipFile(File file, String destination, IProgressMonitor monitor)
{
SubMonitor subMonitor = SubMonitor.convert(monitor);
ZipFile zipFile = null;
String extractDestination = destination != null ? destination : file.getParent();
if (!extractDestination.endsWith(File.separator))
{
extractDestination += File.separator;
}
boolean unziped = true;
try
{
zipFile = new ZipFile(file);
}
catch (Throwable e)
{
unziped = false;
StudioLogger.error(FileUtil.class, "Error extracting file: " + file.getAbsolutePath() //$NON-NLS-1$
+ " to " + extractDestination, e); //$NON-NLS-1$
}
if (zipFile != null)
{
Enumeration<? extends ZipEntry> entries = zipFile.entries();
subMonitor.beginTask("Extracting files", Collections.list(entries).size()); //$NON-NLS-1$
entries = zipFile.entries();
InputStream input = null;
OutputStream output = null;
while (entries.hasMoreElements())
{
try
{
ZipEntry entry = entries.nextElement();
File newFile = new File(extractDestination + entry.getName());
if (entry.isDirectory())
{
newFile.mkdirs();
}
else
{
newFile.getParentFile().mkdirs();
if (newFile.createNewFile())
{
input = zipFile.getInputStream(entry);
output = new BufferedOutputStream(new FileOutputStream(newFile));
copyStreams(input, output);
}
}
}
catch (Throwable t)
{
unziped = false;
StudioLogger.error(FileUtil.class,
"Error extracting file: " + file.getAbsolutePath() + " to " //$NON-NLS-1$ //$NON-NLS-2$
+ extractDestination, t);
}
finally
{
try
{
if (input != null)
{
input.close();
}
if (output != null)
{
output.close();
}
}
catch (Throwable t)
{
//do nothing
}
subMonitor.worked(1);
}
}
}
return unziped;
}
public static boolean extractZipArchive(File file, File destination,
List<String> selectedEntries, IProgressMonitor monitor) throws IOException
{
SubMonitor subMonitor = SubMonitor.convert(monitor);
ZipFile zipFile = null;
CRC32 crc = new CRC32();
byte[] buf = new byte[BUFFER_SIZE];
File extractDestination = destination != null ? destination : file.getParentFile();
if (!extractDestination.exists())
{
extractDestination.mkdirs();
}
boolean unziped = true;
try
{
zipFile = new ZipFile(file);
}
catch (Throwable e)
{
unziped = false;
StudioLogger.error(FileUtil.class, "Error extracting file: " + file.getAbsolutePath() //$NON-NLS-1$
+ " to " + extractDestination, e); //$NON-NLS-1$
}
if (zipFile != null)
{
Enumeration<? extends ZipEntry> entries = zipFile.entries();
subMonitor.beginTask("Extracting files", Collections.list(entries).size()); //$NON-NLS-1$
entries = zipFile.entries();
InputStream input = null;
FileOutputStream output = null;
int diagReturn = IDialogConstants.YES_ID;
while (entries.hasMoreElements())
{
crc.reset();
try
{
ZipEntry entry = entries.nextElement();
if (selectedEntries.contains(entry.getName()))
{
File newFile = new File(extractDestination, entry.getName());
if ((diagReturn != IDialogConstants.YES_TO_ALL_ID) && newFile.exists())
{
diagReturn =
EclipseUtils.showQuestionYesAllCancelDialog(
UtilitiesNLS.FileUtil_File_Exists_Title, NLS.bind(
UtilitiesNLS.FileUtil_File_Exists_Message,
newFile.getAbsolutePath()));
}
if ((diagReturn == IDialogConstants.YES_ID)
|| (diagReturn == IDialogConstants.YES_TO_ALL_ID))
{
newFile.delete();
if (entry.isDirectory())
{
newFile.mkdirs();
}
else
{
newFile.getParentFile().mkdirs();
if (newFile.createNewFile())
{
input = zipFile.getInputStream(entry);
output = new FileOutputStream(newFile);
int length = 0;
while ((length = input.read(buf, 0, BUFFER_SIZE)) > 1)
{
output.write(buf, 0, length);
crc.update(buf, 0, length);
}
if (crc.getValue() != entry.getCrc())
{
throw new IOException();
}
}
}
}
else
{
diagReturn = IDialogConstants.YES_ID; //Attempt to extract next entry
}
}
}
catch (IOException e)
{
unziped = false;
StudioLogger.error(FileUtil.class,
"Error extracting file: " + file.getAbsolutePath() + " to " //$NON-NLS-1$ //$NON-NLS-2$
+ extractDestination, e);
throw e;
}
catch (Throwable t)
{
unziped = false;
StudioLogger.error(FileUtil.class,
"Error extracting file: " + file.getAbsolutePath() + " to " //$NON-NLS-1$ //$NON-NLS-2$
+ extractDestination, t);
}
finally
{
try
{
if (input != null)
{
input.close();
}
if (output != null)
{
output.close();
}
}
catch (Throwable t)
{
//do nothing
}
subMonitor.worked(1);
}
}
}
return unziped;
}
/**
* Unpack a tar file.
*
* @param file the file
* @param destination the destination path or null to unpack at the same directory of file
* @return true if unpacked, false otherwise
*/
public static boolean unpackTarFile(File artifactFile, String destination)
{
boolean unpacked = true;
String extractDestination = destination != null ? destination : artifactFile.getParent();
if (!extractDestination.endsWith(File.separator))
{
extractDestination += File.separator;
}
List<String> commandList = new LinkedList<String>();
commandList.add("tar"); //$NON-NLS-1$
String fileName = artifactFile.getName();
//tar.gz or tgz
if (fileName.endsWith("gz")) //$NON-NLS-1$
{
commandList.add("xzf"); //$NON-NLS-1$
}
//tar.bz2
else if (fileName.endsWith("bz2")) //$NON-NLS-1$
{
commandList.add("xjf"); //$NON-NLS-1$
}
//tar
else if (fileName.endsWith("tar")) //$NON-NLS-1$
{
commandList.add("xf"); //$NON-NLS-1$
}
else
{
unpacked = false;
}
if (unpacked)
{
commandList.add(artifactFile.getAbsolutePath());
File target = new File(extractDestination);
if (target.exists() && target.isDirectory() && target.canWrite())
{
try
{
Process p =
Runtime.getRuntime().exec(commandList.toArray(new String[0]), null,
target);
try
{
p.waitFor();
}
catch (InterruptedException e)
{
//do nothing
}
if (p.exitValue() != 0)
{
unpacked = false;
}
}
catch (IOException e)
{
unpacked = false;
}
}
}
return unpacked;
}
/**
* Copy the input stream to the output stream
* @param inputStream
* @param outputStream
* @throws IOException
*/
public static void copyStreams(InputStream inputStream, OutputStream outputStream)
throws IOException
{
byte[] buffer = new byte[1024];
int length;
while ((length = inputStream.read(buffer)) >= 0)
{
outputStream.write(buffer, 0, length);
}
}
/**
* Add a directory to a Project
* @param project
* @param parentFolder
* @param folderName
* @param monitor
* @throws CoreException
*/
public static void createProjectFolder(IProject project, String parentFolder,
String folderName, IProgressMonitor monitor) throws CoreException
{
monitor.beginTask(UtilitiesNLS.UI_Project_Creating_Folder_Task, 100);
try
{
monitor.setTaskName(UtilitiesNLS.UI_Project_Verifying_Folder_Task);
if (folderName.length() > 0)
{
monitor.worked(10);
IFolder folder = project.getFolder(parentFolder + folderName);
monitor.worked(10);
if (!folder.exists())
{
monitor.worked(10);
if (FileUtil.canWrite(folder.getLocation().toFile()))
{
monitor.worked(10);
monitor.setTaskName(UtilitiesNLS.UI_Project_Creating_Folder_Task);
folder.create(true, true, new SubProgressMonitor(monitor, 60));
}
else
{
String errMsg =
NLS.bind(
UtilitiesNLS.EXC_Project_CannotCreateFolderReadOnlyWorkspace,
folder.getLocation().toFile().toString());
IStatus status = new Status(IStatus.ERROR, CommonPlugin.PLUGIN_ID, errMsg);
throw new CoreException(status);
}
}
}
}
finally
{
monitor.done();
}
}
/**
* Given a directory descriptor represented by a {@link File}, creates it
* only if it does not exist. In case it does, try to create another
* one with its name plus "-1". If it does exists, try to create it with
* its name plus "+2", and so on...
* <br>
* Note that the directory is not fisically created. To do so, on must
* use the method {@link File#mkdir()}.
*
* @param directory Directory to be created.
*
* @return Returns the created directory as a {@link File}.
*/
public static File createUniqueDirectoryDescriptor(File directory)
{
if (directory.exists())
{
boolean exists = true;
int counter = 1;
String rootPath = directory.getAbsolutePath();
while (exists)
{
directory = new File(rootPath + "-" + counter); //$NON-NLS-1$
exists = directory.exists();
counter++;
}
}
return directory;
}
/**
* Return path with special characters escaped.
* Special characters are system dependent, there is a set for linux and another for mac.
* If {@code operationalSystem} is windows, the path is returned unchanged.
*
* @param path to be escaped.
* @param operatingSystem the target operation system that the path will be used.
* @return path with special characters escaped.
* */
public static String getEscapedPath(String path, String operatingSystem)
{
char[] specialCharSet = null;
if (operatingSystem.equals(Platform.OS_LINUX))
{
specialCharSet = LINUX_SPECIAL_CHAR;
}
else if (operatingSystem.equals(Platform.OS_MACOSX))
{
specialCharSet = MAC_SPECIAL_CHAR;
}
if ((path != null) && (specialCharSet != null))
{
for (char c : specialCharSet)
{
CharSequence target = String.valueOf(c);
CharSequence replacement = new String("\\" + String.valueOf(c)); //$NON-NLS-1$
path = path.replace(target, replacement);
}
}
return path;
}
/**
* Return path with special characters escaped.
* Special characters are system dependent, there is a set for linux and another for mac.
* If the system is windows, returns the path unchanged.
*
* @param path to be escaped
* @return path with special characters escaped.
* */
public static String getEscapedPath(String path)
{
return getEscapedPath(path, Platform.getOS());
}
/**
* Return path with special characters unescaped.
* Special characters are system dependent, there is a set for linux and another for mac.
* If the system is windows, returns the path unchanged.
*
* @param path to be unescaped
* @return path with special characters unescaped.
* */
public static String getUnescapedPath(String path)
{
char[] specialCharSet = null;
if (Platform.getOS().equals(Platform.OS_LINUX))
{
specialCharSet = LINUX_SPECIAL_CHAR;
}
else if (Platform.getOS().equals(Platform.OS_MACOSX))
{
specialCharSet = MAC_SPECIAL_CHAR;
}
if ((path != null) && (specialCharSet != null))
{
for (char c : specialCharSet)
{
CharSequence target = new String("\\") + String.valueOf(c); //$NON-NLS-1$
CharSequence replacement = String.valueOf(c);
path = path.replace(target, replacement);
}
}
return path;
}
public static String removeUnescapedQuotes(String path, String quoteReplacement)
{
//remove quotes and double quotes
char quotes[] =
{
'\'', '"'
};
boolean escaped = false;
for (int i = 0; i < path.length(); i++)
{
if (escaped == false)
{
if (path.charAt(i) == ESCAPE_CHAR)
{
escaped = true;
}
else
{
for (char quote : quotes)
{
if (path.charAt(i) == quote)
{
//split the string in two parts:
// - part1: before the quote
String part1 = path.substring(0, i);
// - part2: after the quote
String part2 = path.substring(i + 1, path.length());
//concatenate part1 and part2 with quoteReplacement in-between
//if quoteReplacement is the empty string (""), then part1 and part2 are juxtaposed
path = part1.concat(quoteReplacement).concat(part2);
}
}
}
}
else
{
//current character is escaped, next character can't be escaped
escaped = false;
}
}
return path;
}
/**
* Unescape characters and remove quotes and double quotes.
* Special characters are system dependent, there is a set for linux and another for mac.
* If the system is windows, returns the path unchanged.
*
* @param path to be cleaned.
* @param quoteReplacement string that will replace quotes and double quotes.
* @return path without quotes, double quotes and special characters unescaped.
* */
public static String getCleanPath(String path, String quoteReplacement)
{
path = removeUnescapedQuotes(path, quoteReplacement);
path = getUnescapedPath(path);
return path;
}
public static String calculateMd5Sum(File file) throws IOException
{
String md5Sum = null;
BigInteger hash = null;
FileInputStream fis;
fis = new FileInputStream(file);
byte[] buf = new byte[1500000];
try
{
MessageDigest digest = java.security.MessageDigest.getInstance("MD5"); //$NON-NLS-1$
int bytesRead = 0;
while ((bytesRead = fis.read(buf)) > 0)
{
digest.update(buf, 0, bytesRead);
}
hash = new BigInteger(1, digest.digest());
md5Sum = hash.toString(16);
}
catch (NoSuchAlgorithmException e)
{
// This exception should not happen, because we are using a valid
// hard
// coded value for the algorithm name. However, if it happens, log
// it.
warn("MOTODEV Studio could not find an instance of the MessageDigest for the MD5 algorithm"); //$NON-NLS-1$
throw new IOException(UtilitiesNLS.FileUtil_Get_MD5_Algorithm_Failed);
}
finally
{
if (fis != null)
{
fis.close();
}
}
if (md5Sum == null)
{
throw new IOException(NLS.bind(UtilitiesNLS.FileUtil_MD5_Calculation_Failed,
file.getAbsolutePath()));
}
return md5Sum;
}
/**
* This method is responsible to copy informed source file to informed
* target.
*
* @param sourceFile
* @param targetFile
* @throws IOException
*/
public static void copy(File sourceFile, File targetFile) throws IOException
{
OutputStream outputStream = new FileOutputStream(targetFile);
InputStream inputStream = new FileInputStream(sourceFile);
try
{
int length;
byte[] buffer = new byte[FileUtil.BUFFER_SIZE];
while ((length = inputStream.read(buffer)) >= 0)
{
outputStream.write(buffer, 0, length);
}
}
catch (IOException e)
{
throw new IOException("Error copying file:" + sourceFile.getAbsolutePath() + //$NON-NLS-1$
" to " + targetFile.getAbsolutePath()); //$NON-NLS-1$
}
finally
{
outputStream.close();
inputStream.close();
}
}
/**
* This method normalize a directory path.
*
* @param folder Full path to a directory
* @return The normalized path.
*/
public static String normalizePath(String folder)
{
return folder.endsWith(File.separator) ? folder : folder + File.separator;
}
/**
* Delete the specified file, recursively as necessary.
*
* @param file The file to delete
*/
public static void delete(File file)
{
if (file.exists())
{
if (file.isDirectory())
{
File[] files = file.listFiles();
for (int i = 0; i < files.length; i++)
{
delete(files[i]);
}
}
file.delete();
}
}
/**
* Delete the specified file, recursively as necessary.
*
* @param fileName The file to delete
*/
public static void delete(String fileName)
{
delete(new File(fileName));
}
/**
* This method creates the specified directory.
*
* @param directory The directory to create.
* @throws IOException
*/
public static void mkdir(String directory) throws IOException
{
File f = new File(directory);
if (f.exists())
{
if (f.isFile())
{
throw new IOException("Error creating directory:" + directory); //$NON-NLS-1$
}
}
else
{
if (!f.mkdirs())
{
throw new IOException("Error creating directory:" + directory); //$NON-NLS-1$
}
}
}
}