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.harmony.pack200; 018 019import java.io.EOFException; 020import java.io.IOException; 021import java.io.InputStream; 022import java.util.Arrays; 023import java.util.HashMap; 024import java.util.Map; 025 026/** 027 * CodecEncoding is used to get the right Codec for a given meta-encoding 028 */ 029public class CodecEncoding { 030 031 /** 032 * The canonical encodings are defined to allow a single byte to represent one of the standard encodings. The 033 * following values are defined in the Pack200 specification, and this array cannot be changed. 034 */ 035 private static final BHSDCodec[] canonicalCodec = {null, new BHSDCodec(1, 256), new BHSDCodec(1, 256, 1), 036 new BHSDCodec(1, 256, 0, 1), new BHSDCodec(1, 256, 1, 1), new BHSDCodec(2, 256), new BHSDCodec(2, 256, 1), 037 new BHSDCodec(2, 256, 0, 1), new BHSDCodec(2, 256, 1, 1), new BHSDCodec(3, 256), new BHSDCodec(3, 256, 1), 038 new BHSDCodec(3, 256, 0, 1), new BHSDCodec(3, 256, 1, 1), new BHSDCodec(4, 256), new BHSDCodec(4, 256, 1), 039 new BHSDCodec(4, 256, 0, 1), new BHSDCodec(4, 256, 1, 1), new BHSDCodec(5, 4), new BHSDCodec(5, 4, 1), 040 new BHSDCodec(5, 4, 2), new BHSDCodec(5, 16), new BHSDCodec(5, 16, 1), new BHSDCodec(5, 16, 2), 041 new BHSDCodec(5, 32), new BHSDCodec(5, 32, 1), new BHSDCodec(5, 32, 2), new BHSDCodec(5, 64), 042 new BHSDCodec(5, 64, 1), new BHSDCodec(5, 64, 2), new BHSDCodec(5, 128), new BHSDCodec(5, 128, 1), 043 new BHSDCodec(5, 128, 2), new BHSDCodec(5, 4, 0, 1), new BHSDCodec(5, 4, 1, 1), new BHSDCodec(5, 4, 2, 1), 044 new BHSDCodec(5, 16, 0, 1), new BHSDCodec(5, 16, 1, 1), new BHSDCodec(5, 16, 2, 1), new BHSDCodec(5, 32, 0, 1), 045 new BHSDCodec(5, 32, 1, 1), new BHSDCodec(5, 32, 2, 1), new BHSDCodec(5, 64, 0, 1), new BHSDCodec(5, 64, 1, 1), 046 new BHSDCodec(5, 64, 2, 1), new BHSDCodec(5, 128, 0, 1), new BHSDCodec(5, 128, 1, 1), 047 new BHSDCodec(5, 128, 2, 1), new BHSDCodec(2, 192), new BHSDCodec(2, 224), new BHSDCodec(2, 240), 048 new BHSDCodec(2, 248), new BHSDCodec(2, 252), new BHSDCodec(2, 8, 0, 1), new BHSDCodec(2, 8, 1, 1), 049 new BHSDCodec(2, 16, 0, 1), new BHSDCodec(2, 16, 1, 1), new BHSDCodec(2, 32, 0, 1), new BHSDCodec(2, 32, 1, 1), 050 new BHSDCodec(2, 64, 0, 1), new BHSDCodec(2, 64, 1, 1), new BHSDCodec(2, 128, 0, 1), 051 new BHSDCodec(2, 128, 1, 1), new BHSDCodec(2, 192, 0, 1), new BHSDCodec(2, 192, 1, 1), 052 new BHSDCodec(2, 224, 0, 1), new BHSDCodec(2, 224, 1, 1), new BHSDCodec(2, 240, 0, 1), 053 new BHSDCodec(2, 240, 1, 1), new BHSDCodec(2, 248, 0, 1), new BHSDCodec(2, 248, 1, 1), new BHSDCodec(3, 192), 054 new BHSDCodec(3, 224), new BHSDCodec(3, 240), new BHSDCodec(3, 248), new BHSDCodec(3, 252), 055 new BHSDCodec(3, 8, 0, 1), new BHSDCodec(3, 8, 1, 1), new BHSDCodec(3, 16, 0, 1), new BHSDCodec(3, 16, 1, 1), 056 new BHSDCodec(3, 32, 0, 1), new BHSDCodec(3, 32, 1, 1), new BHSDCodec(3, 64, 0, 1), new BHSDCodec(3, 64, 1, 1), 057 new BHSDCodec(3, 128, 0, 1), new BHSDCodec(3, 128, 1, 1), new BHSDCodec(3, 192, 0, 1), 058 new BHSDCodec(3, 192, 1, 1), new BHSDCodec(3, 224, 0, 1), new BHSDCodec(3, 224, 1, 1), 059 new BHSDCodec(3, 240, 0, 1), new BHSDCodec(3, 240, 1, 1), new BHSDCodec(3, 248, 0, 1), 060 new BHSDCodec(3, 248, 1, 1), new BHSDCodec(4, 192), new BHSDCodec(4, 224), new BHSDCodec(4, 240), 061 new BHSDCodec(4, 248), new BHSDCodec(4, 252), new BHSDCodec(4, 8, 0, 1), new BHSDCodec(4, 8, 1, 1), 062 new BHSDCodec(4, 16, 0, 1), new BHSDCodec(4, 16, 1, 1), new BHSDCodec(4, 32, 0, 1), new BHSDCodec(4, 32, 1, 1), 063 new BHSDCodec(4, 64, 0, 1), new BHSDCodec(4, 64, 1, 1), new BHSDCodec(4, 128, 0, 1), 064 new BHSDCodec(4, 128, 1, 1), new BHSDCodec(4, 192, 0, 1), new BHSDCodec(4, 192, 1, 1), 065 new BHSDCodec(4, 224, 0, 1), new BHSDCodec(4, 224, 1, 1), new BHSDCodec(4, 240, 0, 1), 066 new BHSDCodec(4, 240, 1, 1), new BHSDCodec(4, 248, 0, 1), new BHSDCodec(4, 248, 1, 1)}; 067 068 private static Map<BHSDCodec, Integer> canonicalCodecsToSpecifiers; 069 070 static { 071 final HashMap<BHSDCodec, Integer> reverseMap = new HashMap<>(canonicalCodec.length); 072 for (int i = 0; i < canonicalCodec.length; i++) { 073 reverseMap.put(canonicalCodec[i], Integer.valueOf(i)); 074 } 075 canonicalCodecsToSpecifiers = reverseMap; 076 } 077 078 public static BHSDCodec getCanonicalCodec(final int i) { 079 return canonicalCodec[i]; 080 } 081 082 /** 083 * Returns the codec specified by the given value byte and optional byte header. If the value is >= 116, then 084 * bytes may be consumed from the secondary input stream, which is taken to be the contents of the band_headers byte 085 * array. Since the values from this are consumed and not repeated, the input stream should be reused for subsequent 086 * encodings. This does not therefore close the input stream. 087 * 088 * @param value the canonical encoding value 089 * @param in the input stream to read additional byte headers from 090 * @param defaultCodec TODO 091 * @return the corresponding codec, or {@code null} if the default should be used 092 * 093 * @throws IOException if there is a problem reading from the input stream (which in reality, is never, since the 094 * band_headers are likely stored in a byte array and accessed via a ByteArrayInputStream. However, an 095 * EOFException could occur if things go wrong) 096 * @throws Pack200Exception TODO 097 */ 098 public static Codec getCodec(final int value, final InputStream in, final Codec defaultCodec) 099 throws IOException, Pack200Exception { 100 // Sanity check to make sure that no-one has changed 101 // the canonical codecs, which would really cause havoc 102 if (canonicalCodec.length != 116) { 103 throw new Error("Canonical encodings have been incorrectly modified"); 104 } 105 if (value < 0) { 106 throw new IllegalArgumentException("Encoding cannot be less than zero"); 107 } 108 if (value == 0) { 109 return defaultCodec; 110 } 111 if (value <= 115) { 112 return canonicalCodec[value]; 113 } 114 if (value == 116) { 115 int code = in.read(); 116 if (code == -1) { 117 throw new EOFException("End of buffer read whilst trying to decode codec"); 118 } 119 final int d = code & 0x01; 120 final int s = code >> 1 & 0x03; 121 final int b = (code >> 3 & 0x07) + 1; // this might result in an invalid 122 // number, but it's checked in the 123 // Codec constructor 124 code = in.read(); 125 if (code == -1) { 126 throw new EOFException("End of buffer read whilst trying to decode codec"); 127 } 128 final int h = code + 1; 129 // This handles the special cases for invalid combinations of data. 130 return new BHSDCodec(b, h, s, d); 131 } 132 if (value >= 117 && value <= 140) { // Run codec 133 final int offset = value - 117; 134 final int kx = offset & 3; 135 final boolean kbflag = (offset >> 2 & 1) == 1; 136 final boolean adef = (offset >> 3 & 1) == 1; 137 final boolean bdef = (offset >> 4 & 1) == 1; 138 // If both A and B use the default encoding, what's the point of 139 // having a run of default values followed by default values 140 if (adef && bdef) { 141 throw new Pack200Exception("ADef and BDef should never both be true"); 142 } 143 final int kb = kbflag ? in.read() : 3; 144 final int k = (kb + 1) * (int) Math.pow(16, kx); 145 Codec aCodec, bCodec; 146 if (adef) { 147 aCodec = defaultCodec; 148 } else { 149 aCodec = getCodec(in.read(), in, defaultCodec); 150 } 151 if (bdef) { 152 bCodec = defaultCodec; 153 } else { 154 bCodec = getCodec(in.read(), in, defaultCodec); 155 } 156 return new RunCodec(k, aCodec, bCodec); 157 } 158 if (value < 141 || value > 188) { 159 throw new Pack200Exception("Invalid codec encoding byte (" + value + ") found"); 160 } 161 final int offset = value - 141; 162 final boolean fdef = (offset & 1) == 1; 163 final boolean udef = (offset >> 1 & 1) == 1; 164 final int tdefl = offset >> 2; 165 final boolean tdef = tdefl != 0; 166 // From section 6.7.3 of spec 167 final int[] tdefToL = {0, 4, 8, 16, 32, 64, 128, 192, 224, 240, 248, 252}; 168 final int l = tdefToL[tdefl]; 169 // NOTE: Do not re-factor this to bring out uCodec; the order in 170 // which 171 // they are read from the stream is important 172 if (tdef) { 173 final Codec fCodec = fdef ? defaultCodec : getCodec(in.read(), in, defaultCodec); 174 final Codec uCodec = udef ? defaultCodec : getCodec(in.read(), in, defaultCodec); 175 // Unfortunately, if tdef, then tCodec depends both on l and 176 // also on k, the 177 // number of items read from the fCodec. So we don't know in 178 // advance what 179 // the codec will be. 180 return new PopulationCodec(fCodec, l, uCodec); 181 } 182 final Codec fCodec = fdef ? defaultCodec : getCodec(in.read(), in, defaultCodec); 183 final Codec tCodec = getCodec(in.read(), in, defaultCodec); 184 final Codec uCodec = udef ? defaultCodec : getCodec(in.read(), in, defaultCodec); 185 return new PopulationCodec(fCodec, tCodec, uCodec); 186 } 187 188 public static int[] getSpecifier(final Codec codec, final Codec defaultForBand) { 189 if (canonicalCodecsToSpecifiers.containsKey(codec)) { 190 return new int[] { canonicalCodecsToSpecifiers.get(codec).intValue() }; 191 } 192 if (codec instanceof BHSDCodec) { 193 // Cache these? 194 final BHSDCodec bhsdCodec = (BHSDCodec) codec; 195 final int[] specifiers = new int[3]; 196 specifiers[0] = 116; 197 specifiers[1] = (bhsdCodec.isDelta() ? 1 : 0) + 2 * bhsdCodec.getS() + 8 * (bhsdCodec.getB() - 1); 198 specifiers[2] = bhsdCodec.getH() - 1; 199 return specifiers; 200 } 201 if (codec instanceof RunCodec) { 202 final RunCodec runCodec = (RunCodec) codec; 203 final int k = runCodec.getK(); 204 int kb; 205 int kx; 206 if (k <= 256) { 207 kb = 0; 208 kx = k - 1; 209 } else if (k <= 4096) { 210 kb = 1; 211 kx = k / 16 - 1; 212 } else if (k <= 65536) { 213 kb = 2; 214 kx = k / 256 - 1; 215 } else { 216 kb = 3; 217 kx = k / 4096 - 1; 218 } 219 final Codec aCodec = runCodec.getACodec(); 220 final Codec bCodec = runCodec.getBCodec(); 221 int abDef = 0; 222 if (aCodec.equals(defaultForBand)) { 223 abDef = 1; 224 } else if (bCodec.equals(defaultForBand)) { 225 abDef = 2; 226 } 227 final int first = 117 + kb + (kx == 3 ? 0 : 4) + 8 * abDef; 228 final int[] aSpecifier = abDef == 1 ? new int[0] : getSpecifier(aCodec, defaultForBand); 229 final int[] bSpecifier = abDef == 2 ? new int[0] : getSpecifier(bCodec, defaultForBand); 230 final int[] specifier = new int[1 + (kx == 3 ? 0 : 1) + aSpecifier.length + bSpecifier.length]; 231 specifier[0] = first; 232 int index = 1; 233 if (kx != 3) { 234 specifier[1] = kx; 235 index++; 236 } 237 for (final int element : aSpecifier) { 238 specifier[index] = element; 239 index++; 240 } 241 for (final int element : bSpecifier) { 242 specifier[index] = element; 243 index++; 244 } 245 return specifier; 246 } 247 if (codec instanceof PopulationCodec) { 248 final PopulationCodec populationCodec = (PopulationCodec) codec; 249 final Codec tokenCodec = populationCodec.getTokenCodec(); 250 final Codec favouredCodec = populationCodec.getFavouredCodec(); 251 final Codec unfavouredCodec = populationCodec.getUnfavouredCodec(); 252 final int fDef = favouredCodec.equals(defaultForBand) ? 1 : 0; 253 final int uDef = unfavouredCodec.equals(defaultForBand) ? 1 : 0; 254 int tDefL = 0; 255 final int[] favoured = populationCodec.getFavoured(); 256 if (favoured != null) { 257 if (tokenCodec == Codec.BYTE1) { 258 tDefL = 1; 259 } else if (tokenCodec instanceof BHSDCodec) { 260 final BHSDCodec tokenBHSD = (BHSDCodec) tokenCodec; 261 if (tokenBHSD.getS() == 0) { 262 final int[] possibleLValues = {4, 8, 16, 32, 64, 128, 192, 224, 240, 248, 252}; 263 final int l = 256 - tokenBHSD.getH(); 264 int index = Arrays.binarySearch(possibleLValues, l); 265 if (index != -1) { 266 // TODO: check range is ok for ks 267 tDefL = index++; 268 } 269 } 270 } 271 } 272 final int first = 141 + fDef + 2 * uDef + 4 * tDefL; 273 final int[] favouredSpecifier = fDef == 1 ? new int[0] : getSpecifier(favouredCodec, defaultForBand); 274 final int[] tokenSpecifier = tDefL != 0 ? new int[0] : getSpecifier(tokenCodec, defaultForBand); 275 final int[] unfavouredSpecifier = uDef == 1 ? new int[0] : getSpecifier(unfavouredCodec, defaultForBand); 276 final int[] specifier = new int[1 + favouredSpecifier.length + unfavouredSpecifier.length 277 + tokenSpecifier.length]; 278 specifier[0] = first; 279 int index = 1; 280 for (final int element : favouredSpecifier) { 281 specifier[index] = element; 282 index++; 283 } 284 for (final int element : tokenSpecifier) { 285 specifier[index] = element; 286 index++; 287 } 288 for (final int element : unfavouredSpecifier) { 289 specifier[index] = element; 290 index++; 291 } 292 return specifier; 293 } 294 295 return null; 296 } 297 298 public static int getSpecifierForDefaultCodec(final BHSDCodec defaultCodec) { 299 return getSpecifier(defaultCodec, null)[0]; 300 } 301}