001    /*
002     *  Licensed to the Apache Software Foundation (ASF) under one or more
003     *  contributor license agreements.  See the NOTICE file distributed with
004     *  this work for additional information regarding copyright ownership.
005     *  The ASF licenses this file to You under the Apache License, Version 2.0
006     *  (the "License"); you may not use this file except in compliance with
007     *  the License.  You may obtain a copy of the License at
008     *
009     *      http://www.apache.org/licenses/LICENSE-2.0
010     *
011     *  Unless required by applicable law or agreed to in writing, software
012     *  distributed under the License is distributed on an "AS IS" BASIS,
013     *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     *  See the License for the specific language governing permissions and
015     *  limitations under the License.
016     *
017     */
018    package org.apache.commons.compress.archivers.zip;
019    
020    /**
021     * Parser/encoder for the "general purpose bit" field in ZIP's local
022     * file and central directory headers.
023     * @since 1.1
024     * @NotThreadSafe
025     */
026    public final class GeneralPurposeBit {
027        /**
028         * Indicates that the file is encrypted.
029         */
030        private static final int ENCRYPTION_FLAG = 1 << 0;
031    
032        /**
033         * Indicates that a data descriptor stored after the file contents
034         * will hold CRC and size information.
035         */
036        private static final int DATA_DESCRIPTOR_FLAG = 1 << 3;
037    
038        /**
039         * Indicates strong encryption.
040         */
041        private static final int STRONG_ENCRYPTION_FLAG = 1 << 6;
042    
043        /**
044         * Indicates that filenames are written in utf-8.
045         *
046         * <p>The only reason this is public is that {@link
047         * ZipArchiveOutputStream#EFS_FLAG} was public in Apache Commons
048         * Compress 1.0 and we needed a substitute for it.</p>
049         */
050        public static final int UFT8_NAMES_FLAG = 1 << 11;
051    
052        private boolean languageEncodingFlag = false;
053        private boolean dataDescriptorFlag = false;
054        private boolean encryptionFlag = false;
055        private boolean strongEncryptionFlag = false;
056    
057        public GeneralPurposeBit() {
058        }
059    
060        /**
061         * whether the current entry uses UTF8 for file name and comment.
062         */
063        public boolean usesUTF8ForNames() {
064            return languageEncodingFlag;
065        }
066    
067        /**
068         * whether the current entry will use UTF8 for file name and comment.
069         */
070        public void useUTF8ForNames(boolean b) {
071            languageEncodingFlag = b;
072        }
073    
074        /**
075         * whether the current entry uses the data descriptor to store CRC
076         * and size information
077         */
078        public boolean usesDataDescriptor() {
079            return dataDescriptorFlag;
080        }
081    
082        /**
083         * whether the current entry will use the data descriptor to store
084         * CRC and size information
085         */
086        public void useDataDescriptor(boolean b) {
087            dataDescriptorFlag = b;
088        }
089    
090        /**
091         * whether the current entry is encrypted
092         */
093        public boolean usesEncryption() {
094            return encryptionFlag;
095        }
096    
097        /**
098         * whether the current entry will be encrypted
099         */
100        public void useEncryption(boolean b) {
101            encryptionFlag = b;
102        }
103    
104        /**
105         * whether the current entry is encrypted using strong encryption
106         */
107        public boolean usesStrongEncryption() {
108            return encryptionFlag && strongEncryptionFlag;
109        }
110    
111        /**
112         * whether the current entry will be encrypted  using strong encryption
113         */
114        public void useStrongEncryption(boolean b) {
115            strongEncryptionFlag = b;
116            if (b) {
117                useEncryption(true);
118            }
119        }
120    
121        /**
122         * Encodes the set bits in a form suitable for ZIP archives.
123         */
124        public byte[] encode() {
125            return 
126                ZipShort.getBytes((dataDescriptorFlag ? DATA_DESCRIPTOR_FLAG : 0)
127                                  |
128                                  (languageEncodingFlag ? UFT8_NAMES_FLAG : 0)
129                                  |
130                                  (encryptionFlag ? ENCRYPTION_FLAG : 0)
131                                  |
132                                  (strongEncryptionFlag ? STRONG_ENCRYPTION_FLAG : 0)
133                                  );
134        }
135    
136        /**
137         * Parses the supported flags from the given archive data.
138         * @param data local file header or a central directory entry.
139         * @param offset offset at which the general purpose bit starts
140         */
141        public static GeneralPurposeBit parse(final byte[] data, final int offset) {
142            final int generalPurposeFlag = ZipShort.getValue(data, offset);
143            GeneralPurposeBit b = new GeneralPurposeBit();
144            b.useDataDescriptor((generalPurposeFlag & DATA_DESCRIPTOR_FLAG) != 0);
145            b.useUTF8ForNames((generalPurposeFlag & UFT8_NAMES_FLAG) != 0);
146            b.useStrongEncryption((generalPurposeFlag & STRONG_ENCRYPTION_FLAG)
147                                  != 0);
148            b.useEncryption((generalPurposeFlag & ENCRYPTION_FLAG) != 0);
149            return b;
150        }
151    
152        @Override
153        public int hashCode() {
154            return 3 * (7 * (13 * (17 * (encryptionFlag ? 1 : 0)
155                                   + (strongEncryptionFlag ? 1 : 0))
156                             + (languageEncodingFlag ? 1 : 0))
157                        + (dataDescriptorFlag ? 1 : 0));
158        }
159    
160        @Override
161        public boolean equals(Object o) {
162            if (!(o instanceof GeneralPurposeBit)) {
163                return false;
164            }
165            GeneralPurposeBit g = (GeneralPurposeBit) o;
166            return g.encryptionFlag == encryptionFlag
167                && g.strongEncryptionFlag == strongEncryptionFlag
168                && g.languageEncodingFlag == languageEncodingFlag
169                && g.dataDescriptorFlag == dataDescriptorFlag;
170        }
171    }