1   /*
2    * Logback: the reliable, generic, fast and flexible logging framework.
3    * Copyright (C) 1999-2025, QOS.ch. All rights reserved.
4    *
5    * This program and the accompanying materials are dual-licensed under
6    * either the terms of the Eclipse Public License v1.0 as published by
7    * the Eclipse Foundation
8    *
9    *   or (per the licensee's choosing)
10   *
11   * under the terms of the GNU Lesser General Public License version 2.1
12   * as published by the Free Software Foundation.
13   */
14  
15  package ch.qos.logback.core.rolling.helper;
16  
17  import ch.qos.logback.core.status.ErrorStatus;
18  import ch.qos.logback.core.status.WarnStatus;
19  import java.io.BufferedOutputStream;
20  import java.io.File;
21  import java.io.FileInputStream;
22  import java.io.FileOutputStream;
23  import java.util.zip.ZipEntry;
24  import java.util.zip.ZipOutputStream;
25  
26  /**
27   * Compresses files using JDK's Zip compression algorithm.
28   *
29   * @author Ceki Gülcü
30   * @since 1.5.18
31   */
32  public class ZipCompressionStrategy extends CompressionStrategyBase {
33  
34      @Override
35      public void compress(String originalFileName, String compressedFileName, String innerEntryName) {
36  
37          File file2zip = new File(originalFileName);
38  
39          if (!file2zip.exists()) {
40              addStatus(new WarnStatus("The file to compress named [" + originalFileName + "] does not exist.", this));
41  
42              return;
43          }
44  
45          if (innerEntryName == null) {
46              addStatus(new WarnStatus("The innerEntryName parameter cannot be null", this));
47              return;
48          }
49  
50          if (!compressedFileName.endsWith(".zip")) {
51              compressedFileName = compressedFileName + ".zip";
52          }
53  
54          File zippedFile = new File(compressedFileName);
55  
56          if (zippedFile.exists()) {
57              addStatus(new WarnStatus("The target compressed file named [" + compressedFileName + "] exist already.", this));
58  
59              return;
60          }
61  
62          addInfo("ZIP compressing [" + file2zip + "] as [" + zippedFile + "]");
63          createMissingTargetDirsIfNecessary(zippedFile);
64  
65          try (FileInputStream fis = new FileInputStream(originalFileName);
66               ZipOutputStream zos = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(compressedFileName), BUFFER_SIZE))) {
67  
68              ZipEntry zipEntry = computeZipEntry(innerEntryName);
69              zos.putNextEntry(zipEntry);
70  
71              byte[] inbuf = new byte[BUFFER_SIZE];
72              int n;
73  
74              while ((n = fis.read(inbuf)) != -1) {
75                  zos.write(inbuf, 0, n);
76              }
77  
78              addInfo("Done ZIP compressing [" + file2zip + "] as [" + zippedFile + "]");
79          } catch (Exception e) {
80              addStatus(new ErrorStatus("Error occurred while compressing [" + originalFileName + "] into [" + compressedFileName + "].", this, e));
81          }
82          if (!file2zip.delete()) {
83              addStatus(new WarnStatus("Could not delete [" + originalFileName + "].", this));
84          }
85      }
86  
87      // http://jira.qos.ch/browse/LBCORE-98
88      // The name of the compressed file as nested within the zip archive
89      //
90      // Case 1: RawFile = null, Pattern = foo-%d.zip
91      // nestedFilename = foo-${current-date}
92      //
93      // Case 2: RawFile = hello.txt, Pattern = = foo-%d.zip
94      // nestedFilename = foo-${current-date}
95      //
96      // in both cases, the strategy consisting of removing the compression
97      // suffix of zip file works reasonably well. The alternative strategy
98      // whereby the nested file name was based on the value of the raw file name
99      // (applicable to case 2 only) has the disadvantage of the nested files
100     // all having the same name, which could make it harder for the user
101     // to unzip the file without collisions
102     //ZipEntry computeZipEntry(File zippedFile) {
103     //    return computeZipEntry(zippedFile.getName());
104     //}
105 
106     ZipEntry computeZipEntry(String filename) {
107         String nameOfFileNestedWithinArchive = Compressor.computeFileNameStrWithoutCompSuffix(filename, CompressionMode.ZIP);
108         return new ZipEntry(nameOfFileNestedWithinArchive);
109     }
110 }