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