Package org.olat.core.util

Source Code of org.olat.core.util.ZipUtil

/**
* OLAT - Online Learning and Training<br>
* http://www.olat.org
* <p>
* Licensed under the Apache License, Version 2.0 (the "License"); <br>
* you may not use this file except in compliance with the License.<br>
* You may obtain a copy of the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing,<br>
* software distributed under the License is distributed on an "AS IS" BASIS, <br>
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
* See the License for the specific language governing permissions and <br>
* limitations under the License.
* <p>
* Copyright (c) 1999-2006 at Multimedia- & E-Learning Services (MELS),<br>
* University of Zurich, Switzerland.
* <p>
*/

package org.olat.core.util;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.StringTokenizer;

import net.sf.jazzlib.ZipEntry;
import net.sf.jazzlib.ZipInputStream;
import net.sf.jazzlib.ZipOutputStream;

import org.olat.core.commons.modules.bc.meta.MetaInfoHelper;
import org.olat.core.id.Identity;
import org.olat.core.logging.OLATRuntimeException;
import org.olat.core.logging.OLog;
import org.olat.core.logging.Tracing;
import org.olat.core.util.vfs.LocalFileImpl;
import org.olat.core.util.vfs.LocalFolderImpl;
import org.olat.core.util.vfs.LocalImpl;
import org.olat.core.util.vfs.VFSContainer;
import org.olat.core.util.vfs.VFSItem;
import org.olat.core.util.vfs.VFSLeaf;
import org.olat.core.util.vfs.version.Versionable;
import org.olat.core.util.vfs.version.VersionsFileManager;

/**
* Initial Date:  04.12.2002
*
* @author Mike Stock
*
* Comment: 
*
*/
public class ZipUtil {

  private static final String DIR_NAME__MACOSX = "__MACOSX/";
 
  private static final OLog log = Tracing.createLoggerFor(VersionsFileManager.class);


  /**
   * Constructor for ZipUtil.
   */
  public ZipUtil() {
    super();
  }


  /**
   * Unzip a file to a directory
   * @param zipFile    The zip file to unzip
   * @param targetDir  The directory to unzip the file to
   * @return  True if successfull, false otherwise
   */
  public static boolean unzip(File zipFile, File targetDir) {
    return unzip(new LocalFileImpl(zipFile), new LocalFolderImpl(targetDir));
  }
 
  /**
   * Unzip a inputstream to a directory
   * @param zipInputStream  The inputstream to unzip
   * @param targetDir  The directory to unzip the file to
   * @return  True if successfull, false otherwise
   */
  public static boolean unzip(VFSLeaf zipLeaf, VFSContainer targetDir) {
    return unzip(zipLeaf, targetDir, null, false);
  }
 
