1 /*
2  * unzip.java
3  *
4  * Copyright (C) 2010 Mark Evenson
5  * $Id$
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
20  *
21  * As a special exception, the copyright holders of this library give you
22  * permission to link this library with independent modules to produce an
23  * executable, regardless of the license terms of these independent
24  * modules, and to copy and distribute the resulting executable under
25  * terms of your choice, provided that you also meet, for each linked
26  * independent module, the terms and conditions of the license of that
27  * module.  An independent module is a module which is not derived from
28  * or based on this library.  If you modify this library, you may extend
29  * this exception to your version of the library, but you are not
30  * obligated to do so.  If you do not wish to do so, delete this
31  * exception statement from your version.
32  */
33 
34 package org.armedbear.lisp;
35 
36 import static org.armedbear.lisp.Lisp.*;
37 import java.io.File;
38 import java.io.InputStream;
39 import java.io.FileOutputStream;
40 import java.io.IOException;
41 import java.util.Enumeration;
42 import java.util.zip.ZipEntry;
43 import java.util.zip.ZipFile;
44 
45 @DocString(name="unzip",
46            args="pathname &optional directory => unzipped_pathnames",
47            doc="Unpack zip archive at PATHNAME returning a list of extracted pathnames.\nIf the optional DIRECTORY is specified, root the abstraction in that directory, otherwise use the current value of *DEFAULT-PATHNAME-DEFAULTS*.")
48 public final class unzip
49   extends Primitive
50 {
unzip()51     public unzip() {
52         super("unzip", PACKAGE_SYS, true,
53               "pathname &optional directory => unzipped_pathnames");
54     }
55 
56     @Override
execute(LispObject first)57     public LispObject execute(LispObject first) {
58         Pathname zipFile = coerceToPathname(first);
59         Pathname directory = coerceToPathname(Symbol.DEFAULT_PATHNAME_DEFAULTS.symbolValue());
60         return unzipToDirectory(zipFile, directory);
61     }
62 
63     @Override
execute(LispObject first, LispObject second)64     public LispObject execute(LispObject first, LispObject second) {
65         Pathname zipFile = coerceToPathname(first);
66         Pathname directory = coerceToPathname(second);
67         directory.setName(NIL);
68         directory.setType(NIL);
69         return unzipToDirectory(zipFile, directory);
70     }
71 
unzipToDirectory(Pathname zipPath, Pathname dirPath)72     private LispObject unzipToDirectory(Pathname zipPath, Pathname dirPath) {
73         if (!zipPath.isAbsolute()) {
74             zipPath = Pathname.mergePathnames(zipPath,
75                                               coerceToPathname(Symbol.DEFAULT_PATHNAME_DEFAULTS.symbolValue()));
76         }
77         LispObject o = Symbol.PROBE_FILE.execute(zipPath);
78         if (!(o instanceof Pathname)) {
79             return error(new FileError("No file found: " + zipPath, zipPath));
80         }
81         String zip = ((Pathname)o).getNamestring();
82         if (zip == null) {
83             return error(new FileError("Pathname has no namestring: " + zip, zipPath));
84         }
85         String dir = dirPath.getNamestring();
86         if (dir == null) {
87             return error(new FileError("Could not parse diretory: " + dirPath, dirPath));
88         }
89         LispObject result = NIL;
90         try {
91             ZipFile zipfile = new ZipFile(zip);
92 
93             byte[] buffer = new byte[4096];
94             for (Enumeration<? extends ZipEntry> entries =  zipfile.entries();entries.hasMoreElements();) {
95                 ZipEntry entry = entries.nextElement();
96                 String name = entry.getName();
97                 String filename = dir + name;
98                 File file = new File(filename);
99                 if (entry.isDirectory()) {
100                     file.mkdirs();
101                     continue;
102                 }
103                 FileOutputStream out = new FileOutputStream(file);
104                 InputStream in = zipfile.getInputStream(entry);
105                 int n;
106                 while ((n = in.read(buffer)) > 0) {
107                     out.write(buffer, 0, n);
108                 }
109                 out.close();
110                 in.close();
111                 result = result.push(Pathname.create(filename));
112             }
113         } catch (IOException e) {
114             return error(new FileError("Failed to unzip "
115                                        + "'" + zipPath + "'"
116                                        + " into " + "'" + dirPath + "'"
117                                        + ": " + e, zipPath));
118         }
119         return result;
120     }
121 
122     private static final Primitive unzip = new unzip();
123 }
124