    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 Apache Commons Compress 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    }