/*******************************************************************************
* Copyright (c) 2007 Exadel, Inc. and Red Hat, Inc.
* Distributed under license by Red Hat, Inc. All rights reserved.
* This program is made available under the terms of the
* Eclipse Public License v1.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Exadel, Inc. and Red Hat, Inc. - initial API and implementation
******************************************************************************/
package org.jboss.tools.common.util;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.jar.JarInputStream;
import java.util.jar.JarOutputStream;
import java.util.jar.Manifest;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.jboss.tools.common.core.CommonCorePlugin;
public class FileUtils {
public FileUtils() {}
public static String getEncoding(IFile f) {
String encoding = null;
if(f != null && f.exists() && f.isSynchronized(0)) try {
encoding = f.getCharset();
} catch (CoreException e) {
CommonCorePlugin.getPluginLog().logError(e);
}
return encoding != null ? encoding : "8859_1"; //$NON-NLS-1$
}
public static String readFile(File f) {
if(!f.isFile()) return ""; //$NON-NLS-1$
ReadBytes bs = readBytes(f);
if(bs == null) return ""; //$NON-NLS-1$
String encoding = getEncoding(bs.bs);
if(encoding == null) return new String(bs.bs, 0, bs.length);
try {
return new String(bs.bs, 0, bs.length, encoding);
} catch (UnsupportedEncodingException e) {
return new String(bs.bs, 0, bs.length);
}
}
public static String readFileWithEncodingCheck(File f, String defaultEncoding) {
if(!f.isFile()) return ""; //$NON-NLS-1$
ReadBytes bs = readBytes(f);
if(bs == null) return ""; //$NON-NLS-1$
String encoding = getEncoding(bs.bs);
if(encoding == null) encoding = validateEncoding(defaultEncoding, null);
if(encoding == null) return new String(bs.bs, 0, bs.length);
try {
return new String(bs.bs, 0, bs.length, encoding);
} catch (UnsupportedEncodingException e) {
return new String(bs.bs, 0, bs.length);
}
}
public static ReadBytes readBytes(File f) {
if(!f.isFile()) return null;
BufferedInputStream br = null;
try {
FileInputStream fr = new FileInputStream(f);
br = new BufferedInputStream(fr);
int l = (int)f.length();
byte[] bs = new byte[l];
l = br.read(bs, 0, l);
br.close();
fr.close();
return new ReadBytes(bs, l);
} catch (IOException e) {
return null;
} finally {
if(br!=null) {
try {
br.close();
} catch (IOException e) {
//ignore
}
}
}
}
static class ReadBytes {
byte[] bs;
int length;
ReadBytes(byte[] bs, int l) {
this.bs = bs;
length = l;
}
}
public static String readFile(File f, String encoding) {
ReadBytes bs = readBytes(f);
if(bs == null) return null;
try {
return new String(bs.bs, 0, bs.length, encoding);
} catch (UnsupportedEncodingException e) {
return null;
}
}
public static boolean isTextFile(File f, int length) {
if(!f.isFile()) return false;
BufferedReader br = null;
try {
FileReader fr = new FileReader(f);
br = new BufferedReader(fr);
int l = (int)f.length();
if(l > length) l = length;
char[] cs = new char[l];
br.read(cs, 0, l);
br.close();
fr.close();
return isText(new String(cs));
} catch (IOException e) {
return false;
} finally {
if(br!=null) {
try {
br.close();
} catch (IOException e) {
// ignore
}
}
}
}
public static boolean isText(String body) {
if(body == null) return false;
int l = body.length();
for (int i = 0; i < l; i++) {
char c = body.charAt(i);
if(((int)c) < 32 && c != '\n' && c != '\r' && c != 't') return false;
}
return true;
}
// FIXME Size of string buffer should be set to size of file by default
// to avoid StringBuffer extension on each append
public static String readStream(InputStream is) {
StringBuffer sb = new StringBuffer(""); //$NON-NLS-1$
try {
byte[] b = new byte[4096];
while(true) {
int l = is.read(b, 0, b.length);
if(l < 0) break;
sb.append(new String(b, 0, l));
}
} catch (IOException e) {
CommonCorePlugin.getPluginLog().logError(e);
} finally {
try {
is.close();
} catch (IOException e) {
// Ignore
}
}
return sb.toString();
}
public static String readStream(IFile file) throws CoreException {
String content = null;
InputStream in = null;
try {
String charset = file.getCharset();
if(charset != null) {
charset = validateEncoding(charset, null);
}
in = file.getContents();
content = (charset == null) ? readStream(in) : readStream(in, charset);
} finally {
if(in!=null) {
try {
in.close();
} catch (IOException e) {
CommonCorePlugin.getPluginLog().logError(e);
}
}
}
return content;
}
public static String readStream(InputStream is, String charset) {
StringBuffer sb = new StringBuffer(""); //$NON-NLS-1$
try {
byte[] b = new byte[4096];
while(true) {
int l = is.read(b, 0, b.length);
if(l < 0) break;
sb.append(new String(b, 0, l, charset));
}
} catch (IOException e) {
CommonCorePlugin.getPluginLog().logError(e);
} finally {
try {
is.close();
} catch (IOException e) {
// Ignore
}
}
return sb.toString();
}
public static void copyContent(IFile from, IFile to, boolean force, boolean keepHistory, IProgressMonitor monitor) throws CoreException {
InputStream is = null;
try {
is = from.getContents();
to.setContents(is, force, keepHistory, monitor);
} finally {
if(is!=null) {
try {
is.close();
} catch (IOException e) {
CommonCorePlugin.getPluginLog().logError(e);
}
}
}
}
public static boolean writeFile(File f, String value) {
return writeFileWithEncodingCheck(f, value, null);
}
public static boolean writeFileWithEncodingCheck(File f, String value, String defaultEncoding) {
if(value == null) return false;
String encoding = getEncoding(value);
if(encoding == null) encoding = validateEncoding(defaultEncoding, null);
if(value.startsWith("<?xml")) { //$NON-NLS-1$
String s = validateEncoding(encoding, "UTF-8"); //$NON-NLS-1$
if(encoding == null) {
encoding = s;
} else if(s == null || !s.equals(encoding)) {
return false;
}
}
if(encoding == null) return writeFileDefault(f, value);
return writeFile(f, value, encoding);
}
public static boolean writeFileDefault(File f, String value) {
try {
try {
if(f.isFile() && !isSameFile(f)) f.delete();
if(!f.exists()) f.createNewFile();
} catch (IOException e) {
CommonCorePlugin.getPluginLog().logError("Problem writing to file " + f, e); //$NON-NLS-1$
} catch (SecurityException e) {
CommonCorePlugin.getPluginLog().logError("Problem writing to file " + f, e); //$NON-NLS-1$
}
PrintWriter pw = new PrintWriter(new FileWriter(f));
pw.print(value);
pw.flush();
pw.close();
return true;
} catch (IOException e) {
return false;
}
}
public static boolean copyFile(File source, File dest, boolean mkdirs) {
return copyFile(source, dest, mkdirs, true);
}
public static boolean copyFile(File source, File dest) {
return copyFile(source, dest, false, true);
}
public static boolean copyFile(File source, File dest, boolean mkdirs, boolean overwrite) {
if (mkdirs) dest.getParentFile().mkdirs();
if(!source.isFile()) return false;
if(dest.isFile() && !isSameFile(dest)) dest.delete();
if(dest.isFile() && !overwrite) return false;
if(!dest.exists())
try {
dest.createNewFile();
} catch (IOException e1) {
CommonCorePlugin.getPluginLog().logError(e1);
}
InputStream is = null;
OutputStream os = null;
try {
is = new BufferedInputStream(new FileInputStream(source), 16 * 1024);
os = new BufferedOutputStream(new FileOutputStream(dest), 16 * 1024);
copyStream(is, os);
return true;
} catch (IOException e) {
CommonCorePlugin.getPluginLog().logError(e);
return false;
} finally {
try {
if (is != null) is.close();
} catch (IOException e) {
CommonCorePlugin.getPluginLog().logError(e);
}
try {
if (os != null) os.close();
} catch (IOException e) {
CommonCorePlugin.getPluginLog().logError(e);
}
}
}
public static boolean updateFile(File source, File dest, boolean mkdirs) {
if(!source.isFile()) return false;
if(dest.isFile() && (dest.lastModified()<source.lastModified())) {
dest.delete();
}
return copyFile(source, dest, mkdirs);
}
public static void copyStream(InputStream is, OutputStream os) throws IOException {
byte[] buffer = new byte[1<<14];
while (true) {
int r = is.read(buffer);
if (r > 0) {
os.write(buffer, 0, r);
} else if (r == -1) break;
}
os.flush();
}
public static void clear(File f) {
if (f.isDirectory()) {
File[] fs = f.listFiles();
for (int i = 0; i < fs.length; i++) {
remove(fs[i]);
}
}
}
public static void remove(File f) {
if (f.isFile()) {
f.delete();
} else if (f.isDirectory()) {
File[] fs = f.listFiles();
for (int i = 0; i < fs.length; i++) {
remove(fs[i]);
}
f.delete();
}
}
public static boolean isSameFile(File f) {
if(!f.exists()) return false;
String fn = f.getName();
try {
String cn = f.getCanonicalFile().getName();
return fn.equals(cn);
} catch (IOException e) {
return false;
}
}
public static void copyDir(File from, File to) {
copyDir(from, to, false);
}
public static void copyDir(File from, File to, boolean mkdirs) {
copyDir(from, to, mkdirs, true);
}
public static void copyDir(File from, File to, boolean mkdirs, boolean includeSubdirs) {
copyDir(from, to, includeSubdirs, mkdirs, false);
}
public static void copyDir(File from, boolean includeSubdirs, File to) {
copyDir(from, to, includeSubdirs, false, false);
}
public static void copyDir(File from, File to, boolean includeSubdirs, boolean mkdirs, boolean overwriteOnlyOlderFiles) {
copyDir(from, to, includeSubdirs, mkdirs, overwriteOnlyOlderFiles, null);
}
public static void copyDir(File from, File to, boolean includeSubdirs, boolean mkdirs, boolean overwriteOnlyOlderFiles, FileFilter filter) {
if(filter != null && !filter.accept(from)) return;
if (mkdirs) to.mkdirs();
if(from == null || !from.isDirectory() || !to.isDirectory()) return;
File[] fs = from.listFiles();
if(fs == null) return;
for (int i = 0; i < fs.length; i++) {
String n = fs[i].getName();
File c = new File(to, n);
if (fs[i].isDirectory() && !includeSubdirs) continue;
if(filter != null && !filter.accept(new File(from, n))) continue;
if(fs[i].isDirectory()) {
c.mkdirs();
copyDir(fs[i], c, includeSubdirs, mkdirs, overwriteOnlyOlderFiles, filter);
} else if (overwriteOnlyOlderFiles && fs[i].isFile() && c.isFile()) {
copyFile(fs[i], c, false, c.lastModified() < fs[i].lastModified());
} else {
copyFile(fs[i], c);
}
}
}
public static void unjar(File dest, String jar) throws IOException {
dest.mkdirs();
JarFile jf = new JarFile(jar);
try {
Enumeration es = jf.entries();
while(es.hasMoreElements()) {
JarEntry je = (JarEntry)es.nextElement();
String n = je.getName();
File f = new File(dest, n);
if (je.isDirectory()) {
f.mkdirs();
} else {
if (f.exists()) {
f.delete();
} else {
f.getParentFile().mkdirs();
}
InputStream is = jf.getInputStream(je);
FileOutputStream os = new FileOutputStream(f);
try {
copyStream(is, os);
} finally {
os.close();
}
}
long time = je.getTime();
if (time != -1) f.setLastModified(time);
}
} finally {
jf.close();
}
}
public static void unjar(File dest, InputStream is) throws IOException {
dest.mkdirs();
JarInputStream jis = new JarInputStream(is);
try {
while(true) {
JarEntry je = jis.getNextJarEntry();
if (je == null) break;
String n = je.getName();
File f = new File(dest, n);
if (je.isDirectory()) {
f.mkdirs();
} else {
if (f.exists()) {
f.delete();
} else {
f.getParentFile().mkdirs();
}
FileOutputStream os = new FileOutputStream(f);
try {
copyStream(jis, os);
} finally {
os.close();
}
}
long time = je.getTime();
if (time != -1) f.setLastModified(time);
}
} finally {
jis.close();
}
}
public static void jar(File[] fs, String path) throws IOException {
jar(fs, path, null);
}
public static void jar(File[] fs, String path, Manifest mf) throws IOException {
File f = new File(path);
FileOutputStream fos = new FileOutputStream(f);
JarOutputStream jos = mf == null ? new JarOutputStream(fos) : new JarOutputStream(fos, mf);
try {
for (int i = 0; i < fs.length; i++) add(fs[i].getParentFile(), fs[i], jos);
} finally {
jos.close();
fos.close();
}
}
public static void add(File root, File f, JarOutputStream jos) throws IOException {
int l = root.getAbsolutePath().length();
String en = f.getAbsolutePath().substring(l + 1).replace('\\', '/');
add(f, en, jos);
}
public static void add(File f, String name, JarOutputStream jos) throws IOException {
String en = name;
if(f.isDirectory()) en += "/"; //$NON-NLS-1$
JarEntry entry = (en.endsWith("/")) ? null : new JarEntry(en); //$NON-NLS-1$
if(f.isDirectory()) {
if("/".equals(en)) en = ""; //$NON-NLS-1$ //$NON-NLS-2$
File[] fs = f.listFiles();
if(fs != null) for (int i = 0; i < fs.length; i++)
add(fs[i], en + fs[i].getName(), jos);
} else {
try {
jos.putNextEntry(entry);
} catch (IOException e) {
return;
}
FileInputStream is = new FileInputStream(f);
byte[] b = new byte[1024];
int q = 0;
while((q = is.available()) > 0) {
if(q > 1024) q = 1024;
q = is.read(b, 0, q);
jos.write(b, 0, q);
}
is.close();
}
if(entry != null) jos.closeEntry();
}
public static void copy(InputStream f, OutputStream t) throws IOException {
try {
byte[] b = new byte[1024];
int q = 0;
while((q = f.read(b, 0, b.length)) > 0) t.write(b, 0, q);
} finally {
f.close();
t.close();
}
}
public static void unzip(File dest, String jar) throws IOException {
dest.mkdirs();
ZipFile zf = new ZipFile(jar);
try {
Enumeration es = zf.entries();
while(es.hasMoreElements()) {
ZipEntry je = (ZipEntry)es.nextElement();
String n = je.getName();
File f = new File(dest, n);
if (je.isDirectory()) {
f.mkdirs();
} else {
if (f.exists()) {
f.delete();
} else {
f.getParentFile().mkdirs();
}
InputStream is = zf.getInputStream(je);
FileOutputStream os = new FileOutputStream(f);
try {
copyStream(is, os);
} finally {
os.close();
}
}
long time = je.getTime();
if (time != -1) f.setLastModified(time);
}
} finally {
zf.close();
}
}
public static String fileURLToFilePath(String url) {
if(url == null) return null;
String resultUrl = url.replace('\\', '/');
/// if(!url.startsWith("file:/")) return url;
if(!resultUrl.startsWith("file:")) return resultUrl; //$NON-NLS-1$
int iLast = resultUrl.lastIndexOf(':'), iFirst = resultUrl.indexOf(':');
return (iLast == iFirst) ? resultUrl.substring(5) : resultUrl.substring(iLast - 1);
}
//// Relative path
public static String getRelativePath(String rootpath, String path) {
String[] r = tokenizePath(rootpath);
String[] p = tokenizePath(path);
if(r.length == 0 || p.length == 0 || !r[0].equalsIgnoreCase(p[0])) return null;
int i = 0;
while(i < r.length && i < p.length && r[i].equalsIgnoreCase(p[i])) ++i;
StringBuffer sb = new StringBuffer();
for (int k = i; k < r.length; k++) sb.append("/.."); //$NON-NLS-1$
for (int k = i; k < p.length; k++) sb.append("/").append(p[k]); //$NON-NLS-1$
return sb.toString();
}
private static String[] tokenizePath(String path) {
String tokenizedPath = path.replace('\\', '/');
StringTokenizer st = new StringTokenizer(tokenizedPath, "/"); //$NON-NLS-1$
ArrayList l = new ArrayList();
while(st.hasMoreTokens()) {
String t = st.nextToken();
if(t.isEmpty() || ".".equals(t)) continue; //$NON-NLS-1$
if("..".equals(t)) { //$NON-NLS-1$
if(!l.isEmpty()) l.remove(l.size() - 1);
continue;
}
l.add(t);
}
return (String[])l.toArray(new String[l.size()]);
}
public static boolean writeFile(File f, String value, String encoding) {
try {
try {
if(f.isFile() && !isSameFile(f)) f.delete();
if(!f.exists()) {
f.getParentFile().mkdirs();
f.createNewFile();
}
} catch (IOException e) {
CommonCorePlugin.getPluginLog().logError(e);
}
FileOutputStream fs = new FileOutputStream(f);
OutputStreamWriter osw = new OutputStreamWriter(fs, encoding);
PrintWriter pw = new PrintWriter(osw);
pw.print(value);
pw.flush();
pw.close();
return true;
} catch (FileNotFoundException e) {
//ignore
return writeFileDefault(f, value);
} catch (UnsupportedEncodingException e) {
//ignore
return writeFileDefault(f, value);
}
}
public static String getEncoding(String s) {
if(s == null) return null;
if(s.startsWith("<?xml")) { //$NON-NLS-1$
int i = s.indexOf("encoding="); //$NON-NLS-1$
if(i < 0) return null;
i += "encoding=".length() + 1; //$NON-NLS-1$
int j = s.indexOf('\"', i);
if(j < 0) return null;
return s.substring(i, j);
}
return null;
}
static Set validEncodings = new HashSet();
static Set invalidEncodings = new HashSet();
public static String validateEncoding(String encoding, String defaultEncoding) {
if(encoding == null || encoding.equals(defaultEncoding)) return defaultEncoding;
if(validEncodings.contains(encoding)) return encoding;
if(invalidEncodings.contains(encoding)) return defaultEncoding;
try {
if(defaultEncoding != null && defaultEncoding.equals("UTF-16")) { //$NON-NLS-1$
new String(XML_16, 0, XML_16.length, encoding);
} else {
new String(XML_8, 0, XML_8.length, encoding);
}
validEncodings.add(encoding);
return encoding;
} catch (UnsupportedEncodingException e) {
invalidEncodings.add(encoding);
return defaultEncoding;
}
}
static byte[] XML_8 = {(byte)'<',(byte)'?',(byte)'x',(byte)'m',(byte)'l'};
static byte[] XML_16 = {(byte)-2,(byte)-1,(byte)0,(byte)60,(byte)0,(byte)63,(byte)0,(byte)120,(byte)0,(byte)109,(byte)0,(byte)108};
public static String getEncoding(byte[] bs) {
if(bs.length < 20) return null;
if(startsWith(bs, XML_8)) {
int i = getIndex(bs, (byte)'?', 5);
if(i < 0) return "UTF-8"; //$NON-NLS-1$
String encoding = getEncoding(new String(bs, 0, i));
return validateEncoding(encoding, "UTF-8"); //$NON-NLS-1$
} else if(startsWith(bs, XML_16)) {
int i = getIndex(bs, (byte)'?', XML_16.length);
if(i < 0) return "UTF-16"; //$NON-NLS-1$
try {
String encoding = getEncoding(new String(bs, 0, i, "UTF-16")); //$NON-NLS-1$
return validateEncoding(encoding, "UTF-16"); //$NON-NLS-1$
} catch (UnsupportedEncodingException e) {
return null;
}
}
return null;
}
static boolean startsWith(byte[] bs, byte[] prefix) {
for (int i = 0; i < prefix.length; i++) {
if(bs[i] != prefix[i]) return false;
}
return true;
}
static int getIndex(byte[] bs, byte b, int offset) {
for (int i = offset; i < bs.length; i++) {
if(bs[i] == b) return i;
}
return -1;
}
}