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
031/*-
032 * #%L
033 * org.hl7.fhir.utilities
034 * %%
035 * Copyright (C) 2014 - 2019 Health Level 7
036 * %%
037 * Licensed under the Apache License, Version 2.0 (the "License");
038 * you may not use this file except in compliance with the License.
039 * You may obtain a copy of the License at
040 * 
041 *      http://www.apache.org/licenses/LICENSE-2.0
042 * 
043 * Unless required by applicable law or agreed to in writing, software
044 * distributed under the License is distributed on an "AS IS" BASIS,
045 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
046 * See the License for the specific language governing permissions and
047 * limitations under the License.
048 * #L%
049 */
050
051
052import java.io.BufferedInputStream;
053import java.io.BufferedOutputStream;
054import java.io.ByteArrayInputStream;
055import java.io.File;
056import java.io.FileInputStream;
057import java.io.FileNotFoundException;
058import java.io.FileOutputStream;
059import java.io.IOException;
060import java.io.InputStream;
061import java.util.HashSet;
062import java.util.Set;
063import java.util.zip.CRC32;
064import java.util.zip.Deflater;
065import java.util.zip.ZipEntry;
066import java.util.zip.ZipInputStream;
067import java.util.zip.ZipOutputStream;
068
069public class ZipGenerator {
070
071  private Set<String> names = new HashSet<String>();
072        FileOutputStream dest;
073        ZipOutputStream out;
074
075        public ZipGenerator(String filename) throws FileNotFoundException  {
076                dest = new FileOutputStream(filename);
077                out = new ZipOutputStream(new BufferedOutputStream(dest));
078    out.setLevel(Deflater.BEST_COMPRESSION);
079        }
080
081        public void close() throws IOException  {
082                out.close();
083        }
084
085        static final int BUFFER = 2048;
086
087        public void addFromZip(String zipFilename) throws IOException {
088                byte[] buf = new byte[1024];
089
090                ZipInputStream zin = new ZipInputStream(
091                                new FileInputStream(zipFilename));
092
093                try {
094                        ZipEntry entry = zin.getNextEntry();
095                        while (entry != null) {
096                                String name = entry.getName();
097
098                                names.add(name);
099                                // Add ZIP entry to output stream.
100                                out.putNextEntry(new ZipEntry(name));
101                                // Transfer bytes from the ZIP file to the output file
102                                int len;
103                                while ((len = zin.read(buf)) > 0) {
104                                        out.write(buf, 0, len);
105                                }
106
107                                entry = zin.getNextEntry();
108                        }
109                } finally {
110                        zin.close();
111                }
112        }
113
114        public void addFolder(String actualDir, String statedDir, boolean omitIfExists) throws IOException  {
115                File fd = new CSFile(actualDir);
116                String files[] = fd.list();
117                for (String f : files) {
118                        if (new CSFile(Utilities.path(actualDir, f)).isDirectory())
119                                addFolder(Utilities.path(actualDir, f), Utilities.pathURL(statedDir, f), omitIfExists);
120                        else
121                                addFileName(Utilities.pathURL(statedDir, f), Utilities.path(actualDir, f), omitIfExists);
122                }
123        }
124
125  public void addFolder(String actualDir, String statedDir, boolean omitIfExists, String noExt) throws IOException  {
126    File fd = new CSFile(actualDir);
127    String files[] = fd.list();
128    for (String f : files) {
129      if (new CSFile(Utilities.path(actualDir, f)).isDirectory())
130        addFolder(Utilities.path(actualDir, f), Utilities.pathURL(statedDir, f), omitIfExists, noExt);
131      else if (noExt == null || !f.endsWith(noExt))
132        addFileName(Utilities.pathURL(statedDir, f), Utilities.path(actualDir, f), omitIfExists);
133    }
134  }
135
136        public void addFiles(String actualDir, String statedDir, String ext, String noExt) throws FileNotFoundException, IOException {
137                byte data[] = new byte[BUFFER];
138                statedDir = statedDir.replace("\\", "/");
139                File f = new CSFile(actualDir);
140
141                String files[] = f.list();
142                for (int i = 0; i < files.length; i++) {
143                        if ( new CSFile(actualDir + files[i]).isFile() && ((ext == null || files[i].endsWith(ext)) && (noExt == null || !files[i].endsWith(noExt)))) {
144                                FileInputStream fi = new FileInputStream(actualDir + files[i]);
145                                BufferedInputStream origin = new BufferedInputStream(fi, BUFFER);
146                                ZipEntry entry = new ZipEntry(statedDir + files[i]);
147                                names.add(statedDir + files[i]);
148                                out.putNextEntry(entry);
149                                int count;
150                                while ((count = origin.read(data, 0, BUFFER)) != -1) {
151                                        out.write(data, 0, count);
152                                }
153                                origin.close();
154                        }
155                }
156        }
157
158  public void addFilesFiltered(String actualDir, String statedDir, String ext, String[] noExt) throws FileNotFoundException, IOException {
159    byte data[] = new byte[BUFFER];
160    statedDir = statedDir.replace("\\", "/");
161    File f = new CSFile(actualDir);
162
163    String files[] = f.list();
164    for (int i = 0; i < files.length; i++) {
165      if ( new CSFile(actualDir + files[i]).isFile() && ((ext == null || files[i].endsWith(ext)))) {
166        boolean ok = true;
167        for (String n : noExt) {
168          ok = ok && !files[i].endsWith(n);
169        }
170        if (ok) {
171          FileInputStream fi = new FileInputStream(actualDir + files[i]);
172          BufferedInputStream origin = new BufferedInputStream(fi, BUFFER);
173          ZipEntry entry = new ZipEntry(statedDir + files[i]);
174          names.add(statedDir + files[i]);
175          out.putNextEntry(entry);
176          int count;
177          while ((count = origin.read(data, 0, BUFFER)) != -1) {
178            out.write(data, 0, count);
179          }
180          origin.close();
181        }
182      }
183    }
184  }
185
186        public void addFileSource(String path, String cnt, boolean omitIfExists) throws IOException  {
187                File tmp = Utilities.createTempFile("tmp", ".tmp");
188                TextFile.stringToFile(cnt, tmp.getAbsolutePath());
189                addFileName(path, tmp.getAbsolutePath(), omitIfExists);
190                tmp.delete();
191        }
192
193        public void addFileName(String statedPath, String actualPath, boolean omitIfExists) throws IOException  {
194          if (!omitIfExists || !names.contains(statedPath)) {
195            byte data[] = new byte[BUFFER];
196            FileInputStream fi = new FileInputStream(actualPath);
197            BufferedInputStream origin = new BufferedInputStream(fi, BUFFER);
198            ZipEntry entry = new ZipEntry(statedPath);
199            names.add(statedPath);
200            out.putNextEntry(entry);
201            int count;
202            while ((count = origin.read(data, 0, BUFFER)) != -1) {
203              out.write(data, 0, count);
204            }
205            origin.close();
206          }
207        }
208
209  public void addBytes(String statedPath, byte[] content, boolean omitIfExists) throws IOException  {
210    if (!omitIfExists || !names.contains(statedPath)) {
211      byte data[] = new byte[BUFFER];
212      InputStream fi = new ByteArrayInputStream(content);
213      BufferedInputStream origin = new BufferedInputStream(fi, BUFFER);
214      ZipEntry entry = new ZipEntry(statedPath);
215      names.add(statedPath);
216      out.putNextEntry(entry);
217      int count;
218      while ((count = origin.read(data, 0, BUFFER)) != -1) {
219        out.write(data, 0, count);
220      }
221      origin.close();
222    }
223  }
224
225  public void addMimeTypeFile(String statedPath, String actualPath) throws IOException  {
226  //  byte data[] = new byte[BUFFER];
227    CRC32 crc = new CRC32();
228    
229  //  FileInputStream fi = new FileInputStream(actualPath);
230  //  BufferedInputStream origin = new BufferedInputStream(fi, BUFFER);
231    out.setLevel(0);
232    ZipEntry entry = new ZipEntry(statedPath);
233    entry.setExtra(null);
234    names.add(statedPath);
235    String contents = "application/epub+zip";
236    crc.update(contents.getBytes());
237    entry.setCompressedSize(contents.length());
238    entry.setSize(contents.length());
239    entry.setCrc(crc.getValue());
240    entry.setMethod(ZipEntry.STORED);
241    out.putNextEntry(entry);
242 //   int count;
243//    while ((count = origin.read(data, 0, BUFFER)) != -1) {
244//      out.write(data, 0, count);
245//    }
246  //  origin.close();
247    out.write(contents.getBytes(),0,contents.length());
248    out.setLevel(Deflater.BEST_COMPRESSION);
249  }
250
251  public void addStream(String statedPath, InputStream fi, boolean omitIfExists) throws IOException  {
252    if (!omitIfExists || !names.contains(statedPath)) {
253      byte data[] = new byte[BUFFER];
254      BufferedInputStream origin = new BufferedInputStream(fi, BUFFER);
255      ZipEntry entry = new ZipEntry(statedPath);
256      names.add(statedPath);
257      out.putNextEntry(entry);
258      int count;
259      while ((count = origin.read(data, 0, BUFFER)) != -1) {
260        out.write(data, 0, count);
261      }
262      origin.close();
263    }
264  }
265
266}