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