/******************************************************************************* * Copyright (c) 2000, 2006 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are 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: * IBM Corporation - initial API and implementation * Red Hat, Inc - Was TarFileStructureProvider, performed changes from * IImportStructureProvider to ILeveledImportStructureProvider *******************************************************************************/ package org.maziarz.yiiclipse.datatransfer; import java.io.File; 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 org.eclipse.ui.wizards.datatransfer.IImportStructureProvider; import org.eclipse.core.resources.ResourceAttributes; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.Path; /** * This class provides information regarding the context structure and content of specified tar file entry objects. */ public class TarHandler implements IImportStructureProvider{ private TarFile tarFile; private TarEntry root = new TarEntry("/");//$NON-NLS-1$ private Map<TarEntry, List<TarEntry>> children; private Map<IPath, TarEntry> directoryEntryCache = new HashMap<IPath, TarEntry>(); private int stripLevel; /** * Creates a <code>TarFileStructureProvider</code>, which will operate on the passed tar file. * * @param sourceFile * the source TarFile */ public TarHandler(TarFile sourceFile) { super(); tarFile = sourceFile; root.setFileType(TarEntry.DIRECTORY); } /** * Creates a new container tar 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 TarEntry createContainer(IPath pathname) { TarEntry existingEntry = (TarEntry) directoryEntryCache.get(pathname); if (existingEntry != null) { return existingEntry; } TarEntry parent; if (pathname.segmentCount() == 1) { parent = root; } else { parent = createContainer(pathname.removeLastSegments(1)); } TarEntry newEntry = new TarEntry(pathname.toString()); newEntry.setFileType(TarEntry.DIRECTORY); directoryEntryCache.put(pathname, newEntry); List<TarEntry> childList = new ArrayList<TarEntry>(); children.put(newEntry, childList); List<TarEntry> parentChildList = children.get(parent); parentChildList.add(newEntry); return newEntry; } /** * Creates a new tar file entry with the specified name. */ protected void createFile(TarEntry entry) { IPath pathname = new Path(entry.getName()); TarEntry parent; if (pathname.segmentCount() == 1) { parent = root; } else { parent = directoryEntryCache.get(pathname.removeLastSegments(1)); } List<TarEntry> childList = children.get(parent); childList.add(entry); } public List<TarEntry> getChildren(TarEntry entry) { if (children == null) { initialize(); } return children.get(entry); } public InputStream getContents(TarEntry element) { try { return tarFile.getInputStream(element); } catch (TarException e) { throw new DataTransferException(e.getLocalizedMessage(), e); // YiiclipseBundle.logError(e.getLocalizedMessage(), e); } catch (IOException e) { throw new DataTransferException(e.getLocalizedMessage(), e); } } /** * Returns the resource attributes for this file. * * @param element * @return the attributes of the file */ public ResourceAttributes getResourceAttributes(TarEntry entry) { ResourceAttributes attributes = new ResourceAttributes(); attributes.setExecutable((entry.getMode() & 0100) != 0); attributes.setReadOnly((entry.getMode() & 0200) == 0); return attributes; } public String getFullPath(TarEntry entry) { return stripPath(entry.getName()); } public String getLabel(TarEntry entry) { if (entry.equals(root)) { return entry.getName(); } return stripPath(new Path(entry.getName()).lastSegment()); } /** * Returns the entry that this importer uses as the root sentinel. * * @return TarEntry entry */ public TarEntry getRoot() { return root; } /** * Returns the tar file that this provider provides structure for. * * @return TarFile file */ public TarFile getTarFile() { return tarFile; } public boolean closeArchive() { try { if (getTarFile() != null) { getTarFile().close(); } } catch (IOException e) { // ignore } return true; } /** * Initializes this object's children table based on the contents of the specified source file. */ protected void initialize() { children = new HashMap<TarEntry, List<TarEntry>>(1000); children.put(root, new ArrayList<TarEntry>()); Enumeration<TarEntry> entries = tarFile.entries(); while (entries.hasMoreElements()) { TarEntry entry = (TarEntry) entries.nextElement(); IPath path = new Path(entry.getName()).addTrailingSeparator(); if (entry.getFileType() == TarEntry.DIRECTORY) { 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); } } } public boolean isFolder(TarEntry entry) { return (entry.getFileType() == TarEntry.DIRECTORY); } /* * 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 separator we must strip to the next separator as well if (firstSep == 0) { path = path.substring(1); firstSep = path.indexOf('/'); } // No separator was present so we're in a higher directory right now if (firstSep == -1) { return pathOrig; } path = path.substring(firstSep); } return path; } public void setStrip(int level) { stripLevel = level; } public int getStrip() { return stripLevel; } public TarEntry getEntry(String name) throws TarException{ if (children == null) { initialize(); } TarEntry entry = directoryEntryCache.get(new Path(name)); if (entry != null) { return entry; } throw new TarException("Entry not found: "+name); } private void extractFile(TarEntry entry, File destFolder) throws IOException{ if (!destFolder.exists()){ throw new RuntimeException("Folder does not exists: "+destFolder); } String fileObjectPath = this.getFullPath(entry); InputStream contentStream = this.getContents(entry); String filename = new Path(fileObjectPath).lastSegment(); File destFile = (new Path(destFolder.getAbsolutePath())).append(filename).toFile(); FileUtils.copyInputStreamToFile(contentStream, destFile); } public void extractRecursively(TarEntry entry, File destFolder) throws IOException{ if (!this.isFolder(entry)){ extractFile(entry, destFolder); return; } if (!destFolder.exists()){ throw new RuntimeException("Folder does not exit: "+destFolder); } Path path = new Path(entry.getName()); String lastSegment = path.lastSegment(); path = (Path) new Path(destFolder.getAbsolutePath()).append(lastSegment); path.toFile().mkdir(); for(TarEntry child :this.getChildren(entry)){ extractRecursively(child, path.toFile()); } } @Override public List getChildren(Object element) { return getChildren((TarEntry)element); } @Override public InputStream getContents(Object element) { return getContents((TarEntry)element); } @Override public String getFullPath(Object element) { return getFullPath((TarEntry)element); } @Override public String getLabel(Object element) { return getLabel((TarEntry)element); } @Override public boolean isFolder(Object element) { return isFolder((TarEntry)element); } }