  /**
   * Unzip a inputstream to a directory using the versioning system of VFS
   * @param zipLeaf  The file to unzip
   * @param targetDir  The directory to unzip the file to
   * @param the identity of who unzip the file
   * @param versioning enabled or not
   * @return  True if successfull, false otherwise
   */
  public static boolean unzip(VFSLeaf zipLeaf, VFSContainer targetDir, Identity identity, boolean versioning) {

    ZipInputStream oZip = new ZipInputStream(zipLeaf.getInputStream());
   
    try {
      // unzip files
      ZipEntry oEntr = oZip.getNextEntry();
      while (oEntr != null) {
        if (oEntr.getName() != null && !oEntr.getName().startsWith(DIR_NAME__MACOSX)) {
          if (oEntr.isDirectory()) {
            // skip MacOSX specific metadata directory
            // create directories
            getAllSubdirs(targetDir, oEntr.getName(), true);
          } else {
            // create file
            VFSContainer createIn = targetDir;
            String name = oEntr.getName();
            // check if entry has directories which did not show up as
            // directories above
            int dirSepIndex = name.lastIndexOf('/');
            if (dirSepIndex == -1) {
              // try it windows style, backslash is also valid format
              dirSepIndex = name.lastIndexOf('\\');
            }
            if (dirSepIndex > 0) {
              // create subdirs
              createIn = getAllSubdirs(targetDir, name.substring(0, dirSepIndex), true);
              if (createIn == null) {
                if (log.isDebug()) log.debug("Error creating directory structure for zip entry: "
                    + oEntr.getName());
                return false;
              }
              name = name.substring(dirSepIndex + 1);
            }
           
            if(versioning) {
              VFSLeaf newEntry = (VFSLeaf)createIn.resolve(name);
              if(newEntry == null) {
                newEntry = createIn.createChildLeaf(name);
                OutputStream out = newEntry.getOutputStream(false);
                if (!FileUtils.copy(oZip, out)) return false;
                FileUtils.closeSafely(out);
              } else if (newEntry instanceof Versionable) {
                Versionable versionable = (Versionable)newEntry;
                if(versionable.getVersions().isVersioned()) {
                  versionable.getVersions().addVersion(identity, "", oZip);
                }
              }
            } else {
              VFSLeaf newEntry = createIn.createChildLeaf(name);
              if (newEntry != null) {
                OutputStream out = newEntry.getOutputStream(false);
                if (!FileUtils.copy(oZip, out)) return false;
                FileUtils.closeSafely(out);
              }
            }
          }
        }
        oZip.closeEntry();
        oEntr = oZip.getNextEntry();
      }
    } catch (IOException e) {
      return false;
    } finally {
      FileUtils.closeSafely(oZip);
    }
    return true;
  } // unzip
 
  /**
   * Check if a file in the zip is already in the path
   * @param zipLeaf
   * @param targetDir
   * @param identity
   * @param isAdmin
   * @return the list of files which already exist
   */
  public static List<String> checkLockedFileBeforeUnzip(VFSLeaf zipLeaf, VFSContainer targetDir, Identity identity, boolean isAdmin) {
    List<String> lockedFiles = new ArrayList<String>();
   
    ZipInputStream oZip = new ZipInputStream(zipLeaf.getInputStream());
   
    try {
      // unzip files
      ZipEntry oEntr = oZip.getNextEntry();
      while (oEntr != null) {
        if (oEntr.getName() != null && !oEntr.getName().startsWith(DIR_NAME__MACOSX)) {
          if (oEntr.isDirectory()) {
            // skip MacOSX specific metadata directory
            // directories aren't locked
            oZip.closeEntry();
            oEntr = oZip.getNextEntry();
            continue;
          } else {
            // search file
            VFSContainer createIn = targetDir;
            String name = oEntr.getName();
            // check if entry has directories which did not show up as
            // directories above
            int dirSepIndex = name.lastIndexOf('/');
            if (dirSepIndex == -1) {
              // try it windows style, backslash is also valid format
              dirSepIndex = name.lastIndexOf('\\');
            }
            if (dirSepIndex > 0) {
              // get subdirs
              createIn = getAllSubdirs(targetDir, name.substring(0, dirSepIndex), false);
              if (createIn == null) {
                //sub directories don't exist, and aren't locked
                oZip.closeEntry();
                oEntr = oZip.getNextEntry();
                continue;
              }
              name = name.substring(dirSepIndex + 1);
            }
           
            VFSLeaf newEntry = (VFSLeaf)createIn.resolve(name);
            if(MetaInfoHelper.isLocked(newEntry, identity, isAdmin)) {
              lockedFiles.add(name);
            }
          }
        }
        oZip.closeEntry();
        oEntr = oZip.getNextEntry();
      }
    } catch (IOException e) {
      return null;
    } finally {
      FileUtils.closeSafely(oZip);
    }

    return lockedFiles;
  }

  /**
   * Get the whole subpath.
   * @param create the missing directories
   * @param base
   * @param subDirPath
   * @return Returns the last container of this subpath.
   */
  private static VFSContainer getAllSubdirs(VFSContainer base, String subDirPath, boolean create) {
    StringTokenizer st;
    if (subDirPath.indexOf("/") != -1) {
      st = new StringTokenizer(subDirPath, "/", false);
    } else {
      // try it windows style, backslash is also valid format
      st = new StringTokenizer(subDirPath, "\\", false);
    }
    VFSContainer currentPath = base;
    while (st.hasMoreTokens()) {
      String nextSubpath = st.nextToken();
      VFSItem vfsSubpath = currentPath.resolve(nextSubpath);
      if (vfsSubpath == null && !create) {
        return null;
      }
      if (vfsSubpath == null || (vfsSubpath instanceof VFSLeaf)) {
        vfsSubpath = currentPath.createChildContainer(nextSubpath);
        if (vfsSubpath == null) return null;
      }
      currentPath = (VFSContainer)vfsSubpath;
    }
    return currentPath;
  }
 
  /**
   * Add the set of files residing in root to the ZIP file named target.
   * Files in subfolders will be compressed too.
   *
   * @param files    Filenames to add to ZIP, relative to root
   * @param root    Base path.
   * @param target  Target ZIP file.
   * @return true if successfull, false otherwise.
   */
  public static boolean zip(Set<String> files, File root, File target) {
    //  Create a buffer for reading the files
    if (target.exists()) return false;
    List<VFSItem> vfsFiles = new ArrayList<VFSItem>();
    LocalFolderImpl vfsRoot = new LocalFolderImpl(root);
    for (Iterator<String> iter = files.iterator(); iter.hasNext();) {
      String fileName = iter.next();
      VFSItem item = vfsRoot.resolve(fileName);
      if (item == null) return false;
      vfsFiles.add(item);
    }
    return zip(vfsFiles, new LocalFileImpl(target));
  } // zip
 
  public static boolean zip(List<VFSItem> vfsFiles, VFSLeaf target) {
    boolean success = true;
    OutputStream out = target.getOutputStream(false);
    if (out == null) {
      String name = target.getName();
      if (target instanceof LocalImpl)
        name = ((LocalImpl)target).getBasefile().getAbsolutePath();
      throw new OLATRuntimeException(ZipUtil.class, "Error getting output stream for file: " + name, null);
    }
    ZipOutputStream zipOut = new ZipOutputStream(out);
    for (Iterator<VFSItem> iter = vfsFiles.iterator(); iter.hasNext();) {
      success = success && addToZip(iter.next(), "", zipOut);
    }
    FileUtils.closeSafely(zipOut);
    return success;
  }
 
  private static boolean addToZip(VFSItem vfsItem, String currentPath, ZipOutputStream out) {

    boolean success = true;
    InputStream in = null;
    try {
      String itemName = currentPath.length() == 0 ?
          vfsItem.getName() : currentPath + "/" + vfsItem.getName();
      if (vfsItem instanceof VFSContainer) {
        // this is a directory
        List<VFSItem> items = ((VFSContainer)vfsItem).getItems();
        for (Iterator<VFSItem> iter = items.iterator(); iter.hasNext();) {
          success = success && addToZip(iter.next(), itemName, out);
        }
      } else {
        // Add ZIP entry to output stream.
        out.putNextEntry(new ZipEntry(itemName));
 
        // Transfer bytes from the file to the ZIP file
        in = ((VFSLeaf)vfsItem).getInputStream();
        if (in != nullFileUtils.copy(in, out);
        // Complete the entry
        out.closeEntry();
      }
    } catch (IOException ioe) {
      return false;
    } finally {
      if (in != null) FileUtils.closeSafely(in);
    }
    return success;
  } // addToZip


  /**
   * Zip all files under a certain root directory.
   *
   * @param rootFile
   * @param targetZipFile
   * @return true = success, false = exception/error
   */
  public static boolean zipAll(File rootFile, File targetZipFile) {
    Set<String> fileSet = new HashSet<String>();
    String[] files = rootFile.list();
    for (int i = 0; i < files.length; i++) {
      fileSet.add(files[i]);
    }   
    return zip(fileSet, rootFile, targetZipFile);
  }
 
}
TOP

Related Classes of org.olat.core.util.ZipUtil

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.