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 */
018package 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 */
026public 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}