2682 lines · 108.9 KB · Java
RawDownload
/* * Copyright (c) 2001, 2011, 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.Entry;import com.sun.java.util.jar.pack.ConstantPool.Index;import com.sun.java.util.jar.pack.Package.Class.Field;import java.io.BufferedOutputStream;import java.io.ByteArrayInputStream;import java.io.ByteArrayOutputStream;import java.io.EOFException;import java.io.File;import java.io.FileOutputStream;import java.io.FilterInputStream;import java.io.FilterOutputStream;import java.io.IOException;import java.io.InputStream;import java.io.OutputStream;import java.io.PrintStream;import java.util.ArrayList;import java.util.Arrays;import java.util.Collections;import java.util.HashMap;import java.util.List;import java.util.Map;import java.util.jar.Pack200;import static com.sun.java.util.jar.pack.Constants.*; /** * Define the structure and ordering of "bands" in a packed file. * @author John Rose */abstractclass BandStructure {    static final int MAX_EFFORT = 9;    static final int MIN_EFFORT = 1;    static final int DEFAULT_EFFORT = 5;     // Inherit options from Pack200:    PropMap p200 = Utils.currentPropMap();     int verbose = p200.getInteger(Utils.DEBUG_VERBOSE);    int effort = p200.getInteger(Pack200.Packer.EFFORT);    { if (effort == 0)  effort = DEFAULT_EFFORT; }    boolean optDumpBands = p200.getBoolean(Utils.COM_PREFIX+"dump.bands");    boolean optDebugBands = p200.getBoolean(Utils.COM_PREFIX+"debug.bands");     // Various heuristic options.    boolean optVaryCodings = !p200.getBoolean(Utils.COM_PREFIX+"no.vary.codings");    boolean optBigStrings = !p200.getBoolean(Utils.COM_PREFIX+"no.big.strings");     abstract protected Index getCPIndex(byte tag);     // Local copy of package version.    private int packageMajver = -1;     /** Call this exactly once, early, to specify the archive major version. */    public void initPackageMajver(int packageMajver) throws IOException {        assert(packageMajver > 0 && packageMajver < 0x10000);        if (this.packageMajver > 0) {            throw new IOException(                "Package majver is already initialized to " + this.packageMajver+                "; new setting is " + packageMajver);        }        this.packageMajver = packageMajver;        adjustToMajver();    }    public int getPackageMajver() {        if (packageMajver < 0) {            throw new RuntimeException("Package majver not yet initialized");        }        return packageMajver;    }     private final boolean isReader = this instanceof PackageReader;    protected BandStructure() {    }     final static Coding BYTE1 = Coding.of(1,256);     final static Coding CHAR3 = Coding.of(3,128);    // Note:  Tried sharper (3,16) with no post-zip benefit.     // This is best used with BCI values:    final static Coding BCI5 = Coding.of(5,4);  // mostly 1-byte offsets    final static Coding BRANCH5 = Coding.of(5,4,2); // mostly forward branches     final static Coding UNSIGNED5 = Coding.of(5,64);    final static Coding UDELTA5 = UNSIGNED5.getDeltaCoding();    // "sharp" (5,64) zips 0.4% better than "medium" (5,128)    // It zips 1.1% better than "flat" (5,192)     final static Coding SIGNED5 = Coding.of(5,64,1);  //sharp    final static Coding DELTA5 = SIGNED5.getDeltaCoding();    // Note:  Tried (5,128,2) and (5,192,2) with no benefit.     final static Coding MDELTA5 = Coding.of(5,64,2).getDeltaCoding();     final private static Coding[] basicCodings = {        // Table of "Canonical BHSD Codings" from Pack200 spec.        null,  // _meta_default         // Fixed-length codings:        Coding.of(1,256,0),        Coding.of(1,256,1),        Coding.of(1,256,0).getDeltaCoding(),        Coding.of(1,256,1).getDeltaCoding(),        Coding.of(2,256,0),        Coding.of(2,256,1),        Coding.of(2,256,0).getDeltaCoding(),        Coding.of(2,256,1).getDeltaCoding(),        Coding.of(3,256,0),        Coding.of(3,256,1),        Coding.of(3,256,0).getDeltaCoding(),        Coding.of(3,256,1).getDeltaCoding(),        Coding.of(4,256,0),        Coding.of(4,256,1),        Coding.of(4,256,0).getDeltaCoding(),        Coding.of(4,256,1).getDeltaCoding(),         // Full-range variable-length codings:        Coding.of(5,  4,0),        Coding.of(5,  4,1),        Coding.of(5,  4,2),        Coding.of(5, 16,0),        Coding.of(5, 16,1),        Coding.of(5, 16,2),        Coding.of(5, 32,0),        Coding.of(5, 32,1),        Coding.of(5, 32,2),        Coding.of(5, 64,0),        Coding.of(5, 64,1),        Coding.of(5, 64,2),        Coding.of(5,128,0),        Coding.of(5,128,1),        Coding.of(5,128,2),         Coding.of(5,  4,0).getDeltaCoding(),        Coding.of(5,  4,1).getDeltaCoding(),        Coding.of(5,  4,2).getDeltaCoding(),        Coding.of(5, 16,0).getDeltaCoding(),        Coding.of(5, 16,1).getDeltaCoding(),        Coding.of(5, 16,2).getDeltaCoding(),        Coding.of(5, 32,0).getDeltaCoding(),        Coding.of(5, 32,1).getDeltaCoding(),        Coding.of(5, 32,2).getDeltaCoding(),        Coding.of(5, 64,0).getDeltaCoding(),        Coding.of(5, 64,1).getDeltaCoding(),        Coding.of(5, 64,2).getDeltaCoding(),        Coding.of(5,128,0).getDeltaCoding(),        Coding.of(5,128,1).getDeltaCoding(),        Coding.of(5,128,2).getDeltaCoding(),         // Variable length subrange codings:        Coding.of(2,192,0),        Coding.of(2,224,0),        Coding.of(2,240,0),        Coding.of(2,248,0),        Coding.of(2,252,0),         Coding.of(2,  8,0).getDeltaCoding(),        Coding.of(2,  8,1).getDeltaCoding(),        Coding.of(2, 16,0).getDeltaCoding(),        Coding.of(2, 16,1).getDeltaCoding(),        Coding.of(2, 32,0).getDeltaCoding(),        Coding.of(2, 32,1).getDeltaCoding(),        Coding.of(2, 64,0).getDeltaCoding(),        Coding.of(2, 64,1).getDeltaCoding(),        Coding.of(2,128,0).getDeltaCoding(),        Coding.of(2,128,1).getDeltaCoding(),        Coding.of(2,192,0).getDeltaCoding(),        Coding.of(2,192,1).getDeltaCoding(),        Coding.of(2,224,0).getDeltaCoding(),        Coding.of(2,224,1).getDeltaCoding(),        Coding.of(2,240,0).getDeltaCoding(),        Coding.of(2,240,1).getDeltaCoding(),        Coding.of(2,248,0).getDeltaCoding(),        Coding.of(2,248,1).getDeltaCoding(),         Coding.of(3,192,0),        Coding.of(3,224,0),        Coding.of(3,240,0),        Coding.of(3,248,0),        Coding.of(3,252,0),         Coding.of(3,  8,0).getDeltaCoding(),        Coding.of(3,  8,1).getDeltaCoding(),        Coding.of(3, 16,0).getDeltaCoding(),        Coding.of(3, 16,1).getDeltaCoding(),        Coding.of(3, 32,0).getDeltaCoding(),        Coding.of(3, 32,1).getDeltaCoding(),        Coding.of(3, 64,0).getDeltaCoding(),        Coding.of(3, 64,1).getDeltaCoding(),        Coding.of(3,128,0).getDeltaCoding(),        Coding.of(3,128,1).getDeltaCoding(),        Coding.of(3,192,0).getDeltaCoding(),        Coding.of(3,192,1).getDeltaCoding(),        Coding.of(3,224,0).getDeltaCoding(),        Coding.of(3,224,1).getDeltaCoding(),        Coding.of(3,240,0).getDeltaCoding(),        Coding.of(3,240,1).getDeltaCoding(),        Coding.of(3,248,0).getDeltaCoding(),        Coding.of(3,248,1).getDeltaCoding(),         Coding.of(4,192,0),        Coding.of(4,224,0),        Coding.of(4,240,0),        Coding.of(4,248,0),        Coding.of(4,252,0),         Coding.of(4,  8,0).getDeltaCoding(),        Coding.of(4,  8,1).getDeltaCoding(),        Coding.of(4, 16,0).getDeltaCoding(),        Coding.of(4, 16,1).getDeltaCoding(),        Coding.of(4, 32,0).getDeltaCoding(),        Coding.of(4, 32,1).getDeltaCoding(),        Coding.of(4, 64,0).getDeltaCoding(),        Coding.of(4, 64,1).getDeltaCoding(),        Coding.of(4,128,0).getDeltaCoding(),        Coding.of(4,128,1).getDeltaCoding(),        Coding.of(4,192,0).getDeltaCoding(),        Coding.of(4,192,1).getDeltaCoding(),        Coding.of(4,224,0).getDeltaCoding(),        Coding.of(4,224,1).getDeltaCoding(),        Coding.of(4,240,0).getDeltaCoding(),        Coding.of(4,240,1).getDeltaCoding(),        Coding.of(4,248,0).getDeltaCoding(),        Coding.of(4,248,1).getDeltaCoding(),         null    };    final private static Map<Coding, Integer> basicCodingIndexes;    static {        assert(basicCodings[_meta_default] == null);        assert(basicCodings[_meta_canon_min] != null);        assert(basicCodings[_meta_canon_max] != null);        Map<Coding, Integer> map = new HashMap<>();        for (int i = 0; i < basicCodings.length; i++) {            Coding c = basicCodings[i];            if (c == null)  continue;            assert(i >= _meta_canon_min);            assert(i <= _meta_canon_max);            map.put(c, i);        }        basicCodingIndexes = map;    }    public static Coding codingForIndex(int i) {        return i < basicCodings.length ? basicCodings[i] : null;    }    public static int indexOf(Coding c) {        Integer i = basicCodingIndexes.get(c);        if (i == null)  return 0;        return i.intValue();    }    public static Coding[] getBasicCodings() {        return basicCodings.clone();    }     protected byte[] bandHeaderBytes;    // used for input only    protected int    bandHeaderBytePos;  // BHB read pointer, for input only    protected int    bandHeaderBytePos0; // for debug     protected CodingMethod getBandHeader(int XB, Coding regularCoding) {        CodingMethod[] res = {null};        // push back XB onto the band header bytes        bandHeaderBytes[--bandHeaderBytePos] = (byte) XB;        bandHeaderBytePos0 = bandHeaderBytePos;        // scan forward through XB and any additional band header bytes        bandHeaderBytePos = parseMetaCoding(bandHeaderBytes,                                            bandHeaderBytePos,                                            regularCoding,                                            res);        return res[0];    }     public static int parseMetaCoding(byte[] bytes, int pos, Coding dflt, CodingMethod[] res) {        if ((bytes[pos] & 0xFF) == _meta_default) {            res[0] = dflt;            return pos+1;        }        int pos2;        pos2 = Coding.parseMetaCoding(bytes, pos, dflt, res);        if (pos2 > pos)  return pos2;        pos2 = PopulationCoding.parseMetaCoding(bytes, pos, dflt, res);        if (pos2 > pos)  return pos2;        pos2 = AdaptiveCoding.parseMetaCoding(bytes, pos, dflt, res);        if (pos2 > pos)  return pos2;        throw new RuntimeException("Bad meta-coding op "+(bytes[pos]&0xFF));    }     static final int SHORT_BAND_HEURISTIC = 100;     public static final int NO_PHASE        = 0;     // package writing phases:    public static final int COLLECT_PHASE   = 1; // collect data before write    public static final int FROZEN_PHASE    = 3; // no longer collecting    public static final int WRITE_PHASE     = 5; // ready to write bytes     // package reading phases:    public static final int EXPECT_PHASE    = 2; // gather expected counts    public static final int READ_PHASE      = 4; // ready to read bytes    public static final int DISBURSE_PHASE  = 6; // pass out data after read     public static final int DONE_PHASE      = 8; // done writing or reading     static boolean phaseIsRead(int p) {        return (p % 2) == 0;    }    static int phaseCmp(int p0, int p1) {        assert((p0 % 2) == (p1 % 2) || (p0 % 8) == 0 || (p1 % 8) == 0);        return p0 - p1;    }     /** The packed file is divided up into a number of segments.     *  Most segments are typed as ValueBand, strongly-typed sequences     *  of integer values, all interpreted in a single way.     *  A few segments are ByteBands, which hetergeneous sequences     *  of bytes.     *     *  The two phases for writing a packed file are COLLECT and WRITE.     *  1. When writing a packed file, each band collects     *  data in an ad-hoc order.     *  2. At the end, each band is assigned a coding scheme,     *  and then all the bands are written in their global order.     *     *  The three phases for reading a packed file are EXPECT, READ,     *  and DISBURSE.     *  1. For each band, the expected number of integers  is determined.     *  2. The data is actually read from the file into the band.     *  3. The band pays out its values as requested, in an ad hoc order.     *     *  When the last phase of a band is done, it is marked so (DONE).     *  Clearly, these phases must be properly ordered WRT each other.     */    abstract class Band {        private int    phase = NO_PHASE;        private final  String name;         private int    valuesExpected;         protected long outputSize = -1;  // cache         final public Coding regularCoding;         final public int seqForDebug;        public int       elementCountForDebug;          protected Band(String name, Coding regularCoding) {            this.name = name;            this.regularCoding = regularCoding;            this.seqForDebug = ++nextSeqForDebug;            if (verbose > 2)                Utils.log.fine("Band "+seqForDebug+" is "+name);            // caller must call init        }         public Band init() {            // Cannot due this from the constructor, because constructor            // may wish to initialize some subclass variables.            // Set initial phase for reading or writing:            if (isReader)                readyToExpect();            else                readyToCollect();            return this;        }         // common operations        boolean isReader() { return isReader; }        int phase() { return phase; }        String name() { return name; }         /** Return -1 if data buffer not allocated, else max length. */        public abstract int capacity();         /** Allocate data buffer to specified length. */        protected abstract void setCapacity(int cap);         /** Return current number of values in buffer, which must exist. */        public abstract int length();         protected abstract int valuesRemainingForDebug();         public final int valuesExpected() {            return valuesExpected;        }         /** Write out bytes, encoding the values. */        public final void writeTo(OutputStream out) throws IOException {            assert(assertReadyToWriteTo(this, out));            setPhase(WRITE_PHASE);            // subclasses continue by writing their contents to output            writeDataTo(out);            doneWriting();        }         abstract void chooseBandCodings() throws IOException;         public final long outputSize() {            if (outputSize >= 0) {                long size = outputSize;                assert(size == computeOutputSize());                return size;            }            return computeOutputSize();        }         protected abstract long computeOutputSize();         abstract protected void writeDataTo(OutputStream out) throws IOException;         /** Expect a certain number of values. */        void expectLength(int l) {            assert(assertPhase(this, EXPECT_PHASE));            assert(valuesExpected == 0);  // all at once            assert(l >= 0);            valuesExpected = l;        }        /** Expect more values.  (Multiple calls accumulate.) */        void expectMoreLength(int l) {            assert(assertPhase(this, EXPECT_PHASE));            valuesExpected += l;        }          /// Phase change markers.         private void readyToCollect() { // called implicitly by constructor            setCapacity(1);            setPhase(COLLECT_PHASE);        }        protected void doneWriting() {            assert(assertPhase(this, WRITE_PHASE));            setPhase(DONE_PHASE);        }        private void readyToExpect() { // called implicitly by constructor            setPhase(EXPECT_PHASE);        }        /** Read in bytes, decoding the values. */        public final void readFrom(InputStream in) throws IOException {            assert(assertReadyToReadFrom(this, in));            setCapacity(valuesExpected());            setPhase(READ_PHASE);            // subclasses continue by reading their contents from input:            readDataFrom(in);            readyToDisburse();        }        abstract protected void readDataFrom(InputStream in) throws IOException;        protected void readyToDisburse() {            if (verbose > 1)  Utils.log.fine("readyToDisburse "+this);            setPhase(DISBURSE_PHASE);        }        public void doneDisbursing() {            assert(assertPhase(this, DISBURSE_PHASE));            setPhase(DONE_PHASE);        }        public final void doneWithUnusedBand() {            if (isReader) {                assert(assertPhase(this, EXPECT_PHASE));                assert(valuesExpected() == 0);                // Fast forward:                setPhase(READ_PHASE);                setPhase(DISBURSE_PHASE);                setPhase(DONE_PHASE);            } else {                setPhase(FROZEN_PHASE);            }        }         protected void setPhase(int newPhase) {            assert(assertPhaseChangeOK(this, phase, newPhase));            this.phase = newPhase;        }         protected int lengthForDebug = -1;  // DEBUG ONLY

Lines 1–500 of 2682.