package de.ovgu.cide.samples.utils; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.Enumeration; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.Path; import org.eclipse.ui.wizards.datatransfer.IImportStructureProvider; /** * This class provides information regarding the context structure and content * of specified zip file entry objects. * * @since 3.1 */ public class ZipStructureProvider implements IImportStructureProvider { private ZipFile zipFile; private ZipEntry root = new ZipEntry("/");//$NON-NLS-1$ private Map<ZipEntry, List<ZipEntry>> children; private Map<IPath, ZipEntry> directoryEntryCache = new HashMap<IPath, ZipEntry>(); private int stripLevel; /** * Creates a <code>ZipFileStructureProvider</code>, which will operate on * the passed zip file. * * @param sourceFile * The source file to create the ZipLeveledStructureProvider * around */ public ZipStructureProvider(ZipFile sourceFile) { super(); zipFile = sourceFile; stripLevel = 0; } /** * Creates a new container zip entry with the specified name, if it has * not already been created. If the parent of the given element does not * already exist it will be recursively created as well. * @param pathname The path representing the container * @return The element represented by this pathname (it may have already existed) */ protected ZipEntry createContainer(IPath pathname) { ZipEntry existingEntry = (ZipEntry) directoryEntryCache.get(pathname); if (existingEntry != null) { return existingEntry; } ZipEntry parent; if (pathname.segmentCount() == 1) { parent = root; } else { parent = createContainer(pathname.removeLastSegments(1)); } ZipEntry newEntry = new ZipEntry(pathname.toString()); directoryEntryCache.put(pathname, newEntry); List<ZipEntry> childList = new ArrayList<ZipEntry>(); children.put(newEntry, childList); List<ZipEntry> parentChildList = (List<ZipEntry>)children.get(parent); parentChildList.add(newEntry); return newEntry; } /** * Creates a new file zip entry with the specified name. */ protected void createFile(ZipEntry entry) { IPath pathname = new Path(entry.getName()); ZipEntry parent; if (pathname.segmentCount() == 1) { parent = root; } else { parent = (ZipEntry) directoryEntryCache.get(pathname .removeLastSegments(1)); } List<ZipEntry> childList = (List<ZipEntry>) children.get(parent); childList.add(entry); } /* * (non-Javadoc) Method declared on IImportStructureProvider */ public List<ZipEntry> getChildren(Object element) { if (children == null) { initialize(); } return ((List<ZipEntry>) children.get(element)); } /* * (non-Javadoc) Method declared on IImportStructureProvider */ public InputStream getContents(Object element) { try { return zipFile.getInputStream((ZipEntry) element); } catch (IOException e) { System.err.println(e.getStackTrace()); return null; } } /* * Strip the leading directories from the path */ private String stripPath(String path) { String pathOrig = new String(path); for (int i = 0; i < stripLevel; i++) { int firstSep = path.indexOf('/'); // If the first character was a seperator we must strip to the next // seperator as well if (firstSep == 0) { path = path.substring(1); firstSep = path.indexOf('/'); } // No seperator wasw present so we're in a higher directory right // now if (firstSep == -1) { return pathOrig; } path = path.substring(firstSep); } return path; } /* * (non-Javadoc) Method declared on IImportStructureProvider */ public String getFullPath(Object element) { return stripPath(((ZipEntry) element).getName()); } /* * (non-Javadoc) Method declared on IImportStructureProvider */ public String getLabel(Object element) { if (element.equals(root)) { return ((ZipEntry) element).getName(); } return stripPath(new Path(((ZipEntry) element).getName()).lastSegment()); } /** * Returns the entry that this importer uses as the root sentinel. * * @return java.util.zip.ZipEntry */ public Object getRoot() { return root; } /** * Returns the zip file that this provider provides structure for. * * @return The zip file */ public ZipFile getZipFile() { return zipFile; } /* * (non-Javadoc) * @see org.eclipse.ui.internal.wizards.datatransfer.ILeveledImportStructureProvider#closeArchive() */ public boolean closeArchive(){ try { getZipFile().close(); } catch (IOException e) { System.err.println("Could not Close Archieve: " + e.getStackTrace()); return false; } return true; } /** * Initializes this object's children table based on the contents of the * specified source file. */ protected void initialize() { children = new HashMap<ZipEntry, List<ZipEntry>>(1000); children.put(root, new ArrayList<ZipEntry>()); Enumeration<?> entries = zipFile.entries(); while (entries.hasMoreElements()) { ZipEntry entry = (ZipEntry) entries.nextElement(); IPath path = new Path(entry.getName()).addTrailingSeparator(); if (entry.isDirectory()) { createContainer(path); } else { // Ensure the container structure for all levels above this is initialized // Once we hit a higher-level container that's already added we need go no further int pathSegmentCount = path.segmentCount(); if (pathSegmentCount > 1) { createContainer(path.uptoSegment(pathSegmentCount - 1)); } createFile(entry); } } } /* * (non-Javadoc) Method declared on IImportStructureProvider */ public boolean isFolder(Object element) { return ((ZipEntry) element).isDirectory(); } public void setStrip(int level) { stripLevel = level; } public int getStrip() { return stripLevel; } }