View Javadoc
1   package fr.ifremer.quadrige3.core.dao.technical;
2   
3   /*-
4    * #%L
5    * Quadrige3 Core :: Quadrige3 Core Shared
6    * $Id:$
7    * $HeadURL:$
8    * %%
9    * Copyright (C) 2017 Ifremer
10   * %%
11   * This program is free software: you can redistribute it and/or modify
12   * it under the terms of the GNU Affero General Public License as published by
13   * the Free Software Foundation, either version 3 of the License, or
14   * (at your option) any later version.
15   *
16   * This program is distributed in the hope that it will be useful,
17   * but WITHOUT ANY WARRANTY; without even the implied warranty of
18   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19   * GNU General Public License for more details.
20   *
21   * You should have received a copy of the GNU Affero General Public License
22   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
23   * #L%
24   */
25  
26  import com.google.common.collect.ImmutableList;
27  import fr.ifremer.quadrige3.core.ProgressionCoreModel;
28  import org.apache.commons.io.FileUtils;
29  import org.apache.commons.io.FilenameUtils;
30  import org.apache.commons.lang3.StringUtils;
31  
32  import java.io.File;
33  import java.io.IOException;
34  import java.io.InputStream;
35  import java.io.OutputStream;
36  import java.nio.charset.Charset;
37  import java.nio.file.Path;
38  import java.util.*;
39  import java.util.zip.ZipEntry;
40  import java.util.zip.ZipFile;
41  import java.util.zip.ZipOutputStream;
42  
43  /**
44   * <p>ZipUtils class.</p>
45   */
46  public class ZipUtils {
47  
48      public static List<String> COMPRESSED_EXTENSION_LIST;
49  
50      static {
51          COMPRESSED_EXTENSION_LIST = new ArrayList<>();
52          COMPRESSED_EXTENSION_LIST.addAll(Images.AVAILABLE_EXTENSION_LIST);
53          // Add more extensions here if needed
54          COMPRESSED_EXTENSION_LIST.addAll(ImmutableList.of("zip", "7z", "rar"));
55      }
56  
57      /**
58       * <p>Constructor for ZipUtils.</p>
59       */
60      protected ZipUtils() {
61          // helper class
62      }
63  
64      public static boolean isZipFile(File file) {
65          boolean result = false;
66          try {
67              ZipFile zipFile = new ZipFile(file);
68              zipFile.close();
69              result = true;
70          } catch (IOException ignored) {
71          }
72          return result;
73      }
74  
75      public static ZipFile open(Path file) throws IOException {
76          if (!isZipFile(file.toFile()))
77              throw new IOException("this file is not a zip archive : " + file);
78  
79          // Open the zip file with default encoding IBM437 (Mantis #45096)
80          return new ZipFile(file.toFile(), Charset.forName("IBM437")); // ou 850
81      }
82  
83      public static List<? extends ZipEntry> getEntries(Path file) throws IOException {
84          try (ZipFile zipFile = open(file)) {
85              return Collections.list(zipFile.entries());
86          }
87      }
88  
89      public static void compressFilesInPath(Path source, Path target, boolean deleteAfterCompress) throws IOException {
90          compressFilesInPath(source, target, null, deleteAfterCompress, false);
91      }
92  
93      public static void compressFilesInPath(Path source, Path target, ProgressionCoreModel progressionModel, boolean deleteAfterCompress) throws IOException {
94          compressFilesInPath(source, target, progressionModel, deleteAfterCompress, false);
95      }
96  
97      public static void compressFilesInPath(Path source, Path target, ProgressionCoreModel progressionModel, boolean deleteAfterCompress, boolean includeRoot) throws IOException {
98          Assert.notNull(source);
99          Assert.isTrue(java.nio.file.Files.isDirectory(source), "source must be a directory");
100         Assert.notNull(target);
101         java.nio.file.Files.createDirectories(target.getParent());
102 
103         if (progressionModel != null) {
104             progressionModel.adaptTotal(Files.getSize(source));
105         }
106 
107         try (ZipOutputStream outputStream = new ZipOutputStream(java.nio.file.Files.newOutputStream(target))) {
108             // set low compression level
109             outputStream.setLevel(1);
110             compressDirectory(includeRoot ? source.getParent() : source, source, target, outputStream, progressionModel, deleteAfterCompress);
111             outputStream.finish();
112         }
113     }
114 
115     public static void uncompressFileToPath(Path compressedFile, Path destDir, boolean deleteAfterUncompress) throws IOException {
116         uncompressFileToPath(compressedFile, destDir, null, deleteAfterUncompress);
117     }
118 
119     public static void uncompressFileToPath(Path compressedFile, Path destDir, ProgressionCoreModel progressionModel, boolean deleteAfterUncompress) throws IOException {
120         uncompressFileToPath(compressedFile, destDir, null, progressionModel, deleteAfterUncompress);
121     }
122 
123     public static void uncompressFileToPath(Path compressedFile, Path destDir, String rootDirName, ProgressionCoreModel progressionModel, boolean deleteAfterUncompress) throws IOException {
124         Assert.notNull(compressedFile, "compressed file is null");
125         Assert.notNull(destDir, "destination directory is null");
126         Assert.isTrue(java.nio.file.Files.exists(compressedFile), "compressed file must exists");
127         Assert.isTrue(java.nio.file.Files.isRegularFile(compressedFile), "compressed file must be a regular file");
128         if (progressionModel != null) {
129             progressionModel.adaptTotal(Files.getSize(compressedFile));
130         }
131         rootDirName = StringUtils.appendIfMissing(rootDirName, "/");
132 
133         try (ZipFile zipFile = open(compressedFile)) {
134             Enumeration<? extends ZipEntry> entries = zipFile.entries();
135             while (entries.hasMoreElements()) {
136                 ZipEntry zipEntry = entries.nextElement();
137                 if (rootDirName != null && !zipEntry.getName().startsWith(rootDirName))
138                     continue;
139                 Path destFile = destDir.resolve(StringUtils.removeStartIgnoreCase(zipEntry.getName(), rootDirName));
140                 if (zipEntry.isDirectory()) {
141                     java.nio.file.Files.createDirectories(destFile);
142                 } else {
143                     java.nio.file.Files.createDirectories(destFile.getParent());
144                     try (InputStream in = zipFile.getInputStream(zipEntry);
145                          OutputStream out = java.nio.file.Files.newOutputStream(destFile)) {
146                         Files.copyStream(in, out, progressionModel);
147                     }
148                 }
149             }
150         }
151         if (deleteAfterUncompress) {
152             java.nio.file.Files.delete(compressedFile);
153         }
154     }
155 
156     /* -- Internal methods -- */
157 
158     private static void compressDirectory(Path rootSource, Path source, Path target,
159                                           ZipOutputStream zipOutputStream,
160                                           ProgressionCoreModel progressionModel,
161                                           boolean deleteAfterCompress) throws IOException {
162 
163         List<Path> sourceContent = Files.getDirectoryContent(source);
164         for (Path path : Objects.requireNonNull(sourceContent)) {
165             if (path.equals(target)) {
166                 continue;
167             }
168             if (java.nio.file.Files.isDirectory(path)) {
169                 String zipEntryName = toZipEntryName(rootSource, path);
170                 zipOutputStream.putNextEntry(new ZipEntry(zipEntryName));
171                 compressDirectory(rootSource, path, target, zipOutputStream, progressionModel, deleteAfterCompress);
172                 zipOutputStream.closeEntry();
173                 if (deleteAfterCompress) {
174                     java.nio.file.Files.delete(path);
175                 }
176                 continue;
177             }
178             try (InputStream in = java.nio.file.Files.newInputStream(path)) {
179                 String zipEntryName = toZipEntryName(rootSource, path);
180                 ZipEntry zipEntry = new ZipEntry(zipEntryName);
181                 if (FilenameUtils.isExtension(path.getFileName().toString(), COMPRESSED_EXTENSION_LIST)) {
182                     zipEntry.setMethod(ZipEntry.STORED);
183                     zipEntry.setSize(java.nio.file.Files.size(path));
184                     zipEntry.setCrc(FileUtils.checksumCRC32(path.toFile()));
185                 }
186                 zipOutputStream.putNextEntry(zipEntry);
187                 Files.copyStream(in, zipOutputStream, progressionModel);
188                 zipOutputStream.closeEntry();
189             }
190             if (deleteAfterCompress) {
191                 java.nio.file.Files.delete(path);
192             }
193         }
194     }
195 
196     private static String toZipEntryName(Path root, Path file) {
197         String result = file.toString();
198         if (root != null) {
199             String rootPath = root.toString();
200             if (result.startsWith(rootPath)) {
201                 result = result.substring(rootPath.length());
202             }
203         }
204 
205         result = result.replace('\\', '/');
206         if (java.nio.file.Files.isDirectory(file)) {
207             result = result + '/';
208         }
209 
210         while (result.startsWith("/")) {
211             result = result.substring(1);
212         }
213 
214         return result;
215     }
216 
217 }