    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 */
    017package org.apache.commons.compress.archivers.zip;
    018
    019/**
    020 * Parser/encoder for the "general purpose bit" field in ZIP's local
    021 * file and central directory headers.
    022 *
    023 * @since 1.1
    024 * @NotThreadSafe
    025 */
    026public final class GeneralPurposeBit implements Cloneable {
    027
    028    /**
    029     * Indicates that the file is encrypted.
    030     */
    031    private static final int ENCRYPTION_FLAG = 1 << 0;
    032
    033    /**
    034     * Indicates the size of the sliding dictionary used by the compression method 6 (imploding).
    035     * <ul>
    036     *   <li>0: 4096 bytes</li>
    037     *   <li>1: 8192 bytes</li>
    038     * </ul>
    039     */
    040    private static final int SLIDING_DICTIONARY_SIZE_FLAG = 1 << 1;
    041
    042    /**
    043     * Indicates the number of Shannon-Fano trees used by the compression method 6 (imploding).
    044     * <ul>
    045     *   <li>0: 2 trees (lengths, distances)</li>
    046     *   <li>1: 3 trees (literals, lengths, distances)</li>
    047     * </ul>
    048     */
    049    private static final int NUMBER_OF_SHANNON_FANO_TREES_FLAG = 1 << 2;
    050
    051    /**
    052     * Indicates that a data descriptor stored after the file contents
    053     * will hold CRC and size information.
    054     */
    055    private static final int DATA_DESCRIPTOR_FLAG = 1 << 3;
    056
    057    /**
    058     * Indicates strong encryption.
    059     */
    060    private static final int STRONG_ENCRYPTION_FLAG = 1 << 6;
    061
    062    /**
    063     * Indicates that file names are written in UTF-8.
    064     *
    065     * <p>The only reason this is public is that {@link
    066     * ZipArchiveOutputStream#EFS_FLAG} was public in Apache Commons
    067     * Compress 1.0 and we needed a substitute for it.</p>
    068     */
    069    public static final int UFT8_NAMES_FLAG = 1 << 11;
    070
    071    /**
    072     * Parses the supported flags from the given archive data.
    073     *
    074     * @param data local file header or a central directory entry.
    075     * @param offset offset at which the general purpose bit starts
    076     * @return parsed flags
    077     */
    078    public static GeneralPurposeBit parse(final byte[] data, final int offset) {
    079        final int generalPurposeFlag = ZipShort.getValue(data, offset);
    080        final GeneralPurposeBit b = new GeneralPurposeBit();
    081        b.useDataDescriptor((generalPurposeFlag & DATA_DESCRIPTOR_FLAG) != 0);
    082        b.useUTF8ForNames((generalPurposeFlag & UFT8_NAMES_FLAG) != 0);
    083        b.useStrongEncryption((generalPurposeFlag & STRONG_ENCRYPTION_FLAG) != 0);
    084        b.useEncryption((generalPurposeFlag & ENCRYPTION_FLAG) != 0);
    085        b.slidingDictionarySize = (generalPurposeFlag & SLIDING_DICTIONARY_SIZE_FLAG) != 0 ? 8192 : 4096;
    086        b.numberOfShannonFanoTrees = (generalPurposeFlag & NUMBER_OF_SHANNON_FANO_TREES_FLAG) != 0 ? 3 : 2;
    087        return b;
    088    }
    089    private boolean languageEncodingFlag;
    090    private boolean dataDescriptorFlag;
    091    private boolean encryptionFlag;
    092    private boolean strongEncryptionFlag;
    093    private int slidingDictionarySize;
    094
    095    private int numberOfShannonFanoTrees;
    096
    097    public GeneralPurposeBit() {
    098    }
    099
    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     * @return the encoded general purpose bits
    113     */
    114    public byte[] encode() {
    115        final byte[] result = new byte[2];
    116        encode(result, 0);
    117        return result;
    118    }
    119
    120    /**
    121     * Encodes the set bits in a form suitable for ZIP archives.
    122     *
    123     * @param buf the output buffer
    124     * @param  offset
    125     *         The offset within the output buffer of the first byte to be written.
    126     *         must be non-negative and no larger than {@code buf.length-2}
    127     */
    128    public void encode(final byte[] buf, final int offset) {
    129                ZipShort.putShort((dataDescriptorFlag ? DATA_DESCRIPTOR_FLAG : 0)
    130                        |
    131                        (languageEncodingFlag ? UFT8_NAMES_FLAG : 0)
    132                        |
    133                        (encryptionFlag ? ENCRYPTION_FLAG : 0)
    134                        |
    135                        (strongEncryptionFlag ? STRONG_ENCRYPTION_FLAG : 0)
    136                        , buf, offset);
    137    }
    138
    139    @Override
    140    public boolean equals(final Object o) {
    141        if (!(o instanceof GeneralPurposeBit)) {
    142            return false;
    143        }
    144        final GeneralPurposeBit g = (GeneralPurposeBit) o;
    145        return g.encryptionFlag == encryptionFlag
    146            && g.strongEncryptionFlag == strongEncryptionFlag
    147            && g.languageEncodingFlag == languageEncodingFlag
    148            && g.dataDescriptorFlag == dataDescriptorFlag;
    149    }
    150
    151    /**
    152     * Returns the number of trees used by the compression method 6 (imploding).
    153     */
    154    int getNumberOfShannonFanoTrees() {
    155        return numberOfShannonFanoTrees;
    156    }
    157
    158    /**
    159     * Returns the sliding dictionary size used by the compression method 6 (imploding).
    160     */
    161    int getSlidingDictionarySize() {
    162        return slidingDictionarySize;
    163    }
    164
    165    @Override
    166    public int hashCode() {
    167        return 3 * (7 * (13 * (17 * (encryptionFlag ? 1 : 0)
    168                               + (strongEncryptionFlag ? 1 : 0))
    169                         + (languageEncodingFlag ? 1 : 0))
    170                    + (dataDescriptorFlag ? 1 : 0));
    171    }
    172
    173    /**
    174     * whether the current entry will use the data descriptor to store
    175     * CRC and size information.
    176     * @param b whether the current entry will use the data descriptor to store
    177     * CRC and size information
    178     */
    179    public void useDataDescriptor(final boolean b) {
    180        dataDescriptorFlag = b;
    181    }
    182
    183    /**
    184     * whether the current entry will be encrypted.
    185     * @param b whether the current entry will be encrypted
    186     */
    187    public void useEncryption(final boolean b) {
    188        encryptionFlag = b;
    189    }
    190
    191    /**
    192     * whether the current entry uses the data descriptor to store CRC
    193     * and size information.
    194     * @return whether the current entry uses the data descriptor to store CRC
    195     * and size information
    196     */
    197    public boolean usesDataDescriptor() {
    198        return dataDescriptorFlag;
    199    }
    200
    201
    202    /**
    203     * whether the current entry is encrypted.
    204     * @return whether the current entry is encrypted
    205     */
    206    public boolean usesEncryption() {
    207        return encryptionFlag;
    208    }
    209
    210    /**
    211     * whether the current entry is encrypted using strong encryption.
    212     * @return whether the current entry is encrypted using strong encryption
    213     */
    214    public boolean usesStrongEncryption() {
    215        return encryptionFlag && strongEncryptionFlag;
    216    }
    217
    218    /**
    219     * whether the current entry will be encrypted  using strong encryption.
    220     * @param b whether the current entry will be encrypted  using strong encryption
    221     */
    222    public void useStrongEncryption(final boolean b) {
    223        strongEncryptionFlag = b;
    224        if (b) {
    225            useEncryption(true);
    226        }
    227    }
    228
    229    /**
    230     * whether the current entry uses UTF8 for file name and comment.
    231     * @return whether the current entry uses UTF8 for file name and comment.
    232     */
    233    public boolean usesUTF8ForNames() {
    234        return languageEncodingFlag;
    235    }
    236
    237    /**
    238     * whether the current entry will use UTF8 for file name and comment.
    239     * @param b whether the current entry will use UTF8 for file name and comment.
    240     */
    241    public void useUTF8ForNames(final boolean b) {
    242        languageEncodingFlag = b;
    243    }
    244}