View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   https://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.commons.compress.archivers.zip;
20  
21  /**
22   * Parser/encoder for the "general purpose bit" field in ZIP's local file and central directory headers.
23   *
24   * @since 1.1
25   * @NotThreadSafe
26   */
27  public final class GeneralPurposeBit implements Cloneable {
28  
29      /**
30       * Indicates that the file is encrypted.
31       */
32      private static final int ENCRYPTION_FLAG = 1 << 0;
33  
34      /**
35       * Indicates the size of the sliding dictionary used by the compression method 6 (imploding).
36       * <ul>
37       * <li>0: 4096 bytes</li>
38       * <li>1: 8192 bytes</li>
39       * </ul>
40       */
41      private static final int SLIDING_DICTIONARY_SIZE_FLAG = 1 << 1;
42  
43      /**
44       * Indicates the number of Shannon-Fano trees used by the compression method 6 (imploding).
45       * <ul>
46       * <li>0: 2 trees (lengths, distances)</li>
47       * <li>1: 3 trees (literals, lengths, distances)</li>
48       * </ul>
49       */
50      private static final int NUMBER_OF_SHANNON_FANO_TREES_FLAG = 1 << 2;
51  
52      /**
53       * Indicates that a data descriptor stored after the file contents will hold CRC and size information.
54       */
55      private static final int DATA_DESCRIPTOR_FLAG = 1 << 3;
56  
57      /**
58       * Indicates strong encryption.
59       */
60      private static final int STRONG_ENCRYPTION_FLAG = 1 << 6;
61  
62      /**
63       * Indicates that file names are written in UTF-8.
64       *
65       * <p>
66       * The only reason this is public is that {@link ZipArchiveOutputStream#EFS_FLAG} was public in Apache Commons Compress 1.0 and we needed a substitute for
67       * it.
68       * </p>
69       */
70      public static final int UFT8_NAMES_FLAG = 1 << 11;
71  
72      /**
73       * Parses the supported flags from the given archive data.
74       *
75       * @param data   local file header or a central directory entry.
76       * @param offset offset at which the general purpose bit starts
77       * @return parsed flags
78       */
79      public static GeneralPurposeBit parse(final byte[] data, final int offset) {
80          final int generalPurposeFlag = ZipShort.getValue(data, offset);
81          final GeneralPurposeBit b = new GeneralPurposeBit();
82          b.useDataDescriptor((generalPurposeFlag & DATA_DESCRIPTOR_FLAG) != 0);
83          b.useUTF8ForNames((generalPurposeFlag & UFT8_NAMES_FLAG) != 0);
84          b.useStrongEncryption((generalPurposeFlag & STRONG_ENCRYPTION_FLAG) != 0);
85          b.useEncryption((generalPurposeFlag & ENCRYPTION_FLAG) != 0);
86          b.slidingDictionarySize = (generalPurposeFlag & SLIDING_DICTIONARY_SIZE_FLAG) != 0 ? 8192 : 4096;
87          b.numberOfShannonFanoTrees = (generalPurposeFlag & NUMBER_OF_SHANNON_FANO_TREES_FLAG) != 0 ? 3 : 2;
88          return b;
89      }
90  
91      private boolean languageEncodingFlag;
92      private boolean dataDescriptorFlag;
93      private boolean encryptionFlag;
94      private boolean strongEncryptionFlag;
95      private int slidingDictionarySize;
96  
97      private int numberOfShannonFanoTrees;
98  
99      /**
100      * Constructs a new instance.
101      */
102     public GeneralPurposeBit() {
103     }
104 
105     @Override
106     public Object clone() {
107         try {
108             return super.clone();
109         } catch (final CloneNotSupportedException ex) {
110             // impossible
111             throw new UnsupportedOperationException("GeneralPurposeBit is not Cloneable?", ex); // NOSONAR
112         }
113     }
114 
115     /**
116      * Encodes the set bits in a form suitable for ZIP archives.
117      *
118      * @return the encoded general purpose bits
119      */
120     public byte[] encode() {
121         final byte[] result = new byte[2];
122         encode(result, 0);
123         return result;
124     }
125 
126     /**
127      * Encodes the set bits in a form suitable for ZIP archives.
128      *
129      * @param buf    the output buffer
130      * @param offset The offset within the output buffer of the first byte to be written. must be non-negative and no larger than {@code buf.length-2}
131      */
132     public void encode(final byte[] buf, final int offset) {
133         ZipShort.putShort((dataDescriptorFlag ? DATA_DESCRIPTOR_FLAG : 0) | (languageEncodingFlag ? UFT8_NAMES_FLAG : 0)
134                 | (encryptionFlag ? ENCRYPTION_FLAG : 0) | (strongEncryptionFlag ? STRONG_ENCRYPTION_FLAG : 0), buf, offset);
135     }
136 
137     @Override
138     public boolean equals(final Object o) {
139         if (!(o instanceof GeneralPurposeBit)) {
140             return false;
141         }
142         final GeneralPurposeBit g = (GeneralPurposeBit) o;
143         return g.encryptionFlag == encryptionFlag && g.strongEncryptionFlag == strongEncryptionFlag && g.languageEncodingFlag == languageEncodingFlag
144                 && g.dataDescriptorFlag == dataDescriptorFlag;
145     }
146 
147     /**
148      * Returns the number of trees used by the compression method 6 (imploding).
149      */
150     int getNumberOfShannonFanoTrees() {
151         return numberOfShannonFanoTrees;
152     }
153 
154     /**
155      * Returns the sliding dictionary size used by the compression method 6 (imploding).
156      */
157     int getSlidingDictionarySize() {
158         return slidingDictionarySize;
159     }
160 
161     @Override
162     public int hashCode() {
163         return 3 * (7 * (13 * (17 * (encryptionFlag ? 1 : 0) + (strongEncryptionFlag ? 1 : 0)) + (languageEncodingFlag ? 1 : 0))
164                 + (dataDescriptorFlag ? 1 : 0));
165     }
166 
167     /**
168      * whether the current entry will use the data descriptor to store CRC and size information.
169      *
170      * @param b whether the current entry will use the data descriptor to store CRC and size information
171      */
172     public void useDataDescriptor(final boolean b) {
173         dataDescriptorFlag = b;
174     }
175 
176     /**
177      * whether the current entry will be encrypted.
178      *
179      * @param b whether the current entry will be encrypted
180      */
181     public void useEncryption(final boolean b) {
182         encryptionFlag = b;
183     }
184 
185     /**
186      * whether the current entry uses the data descriptor to store CRC and size information.
187      *
188      * @return whether the current entry uses the data descriptor to store CRC and size information
189      */
190     public boolean usesDataDescriptor() {
191         return dataDescriptorFlag;
192     }
193 
194     /**
195      * whether the current entry is encrypted.
196      *
197      * @return whether the current entry is encrypted
198      */
199     public boolean usesEncryption() {
200         return encryptionFlag;
201     }
202 
203     /**
204      * whether the current entry is encrypted using strong encryption.
205      *
206      * @return whether the current entry is encrypted using strong encryption
207      */
208     public boolean usesStrongEncryption() {
209         return encryptionFlag && strongEncryptionFlag;
210     }
211 
212     /**
213      * whether the current entry will be encrypted using strong encryption.
214      *
215      * @param b whether the current entry will be encrypted using strong encryption
216      */
217     public void useStrongEncryption(final boolean b) {
218         strongEncryptionFlag = b;
219         if (b) {
220             useEncryption(true);
221         }
222     }
223 
224     /**
225      * whether the current entry uses UTF8 for file name and comment.
226      *
227      * @return whether the current entry uses UTF8 for file name and comment.
228      */
229     public boolean usesUTF8ForNames() {
230         return languageEncodingFlag;
231     }
232 
233     /**
234      * whether the current entry will use UTF8 for file name and comment.
235      *
236      * @param b whether the current entry will use UTF8 for file name and comment.
237      */
238     public void useUTF8ForNames(final boolean b) {
239         languageEncodingFlag = b;
240     }
241 }