001/*
002 * Copyright (c) 2006-2014 Nuxeo SA (http://nuxeo.com/) and others.
003 *
004 * All rights reserved. This program and the accompanying materials
005 * are made available under the terms of the Eclipse Public License v1.0
006 * which accompanies this distribution, and is available at
007 * http://www.eclipse.org/legal/epl-v10.html
008 *
009 * Contributors:
010 *     bstefanescu
011 *
012 */
013
014package org.nuxeo.ecm.core.io.impl.plugins;
015
016import java.io.File;
017import java.io.FileInputStream;
018import java.io.FileOutputStream;
019import java.io.IOException;
020import java.io.InputStream;
021import java.util.zip.ZipEntry;
022import java.util.zip.ZipInputStream;
023
024import org.nuxeo.common.utils.FileUtils;
025import org.nuxeo.ecm.core.io.DocumentReader;
026import org.nuxeo.ecm.core.io.ExportedDocument;
027import org.nuxeo.ecm.core.io.impl.AbstractDocumentReader;
028import org.nuxeo.runtime.api.Framework;
029
030/**
031 * A reader to read zip files. If the zip file is recognized as a nuxeo archive then the {@link NuxeoArchiveReader} will
032 * be used to read the zip otherwise the zip will be deflated to a temporary directory and then
033 * {@link XMLDirectoryReader} will be used to read the zip.
034 *
035 * @author <a href="mailto:bs@nuxeo.com">Bogdan Stefanescu</a>
036 */
037public class ZipReader extends AbstractDocumentReader {
038
039    private final ZipInputStream in;
040
041    private DocumentReader delegate;
042
043    public ZipReader(File file) throws IOException {
044        this(new FileInputStream(file));
045    }
046
047    public ZipReader(InputStream in) throws IOException {
048        this.in = new ZipInputStream(in);
049        initialize();
050    }
051
052    private void initialize() throws IOException {
053        ZipEntry entry = in.getNextEntry();
054        if (NuxeoArchiveReader.isMarkerEntry(entry)) {
055            delegate = new NuxeoArchiveReader(in, false);
056        } else { // not a nuxeo archive file
057            File root = null;
058            try {
059                root = File.createTempFile("nuxeo-import-", ".unzip");
060                Framework.trackFile(root, root);
061                root.delete();
062                root.mkdirs();
063                extract(in, entry, root);
064                while ((entry = in.getNextEntry()) != null) {
065                    extract(in, entry, root);
066                }
067            } finally {
068                in.close();
069            }
070            delegate = new XMLDirectoryReader(root);
071        }
072    }
073
074    @Override
075    public ExportedDocument read() throws IOException {
076        return delegate.read();
077    }
078
079    @Override
080    public void close() {
081        delegate.close();
082    }
083
084    private static void extract(ZipInputStream in, ZipEntry entry, File root) throws IOException {
085        if (entry.getName().contains("..")) {
086            return;
087        }
088
089        if (!entry.isDirectory()) { // create the directtory
090            File file = new File(root, entry.getName());
091            if (!file.getParentFile().mkdirs()) { // make sure all parent
092                                                  // directory exists
093                throw new IOException("Failed to create directory: " + file.getParent());
094            }
095            // write the file content
096            FileOutputStream out = new FileOutputStream(file);
097            try {
098                FileUtils.copy(in, out);
099            } finally {
100                out.close();
101            }
102        }
103    }
104
105}