/* * Created on Apr 22, 2006 */ package com.openedit.util; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.ArrayList; import java.util.Date; import java.util.Iterator; import java.util.List; import java.util.zip.GZIPInputStream; import java.util.zip.ZipEntry; import java.util.zip.ZipException; import java.util.zip.ZipInputStream; import java.util.zip.ZipOutputStream; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.openedit.repository.ContentItem; import org.openedit.util.WindowsUtil; import com.openedit.OpenEditException; import com.openedit.page.manage.PageManager; import com.openedit.users.User; public class ZipUtil { private static final Log log = LogFactory.getLog(ZipUtil.class); protected List fieldExcludes; protected OutputFiller filler = new OutputFiller(); protected String fieldFindFileName; protected boolean fieldExitOnFirstFind; protected String fieldFolderToStripOnZip; public String getFolderToStripOnZip() { return fieldFolderToStripOnZip; } public void setFolderToStripOnZip(String inFolderToStripOnZip) { fieldFolderToStripOnZip = inFolderToStripOnZip.substring(1); } protected File fieldRoot; protected WindowsUtil fieldWindowsUtil; protected PageManager fieldPageManager; public PageManager getPageManager() { return fieldPageManager; } public void setPageManager(PageManager inPageManager) { fieldPageManager = inPageManager; } public WindowsUtil getWindowsUtil() { if (fieldWindowsUtil == null) { fieldWindowsUtil = new WindowsUtil(); fieldWindowsUtil.setRoot(getRoot()); } return fieldWindowsUtil; } public List getExcludes() { if (fieldExcludes == null) { fieldExcludes = new ArrayList(); } return fieldExcludes; } public void addExclude(String inPath) { // dont unzip or zip containing this path if (inPath != null) { inPath = inPath.trim(); } getExcludes().add(inPath); } // TODO: Should these use the getRoot() public void unzip(String inPage, String inDest) throws Exception { unzip(new File(inPage), new File(inDest)); } public List unzip(File inPage, File inDest) throws IOException { InputStream in = null; List unzippedFiles = null; try { in = new FileInputStream(inPage); unzippedFiles = unzip(in, inDest); } finally { FileUtils.safeClose(in); } return unzippedFiles; } public List unzip(InputStream inZip, File inDest) throws IOException { return unzip(inZip, inDest, null); } /** * Wow, this is hard to understand... * * @param inZip * -- The Zip InputStream entries have paths buried in them e.g., * data/subdir/file.txt * @param inDest * -- The destination folder, e.g. /opt/appserver/webapp/ROOT * @param inPathSegment * -- A path segment that might exist in the Zip entries, e.g. * /data or data * @param inNewPathSegment * -- A new path segment we want to use, e.g. /backup to make * backup/subdir/file.txt * @throws IOException */ public List unzip(InputStream inZip, File inDest, String inCutOffLeadingPath) throws IOException { ZipInputStream unzip = new ZipInputStream(inZip); ZipEntry entry = unzip.getNextEntry(); List unzippedFiles = new ArrayList(); while (entry != null) { String entryPath = composeEntryPath(entry.getName(), inCutOffLeadingPath); if (fieldFindFileName != null) { if (!PathUtilities.match(entry.getName(), fieldFindFileName)) // TODO // : // Handle // leading // / { entry = unzip.getNextEntry(); continue; } } if (entryPath.contains("__MACOSX")) { entry = unzip.getNextEntry(); continue; } // int zipeSize = (int) entry.getSize(); if (!entry.isDirectory()) { File ufile = null; if (inDest != null) { ufile = new File(inDest, entryPath); } else { ufile = new File(entryPath); } ufile.getParentFile().mkdirs(); if (ufile.exists() && !ufile.delete()) { getWindowsUtil().delete(ufile); } FileOutputStream tout = new FileOutputStream(ufile); try { filler.fill(unzip, tout); } finally { FileUtils.safeClose(tout); } ufile.setLastModified(entry.getTime()); if( log.isDebugEnabled() ) { log.debug(ufile.getAbsolutePath()); } unzippedFiles.add(ufile); if (isExitOnFirstFind()) { return unzippedFiles; } } entry = unzip.getNextEntry(); } return unzippedFiles; } protected String composeEntryPath(String name, String inCutOffLeadingPath) { if (inCutOffLeadingPath != null) { return name.substring(inCutOffLeadingPath.length()); } return name; } /* * public void zipFilesIn( File inDir,OutputStream inToBrowser ) throws * IOException, OpenEditException { zipFilesIn(inDir,"/", inToBrowser); } */ /* * public void zipFilesIn( File inDir,String inIncludePath, OutputStream * inToBrowser ) throws IOException, OpenEditException { * * String startingdir = inDir.getAbsolutePath(); if ( * !startingdir.endsWith(File.separator)) { startingdir = startingdir + * File.separator; } if( inIncludePath.length() > 1) { inDir = new File( * inDir, inIncludePath); } * * ZipOutputStream finalZip = new ZipOutputStream(inToBrowser); * * File[] children = inDir.listFiles(); if ( children != null) { for (int i * = 0; i < children.length; i++) { addToZip( children[i], startingdir, * finalZip); } } finalZip.close(); } */ public void addTozip(String inContent, String inName, ZipOutputStream finalZip) throws IOException { ZipEntry entry = new ZipEntry(inName); entry.setSize(inContent.length()); entry.setTime(new Date().getTime()); finalZip.putNextEntry(entry); finalZip.write(inContent.getBytes("UTF-8")); finalZip.closeEntry(); } public void addTozip(ContentItem inContent, String inName, ZipOutputStream finalZip) throws IOException { InputStream is = inContent.getInputStream(); if (is == null) { log.error("Couldn't add file to zip: " + inContent.getAbsolutePath()); return; } ZipEntry entry = null; if (getFolderToStripOnZip() != null) { if(inName.contains(getFolderToStripOnZip())){ String stripped = inName.substring(getFolderToStripOnZip().length(), inName.length()); entry = new ZipEntry(stripped); } else{ entry = new ZipEntry(inName); } } else { entry = new ZipEntry(inName); } entry.setSize(inContent.getLength()); entry.setTime(inContent.lastModified().getTime()); finalZip.putNextEntry(entry); try { new OutputFiller().fill(is, finalZip); } finally { is.close(); } finalZip.closeEntry(); } public void zip(String inOpenEditPath, ZipOutputStream inStream, boolean recursive) { ZipProcessor zipper = new ZipProcessor(); zipper.setPageManager(getPageManager()); zipper.zipOutputStream = inStream; zipper.setRecursive(recursive); zipper.process(inOpenEditPath); } public void zip(String inOpenEditPath, ZipOutputStream inStream) { zip(inOpenEditPath, inStream, true); } public void zipFile(String inOpenEditPath, OutputStream inToBrowser) throws IOException, OpenEditException { ZipOutputStream finalZip = new ZipOutputStream(inToBrowser); zip(inOpenEditPath, finalZip); finalZip.close(); } public void zipFiles(List inPaths, OutputStream inToBrowser, boolean recursive) throws IOException, OpenEditException { // TODO: inRelative isn't used. Fix up SyncToServer to not use it ZipOutputStream finalZip = new ZipOutputStream(inToBrowser); for (Iterator iterator = inPaths.iterator(); iterator.hasNext();) { String path = (String) iterator.next(); zip(path, finalZip, recursive); } // Throws exception if the folder was empty try { finalZip.close(); } catch (ZipException ex) { // zip might have been empty FileUtils.safeClose(inToBrowser); } } public void zipFiles(List inPaths, OutputStream inToBrowser) throws IOException, OpenEditException { zipFiles(inPaths, inToBrowser, true); } class ZipProcessor extends PathProcessor { ZipOutputStream zipOutputStream; public void processFile(ContentItem inContent, User inUser) throws OpenEditException { String path = inContent.getPath(); // if (inContent instanceof FileItem) // { // String abs = ((FileItem) inContent).getAbsolutePath(); // if (getRoot() != null) // { // String root = getRoot().getAbsolutePath(); // if (abs.contains(getRoot().getAbsolutePath())) // { // path = abs.substring(root.length()); // } // } // } // The zip entry can't begin with any slashes while (path.startsWith("/")) { path = path.substring(1, path.length()); } try { addTozip(inContent, path, zipOutputStream); } catch (Exception e) { if( e.getMessage().startsWith("duplicate")) { return; } throw new OpenEditException(e); } } public boolean acceptFile(ContentItem inFileItem) { String openeditpath = inFileItem.getPath();// .replace('\\', '/'); // // Windows // replace if (inFileItem.isFolder() && !openeditpath.endsWith("/")) { openeditpath = openeditpath + "/"; // Make sure we leave the / // on there for directories } return isValidEntry(openeditpath); } public boolean acceptDir(ContentItem inDir) { return acceptFile(inDir); } } protected boolean isValidEntry(String inPath) throws OpenEditException { if (exclude(inPath)) { return false; } return true; } protected boolean exclude(String inOpenEditPath) { if (fieldExcludes != null) { for (Iterator iter = getExcludes().iterator(); iter.hasNext();) { String wild = (String) iter.next(); if (PathUtilities.match(inOpenEditPath, wild)) { return true; } } } return false; } public String getFindFileName() { return fieldFindFileName; } public void setFindFileName(String inFindFileName) { fieldFindFileName = inFindFileName; } public boolean isExitOnFirstFind() { return fieldExitOnFirstFind; } public void setExitOnFirstFind(boolean inExitOnFirstFind) { fieldExitOnFirstFind = inExitOnFirstFind; } public File getRoot() { return fieldRoot; } public void setRoot(File inRoot) { fieldRoot = inRoot; } /** * Unzips a GZIP file that contains only one file. * * @param inSource * The source GZIP file. * @param inDest * destination file. * @return true if destination file exists after uncompressing. * @throws IOException * @throws FileNotFoundException */ public boolean gunzip(File inSource, File inDest) throws FileNotFoundException, IOException { if (inDest.exists()) inDest.delete(); InputStream in = new GZIPInputStream(new FileInputStream(inSource)); OutputStream out = new FileOutputStream(inDest); new OutputFiller().fill(in, out); in.close(); out.close(); return inDest.exists(); } }