001/*
002Copyright (c) 2011+, HL7, Inc
003All rights reserved.
004
005Redistribution and use in source and binary forms, with or without modification, 
006are permitted provided that the following conditions are met:
007
008 * Redistributions of source code must retain the above copyright notice, this 
009   list of conditions and the following disclaimer.
010 * Redistributions in binary form must reproduce the above copyright notice, 
011   this list of conditions and the following disclaimer in the documentation 
012   and/or other materials provided with the distribution.
013 * Neither the name of HL7 nor the names of its contributors may be used to 
014   endorse or promote products derived from this software without specific 
015   prior written permission.
016
017THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 
018ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 
019WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
020IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 
021INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 
022NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
023PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
024WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
025ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
026POSSIBILITY OF SUCH DAMAGE.
027
028 */
029package org.hl7.fhir.utilities;
030
031import java.io.BufferedInputStream;
032import java.io.BufferedOutputStream;
033import java.io.ByteArrayInputStream;
034import java.io.File;
035import java.io.FileInputStream;
036import java.io.FileNotFoundException;
037import java.io.FileOutputStream;
038import java.io.IOException;
039import java.io.InputStream;
040import java.util.HashSet;
041import java.util.Set;
042import java.util.zip.CRC32;
043import java.util.zip.Deflater;
044import java.util.zip.ZipEntry;
045import java.util.zip.ZipInputStream;
046import java.util.zip.ZipOutputStream;
047
048public class ZipGenerator {
049
050  private Set<String> names = new HashSet<String>();
051        FileOutputStream dest;
052        ZipOutputStream out;
053
054        public ZipGenerator(String filename) throws FileNotFoundException  {
055                dest = new FileOutputStream(filename);
056                out = new ZipOutputStream(new BufferedOutputStream(dest));
057    out.setLevel(Deflater.BEST_COMPRESSION);
058        }
059
060        public void close() throws IOException  {
061                out.close();
062        }
063
064        static final int BUFFER = 2048;
065
066        public void addFromZip(String zipFilename) throws IOException {
067                byte[] buf = new byte[1024];
068
069                ZipInputStream zin = new ZipInputStream(
070                                new FileInputStream(zipFilename));
071
072                try {
073                        ZipEntry entry = zin.getNextEntry();
074                        while (entry != null) {
075                                String name = entry.getName();
076
077                                names.add(name);
078                                // Add ZIP entry to output stream.
079                                out.putNextEntry(new ZipEntry(name));
080                                // Transfer bytes from the ZIP file to the output file
081                                int len;
082                                while ((len = zin.read(buf)) > 0) {
083                                        out.write(buf, 0, len);
084                                }
085
086                                entry = zin.getNextEntry();
087                        }
088                } finally {
089                        zin.close();
090                }
091        }
092
093        public void addFolder(String actualDir, String statedDir, boolean omitIfExists) throws IOException  {
094                File fd = new CSFile(actualDir);
095                String files[] = fd.list();
096                for (String f : files) {
097                        if (new CSFile(Utilities.path(actualDir, f)).isDirectory())
098                                addFolder(Utilities.path(actualDir, f), Utilities.pathURL(statedDir, f), omitIfExists);
099                        else
100                                addFileName(Utilities.pathURL(statedDir, f), Utilities.path(actualDir, f), omitIfExists);
101                }
102        }
103
104  public void addFolder(String actualDir, String statedDir, boolean omitIfExists, String noExt) throws IOException  {
105    File fd = new CSFile(actualDir);
106    String files[] = fd.list();
107    for (String f : files) {
108      if (new CSFile(Utilities.path(actualDir, f)).isDirectory())
109        addFolder(Utilities.path(actualDir, f), Utilities.pathURL(statedDir, f), omitIfExists, noExt);
110      else if (noExt == null || !f.endsWith(noExt))
111        addFileName(Utilities.pathURL(statedDir, f), Utilities.path(actualDir, f), omitIfExists);
112    }
113  }
114
115        public void addFiles(String actualDir, String statedDir, String ext, String noExt) throws FileNotFoundException, IOException {
116                byte data[] = new byte[BUFFER];
117                statedDir = statedDir.replace("\\", "/");
118                File f = new CSFile(actualDir);
119
120                String files[] = f.list();
121                for (int i = 0; i < files.length; i++) {
122                        if ( new CSFile(actualDir + files[i]).isFile() && ((ext == null || files[i].endsWith(ext)) && (noExt == null || !files[i].endsWith(noExt)))) {
123                                FileInputStream fi = new FileInputStream(actualDir + files[i]);
124                                BufferedInputStream origin = new BufferedInputStream(fi, BUFFER);
125                                ZipEntry entry = new ZipEntry(statedDir + files[i]);
126                                names.add(statedDir + files[i]);
127                                out.putNextEntry(entry);
128                                int count;
129                                while ((count = origin.read(data, 0, BUFFER)) != -1) {
130                                        out.write(data, 0, count);
131                                }
132                                origin.close();
133                        }
134                }
135        }
136
137  public void addFilesFiltered(String actualDir, String statedDir, String ext, String[] noExt) throws FileNotFoundException, IOException {
138    byte data[] = new byte[BUFFER];
139    statedDir = statedDir.replace("\\", "/");
140    File f = new CSFile(actualDir);
141
142    String files[] = f.list();
143    for (int i = 0; i < files.length; i++) {
144      if ( new CSFile(actualDir + files[i]).isFile() && ((ext == null || files[i].endsWith(ext)))) {
145        boolean ok = true;
146        for (String n : noExt) {
147          ok = ok && !files[i].endsWith(n);
148        }
149        if (ok) {
150          FileInputStream fi = new FileInputStream(actualDir + files[i]);
151          BufferedInputStream origin = new BufferedInputStream(fi, BUFFER);
152          ZipEntry entry = new ZipEntry(statedDir + files[i]);
153          names.add(statedDir + files[i]);
154          out.putNextEntry(entry);
155          int count;
156          while ((count = origin.read(data, 0, BUFFER)) != -1) {
157            out.write(data, 0, count);
158          }
159          origin.close();
160        }
161      }
162    }
163  }
164
165        public void addFileSource(String path, String cnt, boolean omitIfExists) throws IOException  {
166                File tmp = Utilities.createTempFile("tmp", ".tmp");
167                TextFile.stringToFile(cnt, tmp.getAbsolutePath());
168                addFileName(path, tmp.getAbsolutePath(), omitIfExists);
169                tmp.delete();
170        }
171
172        public void addFileName(String statedPath, String actualPath, boolean omitIfExists) throws IOException  {
173          if (!omitIfExists || !names.contains(statedPath)) {
174            byte data[] = new byte[BUFFER];
175            FileInputStream fi = new FileInputStream(actualPath);
176            BufferedInputStream origin = new BufferedInputStream(fi, BUFFER);
177            ZipEntry entry = new ZipEntry(statedPath);
178            names.add(statedPath);
179            out.putNextEntry(entry);
180            int count;
181            while ((count = origin.read(data, 0, BUFFER)) != -1) {
182              out.write(data, 0, count);
183            }
184            origin.close();
185          }
186        }
187
188  public void addBytes(String statedPath, byte[] content, boolean omitIfExists) throws IOException  {
189    if (!omitIfExists || !names.contains(statedPath)) {
190      byte data[] = new byte[BUFFER];
191      InputStream fi = new ByteArrayInputStream(content);
192      BufferedInputStream origin = new BufferedInputStream(fi, BUFFER);
193      ZipEntry entry = new ZipEntry(statedPath);
194      names.add(statedPath);
195      out.putNextEntry(entry);
196      int count;
197      while ((count = origin.read(data, 0, BUFFER)) != -1) {
198        out.write(data, 0, count);
199      }
200      origin.close();
201    }
202  }
203
204  public void addMimeTypeFile(String statedPath, String actualPath) throws IOException  {
205  //  byte data[] = new byte[BUFFER];
206    CRC32 crc = new CRC32();
207    
208  //  FileInputStream fi = new FileInputStream(actualPath);
209  //  BufferedInputStream origin = new BufferedInputStream(fi, BUFFER);
210    out.setLevel(0);
211    ZipEntry entry = new ZipEntry(statedPath);
212    entry.setExtra(null);
213    names.add(statedPath);
214    String contents = "application/epub+zip";
215    crc.update(contents.getBytes());
216    entry.setCompressedSize(contents.length());
217    entry.setSize(contents.length());
218    entry.setCrc(crc.getValue());
219    entry.setMethod(ZipEntry.STORED);
220    out.putNextEntry(entry);
221 //   int count;
222//    while ((count = origin.read(data, 0, BUFFER)) != -1) {
223//      out.write(data, 0, count);
224//    }
225  //  origin.close();
226    out.write(contents.getBytes(),0,contents.length());
227    out.setLevel(Deflater.BEST_COMPRESSION);
228  }
229
230  public void addStream(String statedPath, InputStream fi, boolean omitIfExists) throws IOException  {
231    if (!omitIfExists || !names.contains(statedPath)) {
232      byte data[] = new byte[BUFFER];
233      BufferedInputStream origin = new BufferedInputStream(fi, BUFFER);
234      ZipEntry entry = new ZipEntry(statedPath);
235      names.add(statedPath);
236      out.putNextEntry(entry);
237      int count;
238      while ((count = origin.read(data, 0, BUFFER)) != -1) {
239        out.write(data, 0, count);
240      }
241      origin.close();
242    }
243  }
244
245}