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 }