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: package org.apache.harmony.pack200;
018:
019: import java.io.EOFException;
020: import java.io.IOException;
021: import java.io.InputStream;
022:
023: public class CodecEncoding {
024:
025: /**
026: * The canonical encodings are defined to allow a single byte to represent
027: * one of the standard encodings. The following values are defined in the
028: * Pack200 specification, and this array cannot be changed.
029: */
030: private static final Codec[] canonicalCodec = { null,
031: new BHSDCodec(1, 256), new BHSDCodec(1, 256, 1),
032: new BHSDCodec(1, 256, 0, 1), new BHSDCodec(1, 256, 1, 1),
033: new BHSDCodec(2, 256), new BHSDCodec(2, 256, 1),
034: new BHSDCodec(2, 256, 0, 1), new BHSDCodec(2, 256, 1, 1),
035: new BHSDCodec(3, 256), new BHSDCodec(3, 256, 1),
036: new BHSDCodec(3, 256, 0, 1), new BHSDCodec(3, 256, 1, 1),
037: new BHSDCodec(4, 256), new BHSDCodec(4, 256, 1),
038: new BHSDCodec(4, 256, 0, 1), new BHSDCodec(4, 256, 1, 1),
039: new BHSDCodec(5, 4), new BHSDCodec(5, 4, 1),
040: new BHSDCodec(5, 4, 2), new BHSDCodec(5, 16),
041: new BHSDCodec(5, 16, 1), new BHSDCodec(5, 16, 2),
042: new BHSDCodec(5, 32), new BHSDCodec(5, 32, 1),
043: new BHSDCodec(5, 32, 2), new BHSDCodec(5, 64),
044: new BHSDCodec(5, 64, 1), new BHSDCodec(5, 64, 2),
045: new BHSDCodec(5, 128), new BHSDCodec(5, 128, 1),
046: new BHSDCodec(5, 128, 2), new BHSDCodec(5, 4, 0, 1),
047: new BHSDCodec(5, 4, 1, 1), new BHSDCodec(5, 4, 2, 1),
048: new BHSDCodec(5, 16, 0, 1), new BHSDCodec(5, 16, 1, 1),
049: new BHSDCodec(5, 16, 2, 1), new BHSDCodec(5, 32, 0, 1),
050: new BHSDCodec(5, 32, 1, 1), new BHSDCodec(5, 32, 2, 1),
051: new BHSDCodec(5, 64, 0, 1), new BHSDCodec(5, 64, 1, 1),
052: new BHSDCodec(5, 64, 2, 1), new BHSDCodec(5, 128, 0, 1),
053: new BHSDCodec(5, 128, 1, 1), new BHSDCodec(5, 128, 2, 1),
054: new BHSDCodec(2, 192), new BHSDCodec(2, 224),
055: new BHSDCodec(2, 240), new BHSDCodec(2, 248),
056: new BHSDCodec(2, 252), new BHSDCodec(2, 8, 0, 1),
057: new BHSDCodec(2, 8, 1, 1), new BHSDCodec(2, 16, 0, 1),
058: new BHSDCodec(2, 16, 1, 1), new BHSDCodec(2, 32, 0, 1),
059: new BHSDCodec(2, 32, 1, 1), new BHSDCodec(2, 64, 0, 1),
060: new BHSDCodec(2, 64, 1, 1), new BHSDCodec(2, 128, 0, 1),
061: new BHSDCodec(2, 128, 1, 1), new BHSDCodec(2, 192, 0, 1),
062: new BHSDCodec(2, 192, 1, 1), new BHSDCodec(2, 224, 0, 1),
063: new BHSDCodec(2, 224, 1, 1), new BHSDCodec(2, 240, 0, 1),
064: new BHSDCodec(2, 240, 1, 1), new BHSDCodec(2, 248, 0, 1),
065: new BHSDCodec(2, 248, 1, 1), new BHSDCodec(3, 192),
066: new BHSDCodec(3, 224), new BHSDCodec(3, 240),
067: new BHSDCodec(3, 248), new BHSDCodec(3, 252),
068: new BHSDCodec(3, 8, 0, 1), new BHSDCodec(3, 8, 1, 1),
069: new BHSDCodec(3, 16, 0, 1), new BHSDCodec(3, 16, 1, 1),
070: new BHSDCodec(3, 32, 0, 1), new BHSDCodec(3, 32, 1, 1),
071: new BHSDCodec(3, 64, 0, 1), new BHSDCodec(3, 64, 1, 1),
072: new BHSDCodec(3, 128, 0, 1), new BHSDCodec(3, 128, 1, 1),
073: new BHSDCodec(3, 192, 0, 1), new BHSDCodec(3, 192, 1, 1),
074: new BHSDCodec(3, 224, 0, 1), new BHSDCodec(3, 224, 1, 1),
075: new BHSDCodec(3, 240, 0, 1), new BHSDCodec(3, 240, 1, 1),
076: new BHSDCodec(3, 248, 0, 1), new BHSDCodec(3, 248, 1, 1),
077: new BHSDCodec(4, 192), new BHSDCodec(4, 224),
078: new BHSDCodec(4, 240), new BHSDCodec(4, 248),
079: new BHSDCodec(4, 252), new BHSDCodec(4, 8, 0, 1),
080: new BHSDCodec(4, 8, 1, 1), new BHSDCodec(4, 16, 0, 1),
081: new BHSDCodec(4, 16, 1, 1), new BHSDCodec(4, 32, 0, 1),
082: new BHSDCodec(4, 32, 1, 1), new BHSDCodec(4, 64, 0, 1),
083: new BHSDCodec(4, 64, 1, 1), new BHSDCodec(4, 128, 0, 1),
084: new BHSDCodec(4, 128, 1, 1), new BHSDCodec(4, 192, 0, 1),
085: new BHSDCodec(4, 192, 1, 1), new BHSDCodec(4, 224, 0, 1),
086: new BHSDCodec(4, 224, 1, 1), new BHSDCodec(4, 240, 0, 1),
087: new BHSDCodec(4, 240, 1, 1), new BHSDCodec(4, 248, 0, 1),
088: new BHSDCodec(4, 248, 1, 1) };
089:
090: /**
091: * Returns the codec specified by the given value byte and optional byte header.
092: * If the value is >=116, then bytes may be consumed from the secondary input
093: * stream, which is taken to be the contents of the band_headers byte array.
094: * Since the values from this are consumed and not repeated, the input stream
095: * should be reused for subsequent encodings. This does not therefore close
096: * the input stream.
097: * @param value the canonical encoding value
098: * @param in the input stream to read additional byte headers from
099: * @param defaultCodec TODO
100: * @return the corresponding codec, or <code>null</code> if the default should be used
101: * @throws IOException
102: * @throws IOException if there is a problem reading from the input stream (which
103: * in reality, is never, since the band_headers are likely stored in a byte array
104: * and accessed via a ByteArrayInputStream. However, an EOFException could occur
105: * if things go wrong)
106: * @throws Pack200Exception
107: */
108: public static Codec getCodec(int value, InputStream in,
109: Codec defaultCodec) throws IOException, Pack200Exception {
110: // Sanity check to make sure that no-one has changed
111: // the canonical codecs, which would really cause havoc
112: if (canonicalCodec.length != 116)
113: throw new Error(
114: "Canonical encodings have been incorrectly modified");
115: if (value < 0) {
116: throw new IllegalArgumentException(
117: "Encoding cannot be less than zero");
118: } else if (value == 0) {
119: return defaultCodec;
120: } else if (value <= 115) {
121: return canonicalCodec[value];
122: } else if (value == 116) {
123: int code = in.read();
124: if (code == -1)
125: throw new EOFException(
126: "End of buffer read whilst trying to decode codec");
127: int d = (code & 0x01);
128: int s = (code >> 1 & 0x03);
129: int b = (code >> 3 & 0x07) + 1; // this might result in an invalid number, but it's checked in the Codec constructor
130: code = in.read();
131: if (code == -1)
132: throw new EOFException(
133: "End of buffer read whilst trying to decode codec");
134: int h = code + 1;
135: // This handles the special cases for invalid combinations of data.
136: return new BHSDCodec(b, h, s, d);
137: } else if (value >= 117 && value <= 140) { // Run codec
138: int offset = value - 117;
139: int kx = offset & 3;
140: boolean kbflag = (offset >> 2 & 1) == 1;
141: boolean adef = (offset >> 3 & 1) == 1;
142: boolean bdef = (offset >> 4 & 1) == 1;
143: // If both A and B use the default encoding, what's the point of having a run of default values followed by default values
144: if (adef && bdef)
145: throw new Pack200Exception(
146: "ADef and BDef should never both be true");
147: int kb = (kbflag ? in.read() : 3);
148: int k = (kb + 1) * (int) Math.pow(16, kx);
149: Codec aCodec, bCodec;
150: if (adef) {
151: aCodec = defaultCodec;
152: } else {
153: aCodec = getCodec(in.read(), in, defaultCodec);
154: }
155: if (bdef) {
156: bCodec = defaultCodec;
157: } else {
158: bCodec = getCodec(in.read(), in, defaultCodec);
159: }
160: return new RunCodec(k, aCodec, bCodec);
161: } else if (value >= 141 && value <= 188) { // Population Codec
162: int offset = value - 141;
163: boolean fdef = (offset & 1) == 1;
164: boolean udef = (offset >> 1 & 1) == 1;
165: int tdefl = offset >> 2;
166: boolean tdef = tdefl != 0;
167: // From section 6.7.3 of spec
168: final int[] tdefToL = { 0, 4, 8, 16, 32, 64, 128, 192, 224,
169: 240, 248, 252 };
170: int l = tdefToL[tdefl];
171: // NOTE: Do not re-factor this to bring out uCodec; the order in which
172: // they are read from the stream is important
173: if (tdef) {
174: Codec fCodec = (fdef ? defaultCodec : getCodec(in
175: .read(), in, defaultCodec));
176: Codec uCodec = (udef ? defaultCodec : getCodec(in
177: .read(), in, defaultCodec));
178: // Unfortunately, if tdef, then tCodec depends both on l and also on k, the
179: // number of items read from the fCodec. So we don't know in advance what
180: // the codec will be.
181: return new PopulationCodec(fCodec, l, uCodec);
182: } else {
183: Codec fCodec = (fdef ? defaultCodec : getCodec(in
184: .read(), in, defaultCodec));
185: Codec tCodec = getCodec(in.read(), in, defaultCodec);
186: Codec uCodec = (udef ? defaultCodec : getCodec(in
187: .read(), in, defaultCodec));
188: return new PopulationCodec(fCodec, tCodec, uCodec);
189: }
190: } else {
191: throw new Pack200Exception("Invalid codec encoding byte ("
192: + value + ") found");
193: }
194: }
195: }
|