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.unpack200;
018
019import java.io.IOException;
020import java.io.InputStream;
021import java.util.ArrayList;
022import java.util.Arrays;
023import java.util.HashMap;
024import java.util.Map;
025
026import org.apache.commons.compress.harmony.pack200.Codec;
027import org.apache.commons.compress.harmony.pack200.Pack200Exception;
028import org.apache.commons.compress.harmony.unpack200.bytecode.CPClass;
029import org.apache.commons.compress.harmony.unpack200.bytecode.CPDouble;
030import org.apache.commons.compress.harmony.unpack200.bytecode.CPFieldRef;
031import org.apache.commons.compress.harmony.unpack200.bytecode.CPFloat;
032import org.apache.commons.compress.harmony.unpack200.bytecode.CPInteger;
033import org.apache.commons.compress.harmony.unpack200.bytecode.CPInterfaceMethodRef;
034import org.apache.commons.compress.harmony.unpack200.bytecode.CPLong;
035import org.apache.commons.compress.harmony.unpack200.bytecode.CPMethodRef;
036import org.apache.commons.compress.harmony.unpack200.bytecode.CPNameAndType;
037import org.apache.commons.compress.harmony.unpack200.bytecode.CPString;
038import org.apache.commons.compress.harmony.unpack200.bytecode.CPUTF8;
039
040/**
041 * Constant Pool bands
042 */
043public class CpBands extends BandSet {
044
045    private final SegmentConstantPool pool = new SegmentConstantPool(this);
046
047    private String[] cpClass;
048
049    private int[] cpClassInts;
050    private int[] cpDescriptorNameInts;
051    private int[] cpDescriptorTypeInts;
052    private String[] cpDescriptor;
053    private double[] cpDouble;
054    private String[] cpFieldClass;
055    private String[] cpFieldDescriptor;
056    private int[] cpFieldClassInts;
057    private int[] cpFieldDescriptorInts;
058    private float[] cpFloat;
059    private String[] cpIMethodClass;
060    private String[] cpIMethodDescriptor;
061    private int[] cpIMethodClassInts;
062    private int[] cpIMethodDescriptorInts;
063    private int[] cpInt;
064    private long[] cpLong;
065    private String[] cpMethodClass;
066    private String[] cpMethodDescriptor;
067    private int[] cpMethodClassInts;
068    private int[] cpMethodDescriptorInts;
069    private String[] cpSignature;
070    private int[] cpSignatureInts;
071    private String[] cpString;
072    private int[] cpStringInts;
073    private String[] cpUTF8;
074    private final Map<String, CPUTF8> stringsToCPUTF8 = new HashMap<>();
075
076    private final Map<String, CPString> stringsToCPStrings = new HashMap<>();
077    private final Map<Long, CPLong> longsToCPLongs = new HashMap<>();
078    private final Map<Integer, CPInteger> integersToCPIntegers = new HashMap<>();
079    private final Map<Float, CPFloat> floatsToCPFloats = new HashMap<>();
080    private final Map<String, CPClass> stringsToCPClass = new HashMap<>();
081    private final Map<Double, CPDouble> doublesToCPDoubles = new HashMap<>();
082    private final Map<String, CPNameAndType> descriptorsToCPNameAndTypes = new HashMap<>();
083    private Map<String, Integer> mapClass;
084
085    private Map<String, Integer> mapDescriptor;
086    private Map<String, Integer> mapUTF8;
087    // TODO: Not used
088    private Map<String, Integer> mapSignature;
089
090    private int intOffset;
091
092    private int floatOffset;
093    private int longOffset;
094    private int doubleOffset;
095    private int stringOffset;
096    private int classOffset;
097    private int signatureOffset;
098    private int descrOffset;
099    private int fieldOffset;
100    private int methodOffset;
101    private int imethodOffset;
102    public CpBands(final Segment segment) {
103        super(segment);
104    }
105
106    public CPClass cpClassValue(final int index) {
107        final String string = cpClass[index];
108        final int utf8Index = cpClassInts[index];
109        final int globalIndex = classOffset + index;
110        CPClass cpString = stringsToCPClass.get(string);
111        if (cpString == null) {
112            cpString = new CPClass(cpUTF8Value(utf8Index), globalIndex);
113            stringsToCPClass.put(string, cpString);
114        }
115        return cpString;
116    }
117
118    public CPClass cpClassValue(final String string) {
119        CPClass cpString = stringsToCPClass.get(string);
120        if (cpString == null) {
121            final Integer index = mapClass.get(string);
122            if (index != null) {
123                return cpClassValue(index.intValue());
124            }
125            cpString = new CPClass(cpUTF8Value(string, false), -1);
126            stringsToCPClass.put(string, cpString);
127        }
128        return cpString;
129    }
130
131    public CPDouble cpDoubleValue(final int index) {
132        final Double dbl = Double.valueOf(cpDouble[index]);
133        CPDouble cpDouble = doublesToCPDoubles.get(dbl);
134        if (cpDouble == null) {
135            cpDouble = new CPDouble(dbl, index + doubleOffset);
136            doublesToCPDoubles.put(dbl, cpDouble);
137        }
138        return cpDouble;
139    }
140
141    public CPFieldRef cpFieldValue(final int index) {
142        return new CPFieldRef(cpClassValue(cpFieldClassInts[index]), cpNameAndTypeValue(cpFieldDescriptorInts[index]),
143            index + fieldOffset);
144    }
145
146    public CPFloat cpFloatValue(final int index) {
147        final Float f = Float.valueOf(cpFloat[index]);
148        CPFloat cpFloat = floatsToCPFloats.get(f);
149        if (cpFloat == null) {
150            cpFloat = new CPFloat(f, index + floatOffset);
151            floatsToCPFloats.put(f, cpFloat);
152        }
153        return cpFloat;
154    }
155
156    public CPInterfaceMethodRef cpIMethodValue(final int index) {
157        return new CPInterfaceMethodRef(cpClassValue(cpIMethodClassInts[index]),
158            cpNameAndTypeValue(cpIMethodDescriptorInts[index]), index + imethodOffset);
159    }
160
161    public CPInteger cpIntegerValue(final int index) {
162        final Integer i = Integer.valueOf(cpInt[index]);
163        CPInteger cpInteger = integersToCPIntegers.get(i);
164        if (cpInteger == null) {
165            cpInteger = new CPInteger(i, index + intOffset);
166            integersToCPIntegers.put(i, cpInteger);
167        }
168        return cpInteger;
169    }
170
171    public CPLong cpLongValue(final int index) {
172        final Long l = Long.valueOf(cpLong[index]);
173        CPLong cpLong = longsToCPLongs.get(l);
174        if (cpLong == null) {
175            cpLong = new CPLong(l, index + longOffset);
176            longsToCPLongs.put(l, cpLong);
177        }
178        return cpLong;
179    }
180
181    public CPMethodRef cpMethodValue(final int index) {
182        return new CPMethodRef(cpClassValue(cpMethodClassInts[index]),
183            cpNameAndTypeValue(cpMethodDescriptorInts[index]), index + methodOffset);
184    }
185
186    public CPNameAndType cpNameAndTypeValue(final int index) {
187        final String descriptor = cpDescriptor[index];
188        CPNameAndType cpNameAndType = descriptorsToCPNameAndTypes.get(descriptor);
189        if (cpNameAndType == null) {
190            final int nameIndex = cpDescriptorNameInts[index];
191            final int descriptorIndex = cpDescriptorTypeInts[index];
192
193            final CPUTF8 name = cpUTF8Value(nameIndex);
194            final CPUTF8 descriptorU = cpSignatureValue(descriptorIndex);
195            cpNameAndType = new CPNameAndType(name, descriptorU, index + descrOffset);
196            descriptorsToCPNameAndTypes.put(descriptor, cpNameAndType);
197        }
198        return cpNameAndType;
199    }
200
201    public CPNameAndType cpNameAndTypeValue(final String descriptor) {
202        CPNameAndType cpNameAndType = descriptorsToCPNameAndTypes.get(descriptor);
203        if (cpNameAndType == null) {
204            final Integer index = mapDescriptor.get(descriptor);
205            if (index != null) {
206                return cpNameAndTypeValue(index.intValue());
207            }
208            final int colon = descriptor.indexOf(':');
209            final String nameString = descriptor.substring(0, colon);
210            final String descriptorString = descriptor.substring(colon + 1);
211
212            final CPUTF8 name = cpUTF8Value(nameString, true);
213            final CPUTF8 descriptorU = cpUTF8Value(descriptorString, true);
214            cpNameAndType = new CPNameAndType(name, descriptorU, -1 + descrOffset);
215            descriptorsToCPNameAndTypes.put(descriptor, cpNameAndType);
216        }
217        return cpNameAndType;
218    }
219
220    public CPUTF8 cpSignatureValue(final int index) {
221        int globalIndex;
222        if (cpSignatureInts[index] != -1) {
223            globalIndex = cpSignatureInts[index];
224        } else {
225            globalIndex = index + signatureOffset;
226        }
227        final String string = cpSignature[index];
228        CPUTF8 cpUTF8 = stringsToCPUTF8.get(string);
229        if (cpUTF8 == null) {
230            cpUTF8 = new CPUTF8(string, globalIndex);
231            stringsToCPUTF8.put(string, cpUTF8);
232        }
233        return cpUTF8;
234    }
235
236    public CPString cpStringValue(final int index) {
237        final String string = cpString[index];
238        final int utf8Index = cpStringInts[index];
239        final int globalIndex = stringOffset + index;
240        CPString cpString = stringsToCPStrings.get(string);
241        if (cpString == null) {
242            cpString = new CPString(cpUTF8Value(utf8Index), globalIndex);
243            stringsToCPStrings.put(string, cpString);
244        }
245        return cpString;
246    }
247
248    public CPUTF8 cpUTF8Value(final int index) {
249        final String string = cpUTF8[index];
250        CPUTF8 cputf8 = stringsToCPUTF8.get(string);
251        if (cputf8 == null) {
252            cputf8 = new CPUTF8(string, index);
253            stringsToCPUTF8.put(string, cputf8);
254        } else if (cputf8.getGlobalIndex() > index) {
255            cputf8.setGlobalIndex(index);
256        }
257        return cputf8;
258    }
259
260    public CPUTF8 cpUTF8Value(final String string) {
261        return cpUTF8Value(string, true);
262    }
263
264    public CPUTF8 cpUTF8Value(final String string, final boolean searchForIndex) {
265        CPUTF8 cputf8 = stringsToCPUTF8.get(string);
266        if (cputf8 == null) {
267            Integer index = null;
268            if (searchForIndex) {
269                index = mapUTF8.get(string);
270            }
271            if (index != null) {
272                return cpUTF8Value(index.intValue());
273            }
274            if (searchForIndex) {
275                index = mapSignature.get(string);
276            }
277            if (index != null) {
278                return cpSignatureValue(index.intValue());
279            }
280            cputf8 = new CPUTF8(string, -1);
281            stringsToCPUTF8.put(string, cputf8);
282        }
283        return cputf8;
284    }
285
286    public SegmentConstantPool getConstantPool() {
287        return pool;
288    }
289
290    public String[] getCpClass() {
291        return cpClass;
292    }
293
294    public String[] getCpDescriptor() {
295        return cpDescriptor;
296    }
297
298    public int[] getCpDescriptorNameInts() {
299        return cpDescriptorNameInts;
300    }
301
302    public int[] getCpDescriptorTypeInts() {
303        return cpDescriptorTypeInts;
304    }
305
306    public String[] getCpFieldClass() {
307        return cpFieldClass;
308    }
309
310    public String[] getCpIMethodClass() {
311        return cpIMethodClass;
312    }
313
314    public int[] getCpInt() {
315        return cpInt;
316    }
317
318    public long[] getCpLong() {
319        return cpLong;
320    }
321
322    public String[] getCpMethodClass() {
323        return cpMethodClass;
324    }
325
326    public String[] getCpMethodDescriptor() {
327        return cpMethodDescriptor;
328    }
329
330    public String[] getCpSignature() {
331        return cpSignature;
332    }
333
334    public String[] getCpUTF8() {
335        return cpUTF8;
336    }
337
338    /**
339     * Parses the constant pool class names, using {@link #cpClassCount} to populate {@link #cpClass} from
340     * {@link #cpUTF8}.
341     *
342     * @param in the input stream to read from
343     * @throws IOException if a problem occurs during reading from the underlying stream
344     * @throws Pack200Exception if a problem occurs with an unexpected value or unsupported codec
345     */
346    private void parseCpClass(final InputStream in) throws IOException, Pack200Exception {
347        final int cpClassCount = header.getCpClassCount();
348        cpClassInts = decodeBandInt("cp_Class", in, Codec.UDELTA5, cpClassCount);
349        cpClass = new String[cpClassCount];
350        mapClass = new HashMap<>(cpClassCount);
351        for (int i = 0; i < cpClassCount; i++) {
352            cpClass[i] = cpUTF8[cpClassInts[i]];
353            mapClass.put(cpClass[i], Integer.valueOf(i));
354        }
355    }
356
357    /**
358     * Parses the constant pool descriptor definitions, using {@link #cpDescriptorCount} to populate
359     * {@link #cpDescriptor}. For ease of use, the cpDescriptor is stored as a string of the form <i>name:type</i>,
360     * largely to make it easier for representing field and method descriptors (e.g.
361     * {@code out:java.lang.PrintStream}) in a way that is compatible with passing String arrays.
362     *
363     * @param in the input stream to read from
364     * @throws IOException if a problem occurs during reading from the underlying stream
365     * @throws Pack200Exception if a problem occurs with an unexpected value or unsupported codec
366     */
367    private void parseCpDescriptor(final InputStream in) throws IOException, Pack200Exception {
368        final int cpDescriptorCount = header.getCpDescriptorCount();
369        cpDescriptorNameInts = decodeBandInt("cp_Descr_name", in, Codec.DELTA5, cpDescriptorCount);
370        cpDescriptorTypeInts = decodeBandInt("cp_Descr_type", in, Codec.UDELTA5, cpDescriptorCount);
371        final String[] cpDescriptorNames = getReferences(cpDescriptorNameInts, cpUTF8);
372        final String[] cpDescriptorTypes = getReferences(cpDescriptorTypeInts, cpSignature);
373        cpDescriptor = new String[cpDescriptorCount];
374        mapDescriptor = new HashMap<>(cpDescriptorCount);
375        for (int i = 0; i < cpDescriptorCount; i++) {
376            cpDescriptor[i] = cpDescriptorNames[i] + ":" + cpDescriptorTypes[i]; //$NON-NLS-1$
377            mapDescriptor.put(cpDescriptor[i], Integer.valueOf(i));
378        }
379    }
380
381    private void parseCpDouble(final InputStream in) throws IOException, Pack200Exception {
382        final int cpDoubleCount = header.getCpDoubleCount();
383        final long[] band = parseFlags("cp_Double", in, cpDoubleCount, Codec.UDELTA5, Codec.DELTA5);
384        cpDouble = new double[band.length];
385        Arrays.setAll(cpDouble, i -> Double.longBitsToDouble(band[i]));
386    }
387
388    /**
389     * Parses the constant pool field definitions, using {@link #cpFieldCount} to populate {@link #cpFieldClass} and
390     * {@link #cpFieldDescriptor}.
391     *
392     * @param in the input stream to read from
393     * @throws IOException if a problem occurs during reading from the underlying stream
394     * @throws Pack200Exception if a problem occurs with an unexpected value or unsupported codec
395     */
396    private void parseCpField(final InputStream in) throws IOException, Pack200Exception {
397        final int cpFieldCount = header.getCpFieldCount();
398        cpFieldClassInts = decodeBandInt("cp_Field_class", in, Codec.DELTA5, cpFieldCount);
399        cpFieldDescriptorInts = decodeBandInt("cp_Field_desc", in, Codec.UDELTA5, cpFieldCount);
400        cpFieldClass = new String[cpFieldCount];
401        cpFieldDescriptor = new String[cpFieldCount];
402        for (int i = 0; i < cpFieldCount; i++) {
403            cpFieldClass[i] = cpClass[cpFieldClassInts[i]];
404            cpFieldDescriptor[i] = cpDescriptor[cpFieldDescriptorInts[i]];
405        }
406    }
407
408    private void parseCpFloat(final InputStream in) throws IOException, Pack200Exception {
409        final int cpFloatCount = header.getCpFloatCount();
410        cpFloat = new float[cpFloatCount];
411        final int[] floatBits = decodeBandInt("cp_Float", in, Codec.UDELTA5, cpFloatCount);
412        for (int i = 0; i < cpFloatCount; i++) {
413            cpFloat[i] = Float.intBitsToFloat(floatBits[i]);
414        }
415    }
416
417    /**
418     * Parses the constant pool interface method definitions, using {@link #cpIMethodCount} to populate
419     * {@link #cpIMethodClass} and {@link #cpIMethodDescriptor}.
420     *
421     * @param in the input stream to read from
422     * @throws IOException if a problem occurs during reading from the underlying stream
423     * @throws Pack200Exception if a problem occurs with an unexpected value or unsupported codec
424     */
425    private void parseCpIMethod(final InputStream in) throws IOException, Pack200Exception {
426        final int cpIMethodCount = header.getCpIMethodCount();
427        cpIMethodClassInts = decodeBandInt("cp_Imethod_class", in, Codec.DELTA5, cpIMethodCount);
428        cpIMethodDescriptorInts = decodeBandInt("cp_Imethod_desc", in, Codec.UDELTA5, cpIMethodCount);
429        cpIMethodClass = new String[cpIMethodCount];
430        cpIMethodDescriptor = new String[cpIMethodCount];
431        for (int i = 0; i < cpIMethodCount; i++) {
432            cpIMethodClass[i] = cpClass[cpIMethodClassInts[i]];
433            cpIMethodDescriptor[i] = cpDescriptor[cpIMethodDescriptorInts[i]];
434        }
435    }
436
437    private void parseCpInt(final InputStream in) throws IOException, Pack200Exception {
438        final int cpIntCount = header.getCpIntCount();
439        cpInt = decodeBandInt("cpInt", in, Codec.UDELTA5, cpIntCount);
440    }
441
442    private void parseCpLong(final InputStream in) throws IOException, Pack200Exception {
443        final int cpLongCount = header.getCpLongCount();
444        cpLong = parseFlags("cp_Long", in, cpLongCount, Codec.UDELTA5, Codec.DELTA5);
445    }
446
447    /**
448     * Parses the constant pool method definitions, using {@link #cpMethodCount} to populate {@link #cpMethodClass} and
449     * {@link #cpMethodDescriptor}.
450     *
451     * @param in the input stream to read from
452     * @throws IOException if a problem occurs during reading from the underlying stream
453     * @throws Pack200Exception if a problem occurs with an unexpected value or unsupported codec
454     */
455    private void parseCpMethod(final InputStream in) throws IOException, Pack200Exception {
456        final int cpMethodCount = header.getCpMethodCount();
457        cpMethodClassInts = decodeBandInt("cp_Method_class", in, Codec.DELTA5, cpMethodCount);
458        cpMethodDescriptorInts = decodeBandInt("cp_Method_desc", in, Codec.UDELTA5, cpMethodCount);
459        cpMethodClass = new String[cpMethodCount];
460        cpMethodDescriptor = new String[cpMethodCount];
461        for (int i = 0; i < cpMethodCount; i++) {
462            cpMethodClass[i] = cpClass[cpMethodClassInts[i]];
463            cpMethodDescriptor[i] = cpDescriptor[cpMethodDescriptorInts[i]];
464        }
465    }
466
467    /**
468     * Parses the constant pool signature classes, using {@link #cpSignatureCount} to populate {@link #cpSignature}. A
469     * signature form is akin to the bytecode representation of a class; Z for boolean, I for int, [ for array etc.
470     * However, although classes are started with L, the classname does not follow the form; instead, there is a
471     * separate array of classes. So an array corresponding to {@code public static void main(String args[])} has a
472     * form of {@code [L(V)} and a classes array of {@code [java.lang.String]}. The {@link #cpSignature} is a
473     * string representation identical to the bytecode equivalent {@code [Ljava/lang/String;(V)} TODO Check that
474     * the form is as above and update other types e.g. J
475     *
476     * @param in the input stream to read from
477     * @throws IOException if a problem occurs during reading from the underlying stream
478     * @throws Pack200Exception if a problem occurs with an unexpected value or unsupported codec
479     */
480    private void parseCpSignature(final InputStream in) throws IOException, Pack200Exception {
481        final int cpSignatureCount = header.getCpSignatureCount();
482        cpSignatureInts = decodeBandInt("cp_Signature_form", in, Codec.DELTA5, cpSignatureCount);
483        final String[] cpSignatureForm = getReferences(cpSignatureInts, cpUTF8);
484        cpSignature = new String[cpSignatureCount];
485        mapSignature = new HashMap<>();
486        int lCount = 0;
487        for (int i = 0; i < cpSignatureCount; i++) {
488            final String form = cpSignatureForm[i];
489            final char[] chars = form.toCharArray();
490            for (final char element : chars) {
491                if (element == 'L') {
492                    cpSignatureInts[i] = -1;
493                    lCount++;
494                }
495            }
496        }
497        final String[] cpSignatureClasses = parseReferences("cp_Signature_classes", in, Codec.UDELTA5, lCount, cpClass);
498        int index = 0;
499        for (int i = 0; i < cpSignatureCount; i++) {
500            final String form = cpSignatureForm[i];
501            final int len = form.length();
502            final StringBuilder signature = new StringBuilder(64);
503            final ArrayList<String> list = new ArrayList<>();
504            for (int j = 0; j < len; j++) {
505                final char c = form.charAt(j);
506                signature.append(c);
507                if (c == 'L') {
508                    final String className = cpSignatureClasses[index];
509                    list.add(className);
510                    signature.append(className);
511                    index++;
512                }
513            }
514            cpSignature[i] = signature.toString();
515            mapSignature.put(signature.toString(), Integer.valueOf(i));
516        }
517//        for (int i = 0; i < cpSignatureInts.length; i++) {
518//            if (cpSignatureInts[i] == -1) {
519//                cpSignatureInts[i] = search(cpUTF8, cpSignature[i]);
520//            }
521//        }
522    }
523
524    /**
525     * Parses the constant pool strings, using {@link #cpStringCount} to populate {@link #cpString} from indexes into
526     * {@link #cpUTF8}.
527     *
528     * @param in the input stream to read from
529     * @throws IOException if a problem occurs during reading from the underlying stream
530     * @throws Pack200Exception if a problem occurs with an unexpected value or unsupported codec
531     */
532    private void parseCpString(final InputStream in) throws IOException, Pack200Exception {
533        final int cpStringCount = header.getCpStringCount();
534        cpStringInts = decodeBandInt("cp_String", in, Codec.UDELTA5, cpStringCount);
535        cpString = new String[cpStringCount];
536        Arrays.setAll(cpString, i -> cpUTF8[cpStringInts[i]]);
537    }
538
539    private void parseCpUtf8(final InputStream in) throws IOException, Pack200Exception {
540        final int cpUTF8Count = header.getCpUTF8Count();
541        cpUTF8 = new String[cpUTF8Count];
542        mapUTF8 = new HashMap<>(cpUTF8Count + 1);
543        cpUTF8[0] = ""; //$NON-NLS-1$
544        mapUTF8.put("", Integer.valueOf(0));
545        final int[] prefix = decodeBandInt("cpUTF8Prefix", in, Codec.DELTA5, cpUTF8Count - 2);
546        int charCount = 0;
547        int bigSuffixCount = 0;
548        final int[] suffix = decodeBandInt("cpUTF8Suffix", in, Codec.UNSIGNED5, cpUTF8Count - 1);
549
550        for (final int element : suffix) {
551            if (element == 0) {
552                bigSuffixCount++;
553            } else {
554                charCount += element;
555            }
556        }
557        final char[] data = new char[charCount];
558        final int[] dataBand = decodeBandInt("cp_Utf8_chars", in, Codec.CHAR3, charCount);
559        for (int i = 0; i < data.length; i++) {
560            data[i] = (char) dataBand[i];
561        }
562
563        // Read in the big suffix data
564        final int[] bigSuffixCounts = decodeBandInt("cp_Utf8_big_suffix", in, Codec.DELTA5, bigSuffixCount);
565        final int[][] bigSuffixDataBand = new int[bigSuffixCount][];
566        for (int i = 0; i < bigSuffixDataBand.length; i++) {
567            bigSuffixDataBand[i] = decodeBandInt("cp_Utf8_big_chars " + i, in, Codec.DELTA5, bigSuffixCounts[i]);
568        }
569
570        // Convert big suffix data to characters
571        final char[][] bigSuffixData = new char[bigSuffixCount][];
572        for (int i = 0; i < bigSuffixDataBand.length; i++) {
573            bigSuffixData[i] = new char[bigSuffixDataBand[i].length];
574            for (int j = 0; j < bigSuffixDataBand[i].length; j++) {
575                bigSuffixData[i][j] = (char) bigSuffixDataBand[i][j];
576            }
577        }
578        // Go through the strings
579        charCount = 0;
580        bigSuffixCount = 0;
581        for (int i = 1; i < cpUTF8Count; i++) {
582            final String lastString = cpUTF8[i - 1];
583            if (suffix[i - 1] == 0) {
584                // The big suffix stuff hasn't been tested, and I'll be
585                // surprised if it works first time w/o errors ...
586                cpUTF8[i] = lastString.substring(0, i > 1 ? prefix[i - 2] : 0)
587                    + new String(bigSuffixData[bigSuffixCount++]);
588                mapUTF8.put(cpUTF8[i], Integer.valueOf(i));
589            } else {
590                cpUTF8[i] = lastString.substring(0, i > 1 ? prefix[i - 2] : 0)
591                    + new String(data, charCount, suffix[i - 1]);
592                charCount += suffix[i - 1];
593                mapUTF8.put(cpUTF8[i], Integer.valueOf(i));
594            }
595        }
596    }
597
598    @Override
599    public void read(final InputStream in) throws IOException, Pack200Exception {
600        parseCpUtf8(in);
601        parseCpInt(in);
602        parseCpFloat(in);
603        parseCpLong(in);
604        parseCpDouble(in);
605        parseCpString(in);
606        parseCpClass(in);
607        parseCpSignature(in);
608        parseCpDescriptor(in);
609        parseCpField(in);
610        parseCpMethod(in);
611        parseCpIMethod(in);
612
613        intOffset = cpUTF8.length;
614        floatOffset = intOffset + cpInt.length;
615        longOffset = floatOffset + cpFloat.length;
616        doubleOffset = longOffset + cpLong.length;
617        stringOffset = doubleOffset + cpDouble.length;
618        classOffset = stringOffset + cpString.length;
619        signatureOffset = classOffset + cpClass.length;
620        descrOffset = signatureOffset + cpSignature.length;
621        fieldOffset = descrOffset + cpDescriptor.length;
622        methodOffset = fieldOffset + cpFieldClass.length;
623        imethodOffset = methodOffset + cpMethodClass.length;
624    }
625
626    @Override
627    public void unpack() {
628
629    }
630
631}