View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   https://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.commons.compress.harmony.unpack200;
20  
21  import java.io.IOException;
22  import java.io.InputStream;
23  import java.util.Arrays;
24  import java.util.HashMap;
25  import java.util.Map;
26  
27  import org.apache.commons.compress.harmony.pack200.Codec;
28  import org.apache.commons.compress.harmony.pack200.Pack200Exception;
29  import org.apache.commons.compress.harmony.unpack200.bytecode.CPClass;
30  import org.apache.commons.compress.harmony.unpack200.bytecode.CPDouble;
31  import org.apache.commons.compress.harmony.unpack200.bytecode.CPFieldRef;
32  import org.apache.commons.compress.harmony.unpack200.bytecode.CPFloat;
33  import org.apache.commons.compress.harmony.unpack200.bytecode.CPInteger;
34  import org.apache.commons.compress.harmony.unpack200.bytecode.CPInterfaceMethodRef;
35  import org.apache.commons.compress.harmony.unpack200.bytecode.CPLong;
36  import org.apache.commons.compress.harmony.unpack200.bytecode.CPMethodRef;
37  import org.apache.commons.compress.harmony.unpack200.bytecode.CPNameAndType;
38  import org.apache.commons.compress.harmony.unpack200.bytecode.CPString;
39  import org.apache.commons.compress.harmony.unpack200.bytecode.CPUTF8;
40  
41  /**
42   * Constant Pool bands.
43   */
44  public class CpBands extends BandSet {
45  
46      private static final String EMPTY_STRING = ""; //$NON-NLS-1$
47  
48      private final SegmentConstantPool pool = new SegmentConstantPool(this);
49  
50      private String[] cpClass;
51  
52      private int[] cpClassInts;
53      private int[] cpDescriptorNameInts;
54      private int[] cpDescriptorTypeInts;
55      private String[] cpDescriptor;
56      private double[] cpDouble;
57      private String[] cpFieldClass;
58      private String[] cpFieldDescriptor;
59      private int[] cpFieldClassInts;
60      private int[] cpFieldDescriptorInts;
61      private float[] cpFloat;
62      private String[] cpIMethodClass;
63      private String[] cpIMethodDescriptor;
64      private int[] cpIMethodClassInts;
65      private int[] cpIMethodDescriptorInts;
66      private int[] cpInt;
67      private long[] cpLong;
68      private String[] cpMethodClass;
69      private String[] cpMethodDescriptor;
70      private int[] cpMethodClassInts;
71      private int[] cpMethodDescriptorInts;
72      private String[] cpSignature;
73      private int[] cpSignatureInts;
74      private String[] cpString;
75      private int[] cpStringInts;
76      private String[] cpUTF8;
77      private final Map<String, CPUTF8> stringsToCPUTF8 = new HashMap<>();
78  
79      private final Map<String, CPString> stringsToCPStrings = new HashMap<>();
80      private final Map<Long, CPLong> longsToCPLongs = new HashMap<>();
81      private final Map<Integer, CPInteger> integersToCPIntegers = new HashMap<>();
82      private final Map<Float, CPFloat> floatsToCPFloats = new HashMap<>();
83      private final Map<String, CPClass> stringsToCPClass = new HashMap<>();
84      private final Map<Double, CPDouble> doublesToCPDoubles = new HashMap<>();
85      private final Map<String, CPNameAndType> descriptorsToCPNameAndTypes = new HashMap<>();
86      private Map<String, Integer> mapClass;
87  
88      private Map<String, Integer> mapDescriptor;
89      private Map<String, Integer> mapUTF8;
90      // TODO: Not used
91      private Map<String, Integer> mapSignature;
92  
93      private int intOffset;
94  
95      private int floatOffset;
96      private int longOffset;
97      private int doubleOffset;
98      private int stringOffset;
99      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 }