GeneralPurposeBit.java

  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.  * Parser/encoder for the "general purpose bit" field in ZIP's local file and central directory headers.
  20.  *
  21.  * @since 1.1
  22.  * @NotThreadSafe
  23.  */
  24. public final class GeneralPurposeBit implements Cloneable {

  25.     /**
  26.      * Indicates that the file is encrypted.
  27.      */
  28.     private static final int ENCRYPTION_FLAG = 1 << 0;

  29.     /**
  30.      * Indicates the size of the sliding dictionary used by the compression method 6 (imploding).
  31.      * <ul>
  32.      * <li>0: 4096 bytes</li>
  33.      * <li>1: 8192 bytes</li>
  34.      * </ul>
  35.      */
  36.     private static final int SLIDING_DICTIONARY_SIZE_FLAG = 1 << 1;

  37.     /**
  38.      * Indicates the number of Shannon-Fano trees used by the compression method 6 (imploding).
  39.      * <ul>
  40.      * <li>0: 2 trees (lengths, distances)</li>
  41.      * <li>1: 3 trees (literals, lengths, distances)</li>
  42.      * </ul>
  43.      */
  44.     private static final int NUMBER_OF_SHANNON_FANO_TREES_FLAG = 1 << 2;

  45.     /**
  46.      * Indicates that a data descriptor stored after the file contents will hold CRC and size information.
  47.      */
  48.     private static final int DATA_DESCRIPTOR_FLAG = 1 << 3;

  49.     /**
  50.      * Indicates strong encryption.
  51.      */
  52.     private static final int STRONG_ENCRYPTION_FLAG = 1 << 6;

  53.     /**
  54.      * Indicates that file names are written in UTF-8.
  55.      *
  56.      * <p>
  57.      * 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
  58.      * it.
  59.      * </p>
  60.      */
  61.     public static final int UFT8_NAMES_FLAG = 1 << 11;

  62.     /**
  63.      * Parses the supported flags from the given archive data.
  64.      *
  65.      * @param data   local file header or a central directory entry.
  66.      * @param offset offset at which the general purpose bit starts
  67.      * @return parsed flags
  68.      */
  69.     public static GeneralPurposeBit parse(final byte[] data, final int offset) {
  70.         final int generalPurposeFlag = ZipShort.getValue(data, offset);
  71.         final GeneralPurposeBit b = new GeneralPurposeBit();
  72.         b.useDataDescriptor((generalPurposeFlag & DATA_DESCRIPTOR_FLAG) != 0);
  73.         b.useUTF8ForNames((generalPurposeFlag & UFT8_NAMES_FLAG) != 0);
  74.         b.useStrongEncryption((generalPurposeFlag & STRONG_ENCRYPTION_FLAG) != 0);
  75.         b.useEncryption((generalPurposeFlag & ENCRYPTION_FLAG) != 0);
  76.         b.slidingDictionarySize = (generalPurposeFlag & SLIDING_DICTIONARY_SIZE_FLAG) != 0 ? 8192 : 4096;
  77.         b.numberOfShannonFanoTrees = (generalPurposeFlag & NUMBER_OF_SHANNON_FANO_TREES_FLAG) != 0 ? 3 : 2;
  78.         return b;
  79.     }

  80.     private boolean languageEncodingFlag;
  81.     private boolean dataDescriptorFlag;
  82.     private boolean encryptionFlag;
  83.     private boolean strongEncryptionFlag;
  84.     private int slidingDictionarySize;

  85.     private int numberOfShannonFanoTrees;

  86.     public GeneralPurposeBit() {
  87.     }

  88.     @Override
  89.     public Object clone() {
  90.         try {
  91.             return super.clone();
  92.         } catch (final CloneNotSupportedException ex) {
  93.             // impossible
  94.             throw new UnsupportedOperationException("GeneralPurposeBit is not Cloneable?", ex); // NOSONAR
  95.         }
  96.     }

  97.     /**
  98.      * Encodes the set bits in a form suitable for ZIP archives.
  99.      *
  100.      * @return the encoded general purpose bits
  101.      */
  102.     public byte[] encode() {
  103.         final byte[] result = new byte[2];
  104.         encode(result, 0);
  105.         return result;
  106.     }

  107.     /**
  108.      * Encodes the set bits in a form suitable for ZIP archives.
  109.      *
  110.      * @param buf    the output buffer
  111.      * @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}
  112.      */
  113.     public void encode(final byte[] buf, final int offset) {
  114.         ZipShort.putShort((dataDescriptorFlag ? DATA_DESCRIPTOR_FLAG : 0) | (languageEncodingFlag ? UFT8_NAMES_FLAG : 0)
  115.                 | (encryptionFlag ? ENCRYPTION_FLAG : 0) | (strongEncryptionFlag ? STRONG_ENCRYPTION_FLAG : 0), buf, offset);
  116.     }

  117.     @Override
  118.     public boolean equals(final Object o) {
  119.         if (!(o instanceof GeneralPurposeBit)) {
  120.             return false;
  121.         }
  122.         final GeneralPurposeBit g = (GeneralPurposeBit) o;
  123.         return g.encryptionFlag == encryptionFlag && g.strongEncryptionFlag == strongEncryptionFlag && g.languageEncodingFlag == languageEncodingFlag
  124.                 && g.dataDescriptorFlag == dataDescriptorFlag;
  125.     }

  126.     /**
  127.      * Returns the number of trees used by the compression method 6 (imploding).
  128.      */
  129.     int getNumberOfShannonFanoTrees() {
  130.         return numberOfShannonFanoTrees;
  131.     }

  132.     /**
  133.      * Returns the sliding dictionary size used by the compression method 6 (imploding).
  134.      */
  135.     int getSlidingDictionarySize() {
  136.         return slidingDictionarySize;
  137.     }

  138.     @Override
  139.     public int hashCode() {
  140.         return 3 * (7 * (13 * (17 * (encryptionFlag ? 1 : 0) + (strongEncryptionFlag ? 1 : 0)) + (languageEncodingFlag ? 1 : 0))
  141.                 + (dataDescriptorFlag ? 1 : 0));
  142.     }

  143.     /**
  144.      * whether the current entry will use the data descriptor to store CRC and size information.
  145.      *
  146.      * @param b whether the current entry will use the data descriptor to store CRC and size information
  147.      */
  148.     public void useDataDescriptor(final boolean b) {
  149.         dataDescriptorFlag = b;
  150.     }

  151.     /**
  152.      * whether the current entry will be encrypted.
  153.      *
  154.      * @param b whether the current entry will be encrypted
  155.      */
  156.     public void useEncryption(final boolean b) {
  157.         encryptionFlag = b;
  158.     }

  159.     /**
  160.      * whether the current entry uses the data descriptor to store CRC and size information.
  161.      *
  162.      * @return whether the current entry uses the data descriptor to store CRC and size information
  163.      */
  164.     public boolean usesDataDescriptor() {
  165.         return dataDescriptorFlag;
  166.     }

  167.     /**
  168.      * whether the current entry is encrypted.
  169.      *
  170.      * @return whether the current entry is encrypted
  171.      */
  172.     public boolean usesEncryption() {
  173.         return encryptionFlag;
  174.     }

  175.     /**
  176.      * whether the current entry is encrypted using strong encryption.
  177.      *
  178.      * @return whether the current entry is encrypted using strong encryption
  179.      */
  180.     public boolean usesStrongEncryption() {
  181.         return encryptionFlag && strongEncryptionFlag;
  182.     }

  183.     /**
  184.      * whether the current entry will be encrypted using strong encryption.
  185.      *
  186.      * @param b whether the current entry will be encrypted using strong encryption
  187.      */
  188.     public void useStrongEncryption(final boolean b) {
  189.         strongEncryptionFlag = b;
  190.         if (b) {
  191.             useEncryption(true);
  192.         }
  193.     }

  194.     /**
  195.      * whether the current entry uses UTF8 for file name and comment.
  196.      *
  197.      * @return whether the current entry uses UTF8 for file name and comment.
  198.      */
  199.     public boolean usesUTF8ForNames() {
  200.         return languageEncodingFlag;
  201.     }

  202.     /**
  203.      * whether the current entry will use UTF8 for file name and comment.
  204.      *
  205.      * @param b whether the current entry will use UTF8 for file name and comment.
  206.      */
  207.     public void useUTF8ForNames(final boolean b) {
  208.         languageEncodingFlag = b;
  209.     }
  210. }