View Javadoc
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 }