|
Java example source code file (PackageReader.java)
The PackageReader.java Java example source code/* * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package com.sun.java.util.jar.pack; import com.sun.java.util.jar.pack.ConstantPool.*; import com.sun.java.util.jar.pack.Package.Class; import com.sun.java.util.jar.pack.Package.File; import com.sun.java.util.jar.pack.Package.InnerClass; import java.io.ByteArrayOutputStream; import java.io.EOFException; import java.io.PrintStream; import java.io.FilterInputStream; import java.io.BufferedInputStream; import java.io.InputStream; import java.io.IOException; import java.util.ArrayList; import java.util.Map; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.HashSet; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.ListIterator; import java.util.Set; import static com.sun.java.util.jar.pack.Constants.*; /** * Reader for a package file. * * @see PackageWriter * @author John Rose */ class PackageReader extends BandStructure { Package pkg; byte[] bytes; LimitedBuffer in; Package.Version packageVersion; PackageReader(Package pkg, InputStream in) throws IOException { this.pkg = pkg; this.in = new LimitedBuffer(in); } /** A buffered input stream which is careful not to * read its underlying stream ahead of a given mark, * called the 'readLimit'. This property declares * the maximum number of characters that future reads * can consume from the underlying stream. */ static class LimitedBuffer extends BufferedInputStream { long served; // total number of charburgers served int servedPos; // ...as of this value of super.pos long limit; // current declared limit long buffered; public boolean atLimit() { boolean z = (getBytesServed() == limit); assert(!z || limit == buffered); return z; } public long getBytesServed() { return served + (pos - servedPos); } public void setReadLimit(long newLimit) { if (newLimit == -1) limit = -1; else limit = getBytesServed() + newLimit; } public long getReadLimit() { if (limit == -1) return limit; else return limit - getBytesServed(); } public int read() throws IOException { if (pos < count) { // fast path return buf[pos++] & 0xFF; } served += (pos - servedPos); int ch = super.read(); servedPos = pos; if (ch >= 0) served += 1; assert(served <= limit || limit == -1); return ch; } public int read(byte b[], int off, int len) throws IOException { served += (pos - servedPos); int nr = super.read(b, off, len); servedPos = pos; if (nr >= 0) served += nr; //assert(served <= limit || limit == -1); return nr; } public long skip(long n) throws IOException { throw new RuntimeException("no skipping"); } LimitedBuffer(InputStream originalIn) { super(null, 1<<14); servedPos = pos; super.in = new FilterInputStream(originalIn) { public int read() throws IOException { if (buffered == limit) return -1; ++buffered; return super.read(); } public int read(byte b[], int off, int len) throws IOException { if (buffered == limit) return -1; if (limit != -1) { long remaining = limit - buffered; if (len > remaining) len = (int)remaining; } int nr = super.read(b, off, len); if (nr >= 0) buffered += nr; return nr; } }; } } void read() throws IOException { boolean ok = false; try { // pack200_archive: // file_header // *band_headers :BYTE1 // cp_bands // attr_definition_bands // ic_bands // class_bands // bc_bands // file_bands readFileHeader(); readBandHeaders(); readConstantPool(); // cp_bands readAttrDefs(); readInnerClasses(); Class[] classes = readClasses(); readByteCodes(); readFiles(); // file_bands assert(archiveSize1 == 0 || in.atLimit()); assert(archiveSize1 == 0 || in.getBytesServed() == archiveSize0+archiveSize1); all_bands.doneDisbursing(); // As a post-pass, build constant pools and inner classes. for (int i = 0; i < classes.length; i++) { reconstructClass(classes[i]); } ok = true; } catch (Exception ee) { Utils.log.warning("Error on input: "+ee, ee); if (verbose > 0) Utils.log.info("Stream offsets:"+ " served="+in.getBytesServed()+ " buffered="+in.buffered+ " limit="+in.limit); //if (verbose > 0) ee.printStackTrace(); if (ee instanceof IOException) throw (IOException)ee; if (ee instanceof RuntimeException) throw (RuntimeException)ee; throw new Error("error unpacking", ee); } } // Temporary count values, until band decoding gets rolling. int[] tagCount = new int[CONSTANT_Limit]; int numFiles; int numAttrDefs; int numInnerClasses; int numClasses; void readFileHeader() throws IOException { // file_header: // archive_magic archive_header readArchiveMagic(); readArchiveHeader(); } // Local routine used to parse fixed-format scalars // in the file_header: private int getMagicInt32() throws IOException { int res = 0; for (int i = 0; i < 4; i++) { res <<= 8; res |= (archive_magic.getByte() & 0xFF); } return res; } final static int MAGIC_BYTES = 4; void readArchiveMagic() throws IOException { // Read a minimum of bytes in the first gulp. in.setReadLimit(MAGIC_BYTES + AH_LENGTH_MIN); // archive_magic: // #archive_magic_word :BYTE1[4] archive_magic.expectLength(MAGIC_BYTES); archive_magic.readFrom(in); // read and check magic numbers: int magic = getMagicInt32(); if (pkg.magic != magic) { throw new IOException("Unexpected package magic number: got " + magic + "; expected " + pkg.magic); } archive_magic.doneDisbursing(); } // Fixed 6211177, converted to throw IOException void checkArchiveVersion() throws IOException { Package.Version versionFound = null; for (Package.Version v : new Package.Version[] { JAVA8_PACKAGE_VERSION, JAVA7_PACKAGE_VERSION, JAVA6_PACKAGE_VERSION, JAVA5_PACKAGE_VERSION }) { if (packageVersion.equals(v)) { versionFound = v; break; } } if (versionFound == null) { String expVer = JAVA8_PACKAGE_VERSION.toString() + "OR" + JAVA7_PACKAGE_VERSION.toString() + " OR " + JAVA6_PACKAGE_VERSION.toString() + " OR " + JAVA5_PACKAGE_VERSION.toString(); throw new IOException("Unexpected package minor version: got " + packageVersion.toString() + "; expected " + expVer); } } void readArchiveHeader() throws IOException { // archive_header: // #archive_minver :UNSIGNED5[1] // #archive_majver :UNSIGNED5[1] // #archive_options :UNSIGNED5[1] // (archive_file_counts) ** (#have_file_headers) // (archive_special_counts) ** (#have_special_formats) // cp_counts // class_counts // // archive_file_counts: // #archive_size_hi :UNSIGNED5[1] // #archive_size_lo :UNSIGNED5[1] // #archive_next_count :UNSIGNED5[1] // #archive_modtime :UNSIGNED5[1] // #file_count :UNSIGNED5[1] // // class_counts: // #ic_count :UNSIGNED5[1] // #default_class_minver :UNSIGNED5[1] // #default_class_majver :UNSIGNED5[1] // #class_count :UNSIGNED5[1] // // archive_special_counts: // #band_headers_size :UNSIGNED5[1] // #attr_definition_count :UNSIGNED5[1] // archive_header_0.expectLength(AH_LENGTH_0); archive_header_0.readFrom(in); int minver = archive_header_0.getInt(); int majver = archive_header_0.getInt(); packageVersion = Package.Version.of(majver, minver); checkArchiveVersion(); this.initHighestClassVersion(JAVA7_MAX_CLASS_VERSION); archiveOptions = archive_header_0.getInt(); archive_header_0.doneDisbursing(); // detect archive optional fields in archive header boolean haveSpecial = testBit(archiveOptions, AO_HAVE_SPECIAL_FORMATS); boolean haveFiles = testBit(archiveOptions, AO_HAVE_FILE_HEADERS); boolean haveNumbers = testBit(archiveOptions, AO_HAVE_CP_NUMBERS); boolean haveCPExtra = testBit(archiveOptions, AO_HAVE_CP_EXTRAS); initAttrIndexLimit(); // now we are ready to use the data: archive_header_S.expectLength(haveFiles? AH_LENGTH_S: 0); archive_header_S.readFrom(in); if (haveFiles) { long sizeHi = archive_header_S.getInt(); long sizeLo = archive_header_S.getInt(); archiveSize1 = (sizeHi << 32) + ((sizeLo << 32) >>> 32); // Set the limit, now, up to the file_bits. in.setReadLimit(archiveSize1); // for debug only } else { archiveSize1 = 0; in.setReadLimit(-1); // remove limitation } archive_header_S.doneDisbursing(); archiveSize0 = in.getBytesServed(); int remainingHeaders = AH_LENGTH_MIN - AH_LENGTH_0 - AH_LENGTH_S; if (haveFiles) remainingHeaders += AH_FILE_HEADER_LEN; if (haveSpecial) remainingHeaders += AH_SPECIAL_FORMAT_LEN; if (haveNumbers) remainingHeaders += AH_CP_NUMBER_LEN; if (haveCPExtra) remainingHeaders += AH_CP_EXTRA_LEN; archive_header_1.expectLength(remainingHeaders); archive_header_1.readFrom(in); if (haveFiles) { archiveNextCount = archive_header_1.getInt(); pkg.default_modtime = archive_header_1.getInt(); numFiles = archive_header_1.getInt(); } else { archiveNextCount = 0; numFiles = 0; } if (haveSpecial) { band_headers.expectLength(archive_header_1.getInt()); numAttrDefs = archive_header_1.getInt(); } else { band_headers.expectLength(0); numAttrDefs = 0; } readConstantPoolCounts(haveNumbers, haveCPExtra); numInnerClasses = archive_header_1.getInt(); minver = (short) archive_header_1.getInt(); majver = (short) archive_header_1.getInt(); pkg.defaultClassVersion = Package.Version.of(majver, minver); numClasses = archive_header_1.getInt(); archive_header_1.doneDisbursing(); // set some derived archive bits if (testBit(archiveOptions, AO_DEFLATE_HINT)) { pkg.default_options |= FO_DEFLATE_HINT; } } void readBandHeaders() throws IOException { band_headers.readFrom(in); bandHeaderBytePos = 1; // Leave room to pushback the initial XB byte. bandHeaderBytes = new byte[bandHeaderBytePos + band_headers.length()]; for (int i = bandHeaderBytePos; i < bandHeaderBytes.length; i++) { bandHeaderBytes[i] = (byte) band_headers.getByte(); } band_headers.doneDisbursing(); } void readConstantPoolCounts(boolean haveNumbers, boolean haveCPExtra) throws IOException { // size the constant pools: for (int k = 0; k < ConstantPool.TAGS_IN_ORDER.length; k++) { // cp_counts: // #cp_Utf8_count :UNSIGNED5[1] // (cp_number_counts) ** (#have_cp_numbers) // #cp_String_count :UNSIGNED5[1] // #cp_Class_count :UNSIGNED5[1] // #cp_Signature_count :UNSIGNED5[1] // #cp_Descr_count :UNSIGNED5[1] // #cp_Field_count :UNSIGNED5[1] // #cp_Method_count :UNSIGNED5[1] // #cp_Imethod_count :UNSIGNED5[1] // (cp_attr_counts) ** (#have_cp_attr_counts) // // cp_number_counts: // #cp_Int_count :UNSIGNED5[1] // #cp_Float_count :UNSIGNED5[1] // #cp_Long_count :UNSIGNED5[1] // #cp_Double_count :UNSIGNED5[1] // // cp_extra_counts: // #cp_MethodHandle_count :UNSIGNED5[1] // #cp_MethodType_count :UNSIGNED5[1] // #cp_InvokeDynamic_count :UNSIGNED5[1] // #cp_BootstrapMethod_count :UNSIGNED5[1] // byte tag = ConstantPool.TAGS_IN_ORDER[k]; if (!haveNumbers) { // These four counts are optional. switch (tag) { case CONSTANT_Integer: case CONSTANT_Float: case CONSTANT_Long: case CONSTANT_Double: continue; } } if (!haveCPExtra) { // These four counts are optional. switch (tag) { case CONSTANT_MethodHandle: case CONSTANT_MethodType: case CONSTANT_InvokeDynamic: case CONSTANT_BootstrapMethod: continue; } } tagCount[tag] = archive_header_1.getInt(); } } protected Index getCPIndex(byte tag) { return pkg.cp.getIndexByTag(tag); } Index initCPIndex(byte tag, Entry[] cpMap) { if (verbose > 3) { for (int i = 0; i < cpMap.length; i++) { Utils.log.fine("cp.add "+cpMap[i]); } } Index index = ConstantPool.makeIndex(ConstantPool.tagName(tag), cpMap); if (verbose > 1) Utils.log.fine("Read "+index); pkg.cp.initIndexByTag(tag, index); return index; } void checkLegacy(String bandname) { if (packageVersion.lessThan(JAVA7_PACKAGE_VERSION)) { throw new RuntimeException("unexpected band " + bandname); } } void readConstantPool() throws IOException { // cp_bands: // cp_Utf8 // *cp_Int :UDELTA5 // *cp_Float :UDELTA5 // cp_Long // cp_Double // *cp_String :UDELTA5 (cp_Utf8) // *cp_Class :UDELTA5 (cp_Utf8) // cp_Signature // cp_Descr // cp_Field // cp_Method // cp_Imethod if (verbose > 0) Utils.log.info("Reading CP"); for (int k = 0; k < ConstantPool.TAGS_IN_ORDER.length; k++) { byte tag = ConstantPool.TAGS_IN_ORDER[k]; int len = tagCount[tag]; Entry[] cpMap = new Entry[len]; if (verbose > 0) Utils.log.info("Reading "+cpMap.length+" "+ConstantPool.tagName(tag)+" entries..."); switch (tag) { case CONSTANT_Utf8: readUtf8Bands(cpMap); break; case CONSTANT_Integer: cp_Int.expectLength(cpMap.length); cp_Int.readFrom(in); for (int i = 0; i < cpMap.length; i++) { int x = cp_Int.getInt(); // coding handles signs OK cpMap[i] = ConstantPool.getLiteralEntry(x); } cp_Int.doneDisbursing(); break; case CONSTANT_Float: cp_Float.expectLength(cpMap.length); cp_Float.readFrom(in); for (int i = 0; i < cpMap.length; i++) { int x = cp_Float.getInt(); float fx = Float.intBitsToFloat(x); cpMap[i] = ConstantPool.getLiteralEntry(fx); } cp_Float.doneDisbursing(); break; case CONSTANT_Long: // cp_Long: // *cp_Long_hi :UDELTA5 // *cp_Long_lo :DELTA5 cp_Long_hi.expectLength(cpMap.length); cp_Long_hi.readFrom(in); cp_Long_lo.expectLength(cpMap.length); cp_Long_lo.readFrom(in); for (int i = 0; i < cpMap.length; i++) { long hi = cp_Long_hi.getInt(); long lo = cp_Long_lo.getInt(); long x = (hi << 32) + ((lo << 32) >>> 32); cpMap[i] = ConstantPool.getLiteralEntry(x); } cp_Long_hi.doneDisbursing(); cp_Long_lo.doneDisbursing(); break; case CONSTANT_Double: // cp_Double: // *cp_Double_hi :UDELTA5 // *cp_Double_lo :DELTA5 cp_Double_hi.expectLength(cpMap.length); cp_Double_hi.readFrom(in); cp_Double_lo.expectLength(cpMap.length); cp_Double_lo.readFrom(in); for (int i = 0; i < cpMap.length; i++) { long hi = cp_Double_hi.getInt(); long lo = cp_Double_lo.getInt(); long x = (hi << 32) + ((lo << 32) >>> 32); double dx = Double.longBitsToDouble(x); cpMap[i] = ConstantPool.getLiteralEntry(dx); } cp_Double_hi.doneDisbursing(); cp_Double_lo.doneDisbursing(); break; case CONSTANT_String: cp_String.expectLength(cpMap.length); cp_String.readFrom(in); cp_String.setIndex(getCPIndex(CONSTANT_Utf8)); for (int i = 0; i < cpMap.length; i++) { cpMap[i] = ConstantPool.getLiteralEntry(cp_String.getRef().stringValue()); } cp_String.doneDisbursing(); break; case CONSTANT_Class: cp_Class.expectLength(cpMap.length); cp_Class.readFrom(in); cp_Class.setIndex(getCPIndex(CONSTANT_Utf8)); for (int i = 0; i < cpMap.length; i++) { cpMap[i] = ConstantPool.getClassEntry(cp_Class.getRef().stringValue()); } cp_Class.doneDisbursing(); break; case CONSTANT_Signature: readSignatureBands(cpMap); break; case CONSTANT_NameandType: // cp_Descr: // *cp_Descr_type :DELTA5 (cp_Signature) // *cp_Descr_name :UDELTA5 (cp_Utf8) cp_Descr_name.expectLength(cpMap.length); cp_Descr_name.readFrom(in); cp_Descr_name.setIndex(getCPIndex(CONSTANT_Utf8)); cp_Descr_type.expectLength(cpMap.length); cp_Descr_type.readFrom(in); cp_Descr_type.setIndex(getCPIndex(CONSTANT_Signature)); for (int i = 0; i < cpMap.length; i++) { Entry ref = cp_Descr_name.getRef(); Entry ref2 = cp_Descr_type.getRef(); cpMap[i] = ConstantPool.getDescriptorEntry((Utf8Entry)ref, (SignatureEntry)ref2); } cp_Descr_name.doneDisbursing(); cp_Descr_type.doneDisbursing(); break; case CONSTANT_Fieldref: readMemberRefs(tag, cpMap, cp_Field_class, cp_Field_desc); break; case CONSTANT_Methodref: readMemberRefs(tag, cpMap, cp_Method_class, cp_Method_desc); break; case CONSTANT_InterfaceMethodref: readMemberRefs(tag, cpMap, cp_Imethod_class, cp_Imethod_desc); break; case CONSTANT_MethodHandle: if (cpMap.length > 0) { checkLegacy(cp_MethodHandle_refkind.name()); } cp_MethodHandle_refkind.expectLength(cpMap.length); cp_MethodHandle_refkind.readFrom(in); cp_MethodHandle_member.expectLength(cpMap.length); cp_MethodHandle_member.readFrom(in); cp_MethodHandle_member.setIndex(getCPIndex(CONSTANT_AnyMember)); for (int i = 0; i < cpMap.length; i++) { byte refKind = (byte) cp_MethodHandle_refkind.getInt(); MemberEntry memRef = (MemberEntry) cp_MethodHandle_member.getRef(); cpMap[i] = ConstantPool.getMethodHandleEntry(refKind, memRef); } cp_MethodHandle_refkind.doneDisbursing(); cp_MethodHandle_member.doneDisbursing(); break; case CONSTANT_MethodType: if (cpMap.length > 0) { checkLegacy(cp_MethodType.name()); } cp_MethodType.expectLength(cpMap.length); cp_MethodType.readFrom(in); cp_MethodType.setIndex(getCPIndex(CONSTANT_Signature)); for (int i = 0; i < cpMap.length; i++) { SignatureEntry typeRef = (SignatureEntry) cp_MethodType.getRef(); cpMap[i] = ConstantPool.getMethodTypeEntry(typeRef); } cp_MethodType.doneDisbursing(); break; case CONSTANT_InvokeDynamic: if (cpMap.length > 0) { checkLegacy(cp_InvokeDynamic_spec.name()); } cp_InvokeDynamic_spec.expectLength(cpMap.length); cp_InvokeDynamic_spec.readFrom(in); cp_InvokeDynamic_spec.setIndex(getCPIndex(CONSTANT_BootstrapMethod)); cp_InvokeDynamic_desc.expectLength(cpMap.length); cp_InvokeDynamic_desc.readFrom(in); cp_InvokeDynamic_desc.setIndex(getCPIndex(CONSTANT_NameandType)); for (int i = 0; i < cpMap.length; i++) { BootstrapMethodEntry bss = (BootstrapMethodEntry) cp_InvokeDynamic_spec.getRef(); DescriptorEntry descr = (DescriptorEntry) cp_InvokeDynamic_desc.getRef(); cpMap[i] = ConstantPool.getInvokeDynamicEntry(bss, descr); } cp_InvokeDynamic_spec.doneDisbursing(); cp_InvokeDynamic_desc.doneDisbursing(); break; case CONSTANT_BootstrapMethod: if (cpMap.length > 0) { checkLegacy(cp_BootstrapMethod_ref.name()); } cp_BootstrapMethod_ref.expectLength(cpMap.length); cp_BootstrapMethod_ref.readFrom(in); cp_BootstrapMethod_ref.setIndex(getCPIndex(CONSTANT_MethodHandle)); cp_BootstrapMethod_arg_count.expectLength(cpMap.length); cp_BootstrapMethod_arg_count.readFrom(in); int totalArgCount = cp_BootstrapMethod_arg_count.getIntTotal(); cp_BootstrapMethod_arg.expectLength(totalArgCount); cp_BootstrapMethod_arg.readFrom(in); cp_BootstrapMethod_arg.setIndex(getCPIndex(CONSTANT_LoadableValue)); for (int i = 0; i < cpMap.length; i++) { MethodHandleEntry bsm = (MethodHandleEntry) cp_BootstrapMethod_ref.getRef(); int argc = cp_BootstrapMethod_arg_count.getInt(); Entry[] argRefs = new Entry[argc]; for (int j = 0; j < argc; j++) { argRefs[j] = cp_BootstrapMethod_arg.getRef(); } cpMap[i] = ConstantPool.getBootstrapMethodEntry(bsm, argRefs); } cp_BootstrapMethod_ref.doneDisbursing(); cp_BootstrapMethod_arg_count.doneDisbursing(); cp_BootstrapMethod_arg.doneDisbursing(); break; default: throw new AssertionError("unexpected CP tag in package"); } Index index = initCPIndex(tag, cpMap); if (optDumpBands) { try (PrintStream ps = new PrintStream(getDumpStream(index, ".idx"))) { printArrayTo(ps, index.cpMap, 0, index.cpMap.length); } } } cp_bands.doneDisbursing(); if (optDumpBands || verbose > 1) { for (byte tag = CONSTANT_GroupFirst; tag < CONSTANT_GroupLimit; tag++) { Index index = pkg.cp.getIndexByTag(tag); if (index == null || index.isEmpty()) continue; Entry[] cpMap = index.cpMap; if (verbose > 1) Utils.log.info("Index group "+ConstantPool.tagName(tag)+" contains "+cpMap.length+" entries."); if (optDumpBands) { try (PrintStream ps = new PrintStream(getDumpStream(index.debugName, tag, ".gidx", index))) { printArrayTo(ps, cpMap, 0, cpMap.length, true); } } } } setBandIndexes(); } void readUtf8Bands(Entry[] cpMap) throws IOException { // cp_Utf8: // *cp_Utf8_prefix :DELTA5 // *cp_Utf8_suffix :UNSIGNED5 // *cp_Utf8_chars :CHAR3 // *cp_Utf8_big_suffix :DELTA5 // (*cp_Utf8_big_chars :DELTA5) // ** length(cp_Utf8_big_suffix) int len = cpMap.length; if (len == 0) return; // nothing to read // Bands have implicit leading zeroes, for the empty string: final int SUFFIX_SKIP_1 = 1; final int PREFIX_SKIP_2 = 2; // First band: Read lengths of shared prefixes. cp_Utf8_prefix.expectLength(Math.max(0, len - PREFIX_SKIP_2)); cp_Utf8_prefix.readFrom(in); // Second band: Read lengths of unshared suffixes: cp_Utf8_suffix.expectLength(Math.max(0, len - SUFFIX_SKIP_1)); cp_Utf8_suffix.readFrom(in); char[][] suffixChars = new char[len][]; int bigSuffixCount = 0; // Third band: Read the char values in the unshared suffixes: cp_Utf8_chars.expectLength(cp_Utf8_suffix.getIntTotal()); cp_Utf8_chars.readFrom(in); for (int i = 0; i < len; i++) { int suffix = (i < SUFFIX_SKIP_1)? 0: cp_Utf8_suffix.getInt(); if (suffix == 0 && i >= SUFFIX_SKIP_1) { // chars are packed in cp_Utf8_big_chars bigSuffixCount += 1; continue; } suffixChars[i] = new char[suffix]; for (int j = 0; j < suffix; j++) { int ch = cp_Utf8_chars.getInt(); assert(ch == (char)ch); suffixChars[i][j] = (char)ch; } } cp_Utf8_chars.doneDisbursing(); // Fourth band: Go back and size the specially packed strings. int maxChars = 0; cp_Utf8_big_suffix.expectLength(bigSuffixCount); cp_Utf8_big_suffix.readFrom(in); cp_Utf8_suffix.resetForSecondPass(); for (int i = 0; i < len; i++) { int suffix = (i < SUFFIX_SKIP_1)? 0: cp_Utf8_suffix.getInt(); int prefix = (i < PREFIX_SKIP_2)? 0: cp_Utf8_prefix.getInt(); if (suffix == 0 && i >= SUFFIX_SKIP_1) { assert(suffixChars[i] == null); suffix = cp_Utf8_big_suffix.getInt(); } else { assert(suffixChars[i] != null); } if (maxChars < prefix + suffix) maxChars = prefix + suffix; } char[] buf = new char[maxChars]; // Fifth band(s): Get the specially packed characters. cp_Utf8_suffix.resetForSecondPass(); cp_Utf8_big_suffix.resetForSecondPass(); for (int i = 0; i < len; i++) { if (i < SUFFIX_SKIP_1) continue; int suffix = cp_Utf8_suffix.getInt(); if (suffix != 0) continue; // already input suffix = cp_Utf8_big_suffix.getInt(); suffixChars[i] = new char[suffix]; if (suffix == 0) { // Do not bother to add an empty "(Utf8_big_0)" band. continue; } IntBand packed = cp_Utf8_big_chars.newIntBand("(Utf8_big_"+i+")"); packed.expectLength(suffix); packed.readFrom(in); for (int j = 0; j < suffix; j++) { int ch = packed.getInt(); assert(ch == (char)ch); suffixChars[i][j] = (char)ch; } packed.doneDisbursing(); } cp_Utf8_big_chars.doneDisbursing(); // Finally, sew together all the prefixes and suffixes. cp_Utf8_prefix.resetForSecondPass(); cp_Utf8_suffix.resetForSecondPass(); cp_Utf8_big_suffix.resetForSecondPass(); for (int i = 0; i < len; i++) { int prefix = (i < PREFIX_SKIP_2)? 0: cp_Utf8_prefix.getInt(); int suffix = (i < SUFFIX_SKIP_1)? 0: cp_Utf8_suffix.getInt(); if (suffix == 0 && i >= SUFFIX_SKIP_1) suffix = cp_Utf8_big_suffix.getInt(); // by induction, the buffer is already filled with the prefix System.arraycopy(suffixChars[i], 0, buf, prefix, suffix); cpMap[i] = ConstantPool.getUtf8Entry(new String(buf, 0, prefix+suffix)); } cp_Utf8_prefix.doneDisbursing(); cp_Utf8_suffix.doneDisbursing(); cp_Utf8_big_suffix.doneDisbursing(); } Map<Utf8Entry, SignatureEntry> utf8Signatures; void readSignatureBands(Entry[] cpMap) throws IOException { // cp_Signature: // *cp_Signature_form :DELTA5 (cp_Utf8) // *cp_Signature_classes :UDELTA5 (cp_Class) cp_Signature_form.expectLength(cpMap.length); cp_Signature_form.readFrom(in); cp_Signature_form.setIndex(getCPIndex(CONSTANT_Utf8)); int[] numSigClasses = new int[cpMap.length]; for (int i = 0; i < cpMap.length; i++) { Utf8Entry formRef = (Utf8Entry) cp_Signature_form.getRef(); numSigClasses[i] = ConstantPool.countClassParts(formRef); } cp_Signature_form.resetForSecondPass(); cp_Signature_classes.expectLength(getIntTotal(numSigClasses)); cp_Signature_classes.readFrom(in); cp_Signature_classes.setIndex(getCPIndex(CONSTANT_Class)); utf8Signatures = new HashMap<>(); for (int i = 0; i < cpMap.length; i++) { Utf8Entry formRef = (Utf8Entry) cp_Signature_form.getRef(); ClassEntry[] classRefs = new ClassEntry[numSigClasses[i]]; for (int j = 0; j < classRefs.length; j++) { classRefs[j] = (ClassEntry) cp_Signature_classes.getRef(); } SignatureEntry se = ConstantPool.getSignatureEntry(formRef, classRefs); cpMap[i] = se; utf8Signatures.put(se.asUtf8Entry(), se); } cp_Signature_form.doneDisbursing(); cp_Signature_classes.doneDisbursing(); } void readMemberRefs(byte tag, Entry[] cpMap, CPRefBand cp_class, CPRefBand cp_desc) throws IOException { // cp_Field: // *cp_Field_class :DELTA5 (cp_Class) // *cp_Field_desc :UDELTA5 (cp_Descr) // cp_Method: // *cp_Method_class :DELTA5 (cp_Class) // *cp_Method_desc :UDELTA5 (cp_Descr) // cp_Imethod: // *cp_Imethod_class :DELTA5 (cp_Class) // *cp_Imethod_desc :UDELTA5 (cp_Descr) cp_class.expectLength(cpMap.length); cp_class.readFrom(in); cp_class.setIndex(getCPIndex(CONSTANT_Class)); cp_desc.expectLength(cpMap.length); cp_desc.readFrom(in); cp_desc.setIndex(getCPIndex(CONSTANT_NameandType)); for (int i = 0; i < cpMap.length; i++) { ClassEntry mclass = (ClassEntry ) cp_class.getRef(); DescriptorEntry mdescr = (DescriptorEntry) cp_desc.getRef(); cpMap[i] = ConstantPool.getMemberEntry(tag, mclass, mdescr); } cp_class.doneDisbursing(); cp_desc.doneDisbursing(); } void readFiles() throws IOException { // file_bands: // *file_name :UNSIGNED5 (cp_Utf8) // *file_size_hi :UNSIGNED5 // *file_size_lo :UNSIGNED5 // *file_modtime :DELTA5 // *file_options :UNSIGNED5 // *file_bits :BYTE1 if (verbose > 0) Utils.log.info(" ...building "+numFiles+" files..."); file_name.expectLength(numFiles); file_size_lo.expectLength(numFiles); int options = archiveOptions; boolean haveSizeHi = testBit(options, AO_HAVE_FILE_SIZE_HI); boolean haveModtime = testBit(options, AO_HAVE_FILE_MODTIME); boolean haveOptions = testBit(options, AO_HAVE_FILE_OPTIONS); if (haveSizeHi) file_size_hi.expectLength(numFiles); if (haveModtime) file_modtime.expectLength(numFiles); if (haveOptions) file_options.expectLength(numFiles); file_name.readFrom(in); file_size_hi.readFrom(in); file_size_lo.readFrom(in); file_modtime.readFrom(in); file_options.readFrom(in); file_bits.setInputStreamFrom(in); Iterator<Class> nextClass = pkg.getClasses().iterator(); // Compute file lengths before reading any file bits. long totalFileLength = 0; long[] fileLengths = new long[numFiles]; for (int i = 0; i < numFiles; i++) { long size = ((long)file_size_lo.getInt() << 32) >>> 32; if (haveSizeHi) size += (long)file_size_hi.getInt() << 32; fileLengths[i] = size; totalFileLength += size; } assert(in.getReadLimit() == -1 || in.getReadLimit() == totalFileLength); byte[] buf = new byte[1<<16]; for (int i = 0; i < numFiles; i++) { // %%% Use a big temp file for file bits? Utf8Entry name = (Utf8Entry) file_name.getRef(); long size = fileLengths[i]; File file = pkg.new File(name); file.modtime = pkg.default_modtime; file.options = pkg.default_options; if (haveModtime) file.modtime += file_modtime.getInt(); if (haveOptions) file.options |= file_options.getInt(); if (verbose > 1) Utils.log.fine("Reading "+size+" bytes of "+name.stringValue()); long toRead = size; while (toRead > 0) { int nr = buf.length; if (nr > toRead) nr = (int) toRead; nr = file_bits.getInputStream().read(buf, 0, nr); if (nr < 0) throw new EOFException(); file.addBytes(buf, 0, nr); toRead -= nr; } pkg.addFile(file); if (file.isClassStub()) { assert(file.getFileLength() == 0); Class cls = nextClass.next(); cls.initFile(file); } } // Do the rest of the classes. while (nextClass.hasNext()) { Class cls = nextClass.next(); cls.initFile(null); // implicitly initialize to a trivial one cls.file.modtime = pkg.default_modtime; } file_name.doneDisbursing(); file_size_hi.doneDisbursing(); file_size_lo.doneDisbursing(); file_modtime.doneDisbursing(); file_options.doneDisbursing(); file_bits.doneDisbursing(); file_bands.doneDisbursing(); if (archiveSize1 != 0 && !in.atLimit()) { throw new RuntimeException("Predicted archive_size "+ archiveSize1+" != "+ (in.getBytesServed()-archiveSize0)); } } void readAttrDefs() throws IOException { // attr_definition_bands: // *attr_definition_headers :BYTE1 // *attr_definition_name :UNSIGNED5 (cp_Utf8) // *attr_definition_layout :UNSIGNED5 (cp_Utf8) attr_definition_headers.expectLength(numAttrDefs); attr_definition_name.expectLength(numAttrDefs); attr_definition_layout.expectLength(numAttrDefs); attr_definition_headers.readFrom(in); attr_definition_name.readFrom(in); attr_definition_layout.readFrom(in); try (PrintStream dump = !optDumpBands ? null : new PrintStream(getDumpStream(attr_definition_headers, ".def"))) { for (int i = 0; i < numAttrDefs; i++) { int header = attr_definition_headers.getByte(); Utf8Entry name = (Utf8Entry) attr_definition_name.getRef(); Utf8Entry layout = (Utf8Entry) attr_definition_layout.getRef(); int ctype = (header & ADH_CONTEXT_MASK); int index = (header >> ADH_BIT_SHIFT) - ADH_BIT_IS_LSB; Attribute.Layout def = new Attribute.Layout(ctype, name.stringValue(), layout.stringValue()); // Check layout string for Java 6 extensions. String pvLayout = def.layoutForClassVersion(getHighestClassVersion()); if (!pvLayout.equals(def.layout())) { throw new IOException("Bad attribute layout in archive: "+def.layout()); } this.setAttributeLayoutIndex(def, index); if (dump != null) dump.println(index+" "+def); } } attr_definition_headers.doneDisbursing(); attr_definition_name.doneDisbursing(); attr_definition_layout.doneDisbursing(); // Attribute layouts define bands, one per layout element. // Create them now, all at once. makeNewAttributeBands(); attr_definition_bands.doneDisbursing(); } void readInnerClasses() throws IOException { // ic_bands: // *ic_this_class :UDELTA5 (cp_Class) // *ic_flags :UNSIGNED5 // *ic_outer_class :DELTA5 (null or cp_Class) // *ic_name :DELTA5 (null or cp_Utf8) ic_this_class.expectLength(numInnerClasses); ic_this_class.readFrom(in); ic_flags.expectLength(numInnerClasses); ic_flags.readFrom(in); int longICCount = 0; for (int i = 0; i < numInnerClasses; i++) { int flags = ic_flags.getInt(); boolean longForm = (flags & ACC_IC_LONG_FORM) != 0; if (longForm) { longICCount += 1; } } ic_outer_class.expectLength(longICCount); ic_outer_class.readFrom(in); ic_name.expectLength(longICCount); ic_name.readFrom(in); ic_flags.resetForSecondPass(); List<InnerClass> icList = new ArrayList<>(numInnerClasses); for (int i = 0; i < numInnerClasses; i++) { int flags = ic_flags.getInt(); boolean longForm = (flags & ACC_IC_LONG_FORM) != 0; flags &= ~ACC_IC_LONG_FORM; ClassEntry thisClass = (ClassEntry) ic_this_class.getRef(); ClassEntry outerClass; Utf8Entry thisName; if (longForm) { outerClass = (ClassEntry) ic_outer_class.getRef(); thisName = (Utf8Entry) ic_name.getRef(); } else { String n = thisClass.stringValue(); String[] parse = Package.parseInnerClassName(n); assert(parse != null); String pkgOuter = parse[0]; //String number = parse[1]; String name = parse[2]; if (pkgOuter == null) outerClass = null; else outerClass = ConstantPool.getClassEntry(pkgOuter); if (name == null) thisName = null; else thisName = ConstantPool.getUtf8Entry(name); } InnerClass ic = new InnerClass(thisClass, outerClass, thisName, flags); assert(longForm || ic.predictable); icList.add(ic); } ic_flags.doneDisbursing(); ic_this_class.doneDisbursing(); ic_outer_class.doneDisbursing(); ic_name.doneDisbursing(); pkg.setAllInnerClasses(icList); ic_bands.doneDisbursing(); } void readLocalInnerClasses(Class cls) throws IOException { int nc = class_InnerClasses_N.getInt(); List<InnerClass> localICs = new ArrayList<>(nc); for (int i = 0; i < nc; i++) { ClassEntry thisClass = (ClassEntry) class_InnerClasses_RC.getRef(); int flags = class_InnerClasses_F.getInt(); if (flags == 0) { // A zero flag means copy a global IC here. InnerClass ic = pkg.getGlobalInnerClass(thisClass); assert(ic != null); // must be a valid global IC reference localICs.add(ic); } else { if (flags == ACC_IC_LONG_FORM) flags = 0; // clear the marker bit ClassEntry outer = (ClassEntry) class_InnerClasses_outer_RCN.getRef(); Utf8Entry name = (Utf8Entry) class_InnerClasses_name_RUN.getRef(); localICs.add(new InnerClass(thisClass, outer, name, flags)); } } cls.setInnerClasses(localICs); // cls.expandLocalICs may add more tuples to ics also, // or may even delete tuples. // We cannot do that now, because we do not know the // full contents of the local constant pool yet. } static final int NO_FLAGS_YET = 0; // placeholder for later flag read-in Class[] readClasses() throws IOException { // class_bands: // *class_this :DELTA5 (cp_Class) // *class_super :DELTA5 (cp_Class) // *class_interface_count :DELTA5 // *class_interface :DELTA5 (cp_Class) // ...(member bands)... // class_attr_bands // code_bands Class[] classes = new Class[numClasses]; if (verbose > 0) Utils.log.info(" ...building "+classes.length+" classes..."); class_this.expectLength(numClasses); class_super.expectLength(numClasses); class_interface_count.expectLength(numClasses); class_this.readFrom(in); class_super.readFrom(in); class_interface_count.readFrom(in); class_interface.expectLength(class_interface_count.getIntTotal()); class_interface.readFrom(in); for (int i = 0; i < classes.length; i++) { ClassEntry thisClass = (ClassEntry) class_this.getRef(); ClassEntry superClass = (ClassEntry) class_super.getRef(); ClassEntry[] interfaces = new ClassEntry[class_interface_count.getInt()]; for (int j = 0; j < interfaces.length; j++) { interfaces[j] = (ClassEntry) class_interface.getRef(); } // Packer encoded rare case of null superClass as thisClass: if (superClass == thisClass) superClass = null; Class cls = pkg.new Class(NO_FLAGS_YET, thisClass, superClass, interfaces); classes[i] = cls; } class_this.doneDisbursing(); class_super.doneDisbursing(); class_interface_count.doneDisbursing(); class_interface.doneDisbursing(); readMembers(classes); countAndReadAttrs(ATTR_CONTEXT_CLASS, Arrays.asList(classes)); pkg.trimToSize(); readCodeHeaders(); //code_bands.doneDisbursing(); // still need to read code attrs //class_bands.doneDisbursing(); // still need to read code attrs return classes; } private int getOutputIndex(Entry e) { // Output CPs do not contain signatures. assert(e.tag != CONSTANT_Signature); int k = pkg.cp.untypedIndexOf(e); // In the output ordering, input signatures can serve // in place of Utf8s. if (k >= 0) return k; if (e.tag == CONSTANT_Utf8) { Entry se = utf8Signatures.get(e); return pkg.cp.untypedIndexOf(se); } return -1; } Comparator<Entry> entryOutputOrder = new Comparator Other Java examples (source code examples)Here is a short list of links related to this Java PackageReader.java source code file: |
... this post is sponsored by my books ... | |
#1 New Release! |
FP Best Seller |
Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.
A percentage of advertising revenue from
pages under the /java/jwarehouse
URI on this website is
paid back to open source projects.