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