From b6d455a02bd338e9dc0faa09d4d8177ecd8d569a Mon Sep 17 00:00:00 2001 From: Petr Mrázek Date: Sun, 10 Apr 2016 15:53:05 +0200 Subject: NOISSUE reorganize and document libraries --- libraries/pack200/src/bands.cpp | 423 ++++ libraries/pack200/src/bands.h | 489 ++++ libraries/pack200/src/bytes.cpp | 217 ++ libraries/pack200/src/bytes.h | 286 +++ libraries/pack200/src/coding.cpp | 1044 ++++++++ libraries/pack200/src/coding.h | 247 ++ libraries/pack200/src/constants.h | 442 ++++ libraries/pack200/src/defines.h | 65 + libraries/pack200/src/unpack.cpp | 4793 +++++++++++++++++++++++++++++++++++ libraries/pack200/src/unpack.h | 547 ++++ libraries/pack200/src/unpack200.cpp | 162 ++ libraries/pack200/src/utils.cpp | 71 + libraries/pack200/src/utils.h | 53 + libraries/pack200/src/zip.cpp | 589 +++++ libraries/pack200/src/zip.h | 110 + 15 files changed, 9538 insertions(+) create mode 100644 libraries/pack200/src/bands.cpp create mode 100644 libraries/pack200/src/bands.h create mode 100644 libraries/pack200/src/bytes.cpp create mode 100644 libraries/pack200/src/bytes.h create mode 100644 libraries/pack200/src/coding.cpp create mode 100644 libraries/pack200/src/coding.h create mode 100644 libraries/pack200/src/constants.h create mode 100644 libraries/pack200/src/defines.h create mode 100644 libraries/pack200/src/unpack.cpp create mode 100644 libraries/pack200/src/unpack.h create mode 100644 libraries/pack200/src/unpack200.cpp create mode 100644 libraries/pack200/src/utils.cpp create mode 100644 libraries/pack200/src/utils.h create mode 100644 libraries/pack200/src/zip.cpp create mode 100644 libraries/pack200/src/zip.h (limited to 'libraries/pack200/src') diff --git a/libraries/pack200/src/bands.cpp b/libraries/pack200/src/bands.cpp new file mode 100644 index 00000000..1608d838 --- /dev/null +++ b/libraries/pack200/src/bands.cpp @@ -0,0 +1,423 @@ +/* + * Copyright (c) 2002, 2009, 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. + */ + +// -*- C++ -*- +// Small program for unpacking specially compressed Java packages. +// John R. Rose + +#include + +#include +#include +#include +#include +#include +#include + +#include "defines.h" +#include "bytes.h" +#include "utils.h" +#include "coding.h" +#include "bands.h" + +#include "constants.h" +#include "unpack.h" + +void band::readData(int expectedLength) +{ + assert(expectedLength >= 0); + assert(vs[0].cmk == cmk_ERROR); + if (expectedLength != 0) + { + assert(length == 0); + length = expectedLength; + } + if (length == 0) + { + assert((rplimit = cm.vs0.rp = u->rp) != nullptr); + return; + } + assert(length > 0); + + bool is_BYTE1 = (defc->spec == BYTE1_spec); + + if (is_BYTE1) + { + // No possibility of coding change. Sizing is exact. + u->ensure_input(length); + } + else + { + // Make a conservatively generous estimate of band size in bytes. + // Assume B == 5 everywhere. + // Assume awkward pop with all {U} values (2*5 per value) + int64_t generous = (int64_t)length * (B_MAX * 3 + 1) + C_SLOP; + u->ensure_input(generous); + } + + // Read one value to see what it might be. + int XB = _meta_default; + if (!is_BYTE1) + { + // must be a variable-length coding + assert(defc->B() > 1 && defc->L() > 0); + + value_stream xvs; + coding *valc = defc; + if (valc->D() != 0) + { + valc = coding::findBySpec(defc->B(), defc->H(), defc->S()); + assert(!valc->isMalloc); + } + xvs.init(u->rp, u->rplimit, valc); + int X = xvs.getInt(); + if (valc->S() != 0) + { + assert(valc->min <= -256); + XB = -1 - X; + } + else + { + int L = valc->L(); + assert(valc->max >= L + 255); + XB = X - L; + } + if (0 <= XB && XB < 256) + { + // Skip over the escape value. + u->rp = xvs.rp; + } + else + { + // No, it's still default. + XB = _meta_default; + } + } + + if (XB <= _meta_canon_max) + { + byte XB_byte = (byte)XB; + byte *XB_ptr = &XB_byte; + cm.init(u->rp, u->rplimit, XB_ptr, 0, defc, length, nullptr); + } + else + { + assert(u->meta_rp != nullptr); + // Scribble the initial byte onto the band. + byte *save_meta_rp = --u->meta_rp; + byte save_meta_xb = (*save_meta_rp); + (*save_meta_rp) = (byte)XB; + cm.init(u->rp, u->rplimit, u->meta_rp, 0, defc, length, nullptr); + (*save_meta_rp) = save_meta_xb; // put it back, just to be tidy + } + rplimit = u->rp; + + rewind(); +} + +void band::setIndex(cpindex *ix_) +{ + assert(ix_ == nullptr || ixTag == ix_->ixTag); + ix = ix_; +} +void band::setIndexByTag(byte tag) +{ + setIndex(u->cp.getIndex(tag)); +} + +entry *band::getRefCommon(cpindex *ix_, bool nullOKwithCaller) +{ + assert(ix_->ixTag == ixTag || + (ixTag == CONSTANT_Literal && ix_->ixTag >= CONSTANT_Integer && + ix_->ixTag <= CONSTANT_String)); + int n = vs[0].getInt() - nullOK; + // Note: band-local nullOK means nullptr encodes as 0. + // But nullOKwithCaller means caller is willing to tolerate a nullptr. + entry *ref = ix_->get(n); + if (ref == nullptr && !(nullOKwithCaller && n == -1)) + unpack_abort(n == -1 ? "nullptr ref" : "bad ref"); + return ref; +} + +int64_t band::getLong(band &lo_band, bool have_hi) +{ + band &hi_band = (*this); + assert(lo_band.bn == hi_band.bn + 1); + uint32_t lo = lo_band.getInt(); + if (!have_hi) + { + assert(hi_band.length == 0); + return makeLong(0, lo); + } + uint32_t hi = hi_band.getInt(); + return makeLong(hi, lo); +} + +int band::getIntTotal() +{ + if (length == 0) + return 0; + if (total_memo > 0) + return total_memo - 1; + int total = getInt(); + // overflow checks require that none of the addends are <0, + // and that the partial sums never overflow (wrap negative) + if (total < 0) + { + unpack_abort("overflow detected"); + } + for (int k = length - 1; k > 0; k--) + { + int prev_total = total; + total += vs[0].getInt(); + if (total < prev_total) + { + unpack_abort("overflow detected"); + } + } + rewind(); + total_memo = total + 1; + return total; +} + +int band::getIntCount(int tag) +{ + if (length == 0) + return 0; + if (tag >= HIST0_MIN && tag <= HIST0_MAX) + { + if (hist0 == nullptr) + { + // Lazily calculate an approximate histogram. + hist0 = U_NEW(int, (HIST0_MAX - HIST0_MIN) + 1); + for (int k = length; k > 0; k--) + { + int x = vs[0].getInt(); + if (x >= HIST0_MIN && x <= HIST0_MAX) + hist0[x - HIST0_MIN] += 1; + } + rewind(); + } + return hist0[tag - HIST0_MIN]; + } + int total = 0; + for (int k = length; k > 0; k--) + { + total += (vs[0].getInt() == tag) ? 1 : 0; + } + rewind(); + return total; +} + +#define INDEX_INIT(tag, nullOK, subindex) ((tag) + (subindex) * SUBINDEX_BIT + (nullOK) * 256) + +#define INDEX(tag) INDEX_INIT(tag, 0, 0) +#define NULL_OR_INDEX(tag) INDEX_INIT(tag, 1, 0) +#define SUB_INDEX(tag) INDEX_INIT(tag, 0, 1) +#define NO_INDEX 0 + +struct band_init +{ + int defc; + int index; +}; + +#define BAND_INIT(name, cspec, ix) \ + { \ + cspec, ix \ + } + +const band_init all_band_inits[] = + { + // BAND_INIT(archive_magic, BYTE1_spec, 0), + // BAND_INIT(archive_header, UNSIGNED5_spec, 0), + // BAND_INIT(band_headers, BYTE1_spec, 0), + BAND_INIT(cp_Utf8_prefix, DELTA5_spec, 0), BAND_INIT(cp_Utf8_suffix, UNSIGNED5_spec, 0), + BAND_INIT(cp_Utf8_chars, CHAR3_spec, 0), BAND_INIT(cp_Utf8_big_suffix, DELTA5_spec, 0), + BAND_INIT(cp_Utf8_big_chars, DELTA5_spec, 0), BAND_INIT(cp_Int, UDELTA5_spec, 0), + BAND_INIT(cp_Float, UDELTA5_spec, 0), BAND_INIT(cp_Long_hi, UDELTA5_spec, 0), + BAND_INIT(cp_Long_lo, DELTA5_spec, 0), BAND_INIT(cp_Double_hi, UDELTA5_spec, 0), + BAND_INIT(cp_Double_lo, DELTA5_spec, 0), + BAND_INIT(cp_String, UDELTA5_spec, INDEX(CONSTANT_Utf8)), + BAND_INIT(cp_Class, UDELTA5_spec, INDEX(CONSTANT_Utf8)), + BAND_INIT(cp_Signature_form, DELTA5_spec, INDEX(CONSTANT_Utf8)), + BAND_INIT(cp_Signature_classes, UDELTA5_spec, INDEX(CONSTANT_Class)), + BAND_INIT(cp_Descr_name, DELTA5_spec, INDEX(CONSTANT_Utf8)), + BAND_INIT(cp_Descr_type, UDELTA5_spec, INDEX(CONSTANT_Signature)), + BAND_INIT(cp_Field_class, DELTA5_spec, INDEX(CONSTANT_Class)), + BAND_INIT(cp_Field_desc, UDELTA5_spec, INDEX(CONSTANT_NameandType)), + BAND_INIT(cp_Method_class, DELTA5_spec, INDEX(CONSTANT_Class)), + BAND_INIT(cp_Method_desc, UDELTA5_spec, INDEX(CONSTANT_NameandType)), + BAND_INIT(cp_Imethod_class, DELTA5_spec, INDEX(CONSTANT_Class)), + BAND_INIT(cp_Imethod_desc, UDELTA5_spec, INDEX(CONSTANT_NameandType)), + BAND_INIT(attr_definition_headers, BYTE1_spec, 0), + BAND_INIT(attr_definition_name, UNSIGNED5_spec, INDEX(CONSTANT_Utf8)), + BAND_INIT(attr_definition_layout, UNSIGNED5_spec, INDEX(CONSTANT_Utf8)), + BAND_INIT(ic_this_class, UDELTA5_spec, INDEX(CONSTANT_Class)), + BAND_INIT(ic_flags, UNSIGNED5_spec, 0), + BAND_INIT(ic_outer_class, DELTA5_spec, NULL_OR_INDEX(CONSTANT_Class)), + BAND_INIT(ic_name, DELTA5_spec, NULL_OR_INDEX(CONSTANT_Utf8)), + BAND_INIT(class_this, DELTA5_spec, INDEX(CONSTANT_Class)), + BAND_INIT(class_super, DELTA5_spec, INDEX(CONSTANT_Class)), + BAND_INIT(class_interface_count, DELTA5_spec, 0), + BAND_INIT(class_interface, DELTA5_spec, INDEX(CONSTANT_Class)), + BAND_INIT(class_field_count, DELTA5_spec, 0), + BAND_INIT(class_method_count, DELTA5_spec, 0), + BAND_INIT(field_descr, DELTA5_spec, INDEX(CONSTANT_NameandType)), + BAND_INIT(field_flags_hi, UNSIGNED5_spec, 0), + BAND_INIT(field_flags_lo, UNSIGNED5_spec, 0), + BAND_INIT(field_attr_count, UNSIGNED5_spec, 0), + BAND_INIT(field_attr_indexes, UNSIGNED5_spec, 0), + BAND_INIT(field_attr_calls, UNSIGNED5_spec, 0), + BAND_INIT(field_ConstantValue_KQ, UNSIGNED5_spec, INDEX(CONSTANT_Literal)), + BAND_INIT(field_Signature_RS, UNSIGNED5_spec, INDEX(CONSTANT_Signature)), + BAND_INIT(field_metadata_bands, -1, -1), BAND_INIT(field_attr_bands, -1, -1), + BAND_INIT(method_descr, MDELTA5_spec, INDEX(CONSTANT_NameandType)), + BAND_INIT(method_flags_hi, UNSIGNED5_spec, 0), + BAND_INIT(method_flags_lo, UNSIGNED5_spec, 0), + BAND_INIT(method_attr_count, UNSIGNED5_spec, 0), + BAND_INIT(method_attr_indexes, UNSIGNED5_spec, 0), + BAND_INIT(method_attr_calls, UNSIGNED5_spec, 0), + BAND_INIT(method_Exceptions_N, UNSIGNED5_spec, 0), + BAND_INIT(method_Exceptions_RC, UNSIGNED5_spec, INDEX(CONSTANT_Class)), + BAND_INIT(method_Signature_RS, UNSIGNED5_spec, INDEX(CONSTANT_Signature)), + BAND_INIT(method_metadata_bands, -1, -1), BAND_INIT(method_attr_bands, -1, -1), + BAND_INIT(class_flags_hi, UNSIGNED5_spec, 0), + BAND_INIT(class_flags_lo, UNSIGNED5_spec, 0), + BAND_INIT(class_attr_count, UNSIGNED5_spec, 0), + BAND_INIT(class_attr_indexes, UNSIGNED5_spec, 0), + BAND_INIT(class_attr_calls, UNSIGNED5_spec, 0), + BAND_INIT(class_SourceFile_RUN, UNSIGNED5_spec, NULL_OR_INDEX(CONSTANT_Utf8)), + BAND_INIT(class_EnclosingMethod_RC, UNSIGNED5_spec, INDEX(CONSTANT_Class)), + BAND_INIT(class_EnclosingMethod_RDN, UNSIGNED5_spec, + NULL_OR_INDEX(CONSTANT_NameandType)), + BAND_INIT(class_Signature_RS, UNSIGNED5_spec, INDEX(CONSTANT_Signature)), + BAND_INIT(class_metadata_bands, -1, -1), + BAND_INIT(class_InnerClasses_N, UNSIGNED5_spec, 0), + BAND_INIT(class_InnerClasses_RC, UNSIGNED5_spec, INDEX(CONSTANT_Class)), + BAND_INIT(class_InnerClasses_F, UNSIGNED5_spec, 0), + BAND_INIT(class_InnerClasses_outer_RCN, UNSIGNED5_spec, NULL_OR_INDEX(CONSTANT_Class)), + BAND_INIT(class_InnerClasses_name_RUN, UNSIGNED5_spec, NULL_OR_INDEX(CONSTANT_Utf8)), + BAND_INIT(class_ClassFile_version_minor_H, UNSIGNED5_spec, 0), + BAND_INIT(class_ClassFile_version_major_H, UNSIGNED5_spec, 0), + BAND_INIT(class_attr_bands, -1, -1), BAND_INIT(code_headers, BYTE1_spec, 0), + BAND_INIT(code_max_stack, UNSIGNED5_spec, 0), + BAND_INIT(code_max_na_locals, UNSIGNED5_spec, 0), + BAND_INIT(code_handler_count, UNSIGNED5_spec, 0), + BAND_INIT(code_handler_start_P, BCI5_spec, 0), + BAND_INIT(code_handler_end_PO, BRANCH5_spec, 0), + BAND_INIT(code_handler_catch_PO, BRANCH5_spec, 0), + BAND_INIT(code_handler_class_RCN, UNSIGNED5_spec, NULL_OR_INDEX(CONSTANT_Class)), + BAND_INIT(code_flags_hi, UNSIGNED5_spec, 0), + BAND_INIT(code_flags_lo, UNSIGNED5_spec, 0), + BAND_INIT(code_attr_count, UNSIGNED5_spec, 0), + BAND_INIT(code_attr_indexes, UNSIGNED5_spec, 0), + BAND_INIT(code_attr_calls, UNSIGNED5_spec, 0), + BAND_INIT(code_StackMapTable_N, UNSIGNED5_spec, 0), + BAND_INIT(code_StackMapTable_frame_T, BYTE1_spec, 0), + BAND_INIT(code_StackMapTable_local_N, UNSIGNED5_spec, 0), + BAND_INIT(code_StackMapTable_stack_N, UNSIGNED5_spec, 0), + BAND_INIT(code_StackMapTable_offset, UNSIGNED5_spec, 0), + BAND_INIT(code_StackMapTable_T, BYTE1_spec, 0), + BAND_INIT(code_StackMapTable_RC, UNSIGNED5_spec, INDEX(CONSTANT_Class)), + BAND_INIT(code_StackMapTable_P, BCI5_spec, 0), + BAND_INIT(code_LineNumberTable_N, UNSIGNED5_spec, 0), + BAND_INIT(code_LineNumberTable_bci_P, BCI5_spec, 0), + BAND_INIT(code_LineNumberTable_line, UNSIGNED5_spec, 0), + BAND_INIT(code_LocalVariableTable_N, UNSIGNED5_spec, 0), + BAND_INIT(code_LocalVariableTable_bci_P, BCI5_spec, 0), + BAND_INIT(code_LocalVariableTable_span_O, BRANCH5_spec, 0), + BAND_INIT(code_LocalVariableTable_name_RU, UNSIGNED5_spec, INDEX(CONSTANT_Utf8)), + BAND_INIT(code_LocalVariableTable_type_RS, UNSIGNED5_spec, INDEX(CONSTANT_Signature)), + BAND_INIT(code_LocalVariableTable_slot, UNSIGNED5_spec, 0), + BAND_INIT(code_LocalVariableTypeTable_N, UNSIGNED5_spec, 0), + BAND_INIT(code_LocalVariableTypeTable_bci_P, BCI5_spec, 0), + BAND_INIT(code_LocalVariableTypeTable_span_O, BRANCH5_spec, 0), + BAND_INIT(code_LocalVariableTypeTable_name_RU, UNSIGNED5_spec, INDEX(CONSTANT_Utf8)), + BAND_INIT(code_LocalVariableTypeTable_type_RS, UNSIGNED5_spec, + INDEX(CONSTANT_Signature)), + BAND_INIT(code_LocalVariableTypeTable_slot, UNSIGNED5_spec, 0), + BAND_INIT(code_attr_bands, -1, -1), BAND_INIT(bc_codes, BYTE1_spec, 0), + BAND_INIT(bc_case_count, UNSIGNED5_spec, 0), BAND_INIT(bc_case_value, DELTA5_spec, 0), + BAND_INIT(bc_byte, BYTE1_spec, 0), BAND_INIT(bc_short, DELTA5_spec, 0), + BAND_INIT(bc_local, UNSIGNED5_spec, 0), BAND_INIT(bc_label, BRANCH5_spec, 0), + BAND_INIT(bc_intref, DELTA5_spec, INDEX(CONSTANT_Integer)), + BAND_INIT(bc_floatref, DELTA5_spec, INDEX(CONSTANT_Float)), + BAND_INIT(bc_longref, DELTA5_spec, INDEX(CONSTANT_Long)), + BAND_INIT(bc_doubleref, DELTA5_spec, INDEX(CONSTANT_Double)), + BAND_INIT(bc_stringref, DELTA5_spec, INDEX(CONSTANT_String)), + BAND_INIT(bc_classref, UNSIGNED5_spec, NULL_OR_INDEX(CONSTANT_Class)), + BAND_INIT(bc_fieldref, DELTA5_spec, INDEX(CONSTANT_Fieldref)), + BAND_INIT(bc_methodref, UNSIGNED5_spec, INDEX(CONSTANT_Methodref)), + BAND_INIT(bc_imethodref, DELTA5_spec, INDEX(CONSTANT_InterfaceMethodref)), + BAND_INIT(bc_thisfield, UNSIGNED5_spec, SUB_INDEX(CONSTANT_Fieldref)), + BAND_INIT(bc_superfield, UNSIGNED5_spec, SUB_INDEX(CONSTANT_Fieldref)), + BAND_INIT(bc_thismethod, UNSIGNED5_spec, SUB_INDEX(CONSTANT_Methodref)), + BAND_INIT(bc_supermethod, UNSIGNED5_spec, SUB_INDEX(CONSTANT_Methodref)), + BAND_INIT(bc_initref, UNSIGNED5_spec, SUB_INDEX(CONSTANT_Methodref)), + BAND_INIT(bc_escref, UNSIGNED5_spec, INDEX(CONSTANT_All)), + BAND_INIT(bc_escrefsize, UNSIGNED5_spec, 0), BAND_INIT(bc_escsize, UNSIGNED5_spec, 0), + BAND_INIT(bc_escbyte, BYTE1_spec, 0), + BAND_INIT(file_name, UNSIGNED5_spec, INDEX(CONSTANT_Utf8)), + BAND_INIT(file_size_hi, UNSIGNED5_spec, 0), BAND_INIT(file_size_lo, UNSIGNED5_spec, 0), + BAND_INIT(file_modtime, DELTA5_spec, 0), BAND_INIT(file_options, UNSIGNED5_spec, 0), + // BAND_INIT(file_bits, BYTE1_spec, 0), + {0, 0}}; + +band *band::makeBands(unpacker *u) +{ + band *tmp_all_bands = U_NEW(band, BAND_LIMIT); + for (int i = 0; i < BAND_LIMIT; i++) + { + assert((byte *)&all_band_inits[i + 1] < + (byte *)all_band_inits + sizeof(all_band_inits)); + const band_init &bi = all_band_inits[i]; + band &b = tmp_all_bands[i]; + coding *defc = coding::findBySpec(bi.defc); + assert((defc == nullptr) == (bi.defc == -1)); // no garbage, please + assert(defc == nullptr || !defc->isMalloc); + b.init(u, i, defc); + if (bi.index > 0) + { + b.nullOK = ((bi.index >> 8) & 1); + b.ixTag = (bi.index & 0xFF); + } + } + return tmp_all_bands; +} + +void band::initIndexes(unpacker *u) +{ + band *tmp_all_bands = u->all_bands; + for (int i = 0; i < BAND_LIMIT; i++) + { + band *scan = &tmp_all_bands[i]; + uint32_t tag = scan->ixTag; // Cf. #define INDEX(tag) above + if (tag != 0 && tag != CONSTANT_Literal && (tag & SUBINDEX_BIT) == 0) + { + scan->setIndex(u->cp.getIndex(tag)); + } + } +} diff --git a/libraries/pack200/src/bands.h b/libraries/pack200/src/bands.h new file mode 100644 index 00000000..a56cd7d5 --- /dev/null +++ b/libraries/pack200/src/bands.h @@ -0,0 +1,489 @@ +/* + * Copyright (c) 2002, 2005, 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. + */ + +// -*- C++ -*- +struct entry; +struct cpindex; +struct unpacker; + +struct band +{ + int bn; // band_number of this band + coding *defc; // default coding method + cpindex *ix; // CP entry mapping, if CPRefBand + byte ixTag; // 0 or 1; nullptr is coded as (nullOK?0:-1) + byte nullOK; // 0 or 1; nullptr is coded as (nullOK?0:-1) + int length; // expected # values + unpacker *u; // back pointer + + value_stream vs[2]; // source of values + coding_method cm; // method used for initial state of vs[0] + byte *rplimit; // end of band (encoded, transmitted) + + int total_memo; // cached value of getIntTotal, or -1 + int *hist0; // approximate. histogram + enum + { + HIST0_MIN = 0, + HIST0_MAX = 255 + }; // catches the usual cases + + // properties for attribute layout elements: + byte le_kind; // EK_XXX + byte le_bci; // 0,EK_BCI,EK_BCD,EK_BCO + byte le_back; // ==EF_BACK + byte le_len; // 0,1,2,4 (size in classfile), or call addr + band **le_body; // body of repl, union, call (nullptr-terminated) +// Note: EK_CASE elements use hist0 to record union tags. +#define le_casetags hist0 + + band &nextBand() + { + return this[1]; + } + band &prevBand() + { + return this[-1]; + } + + void init(unpacker *u_, int bn_, coding *defc_) + { + u = u_; + cm.u = u_; + bn = bn_; + defc = defc_; + } + void init(unpacker *u_, int bn_, int defcSpec) + { + init(u_, bn_, coding::findBySpec(defcSpec)); + } + void initRef(int ixTag_ = 0, bool nullOK_ = false) + { + ixTag = ixTag_; + nullOK = nullOK_; + setIndexByTag(ixTag); + } + + void expectMoreLength(int l) + { + assert(length >= 0); // able to accept a length + assert((int)l >= 0); // no overflow + assert(rplimit == nullptr); // readData not yet called + length += l; + assert(length >= l); // no overflow + } + + void setIndex(cpindex *ix_); + void setIndexByTag(byte tag); + + // Parse the band and its meta-coding header. + void readData(int expectedLength = 0); + + // Reset the band for another pass (Cf. Java Band.resetForSecondPass.) + void rewind() + { + cm.reset(&vs[0]); + } + + byte *&curRP() + { + return vs[0].rp; + } + byte *minRP() + { + return cm.vs0.rp; + } + byte *maxRP() + { + return rplimit; + } + size_t size() + { + return maxRP() - minRP(); + } + + int getByte() + { + assert(ix == nullptr); + return vs[0].getByte(); + } + int getInt() + { + assert(ix == nullptr); + return vs[0].getInt(); + } + entry *getRefN() + { + assert(ix != nullptr); + return getRefCommon(ix, true); + } + entry *getRef() + { + assert(ix != nullptr); + return getRefCommon(ix, false); + } + entry *getRefUsing(cpindex *ix2) + { + assert(ix == nullptr); + return getRefCommon(ix2, true); + } + entry *getRefCommon(cpindex *ix, bool nullOK); + int64_t getLong(band &lo_band, bool have_hi); + + static int64_t makeLong(uint32_t hi, uint32_t lo) + { + return ((uint64_t)hi << 32) + (((uint64_t)lo << 32) >> 32); + } + + int getIntTotal(); + int getIntCount(int tag); + + static band *makeBands(unpacker *u); + static void initIndexes(unpacker *u); +}; + +extern band all_bands[]; + +#define BAND_LOCAL /* \ + band* band_temp = all_bands; \ + band* all_bands = band_temp */ + +// Band schema: +enum band_number +{ + // e_archive_magic, + // e_archive_header, + // e_band_headers, + + // constant pool contents + e_cp_Utf8_prefix, + e_cp_Utf8_suffix, + e_cp_Utf8_chars, + e_cp_Utf8_big_suffix, + e_cp_Utf8_big_chars, + e_cp_Int, + e_cp_Float, + e_cp_Long_hi, + e_cp_Long_lo, + e_cp_Double_hi, + e_cp_Double_lo, + e_cp_String, + e_cp_Class, + e_cp_Signature_form, + e_cp_Signature_classes, + e_cp_Descr_name, + e_cp_Descr_type, + e_cp_Field_class, + e_cp_Field_desc, + e_cp_Method_class, + e_cp_Method_desc, + e_cp_Imethod_class, + e_cp_Imethod_desc, + + // bands which define transmission of attributes + e_attr_definition_headers, + e_attr_definition_name, + e_attr_definition_layout, + + // band for hardwired InnerClasses attribute (shared across the package) + e_ic_this_class, + e_ic_flags, + // These bands contain data only where flags sets ACC_IC_LONG_FORM: + e_ic_outer_class, + e_ic_name, + + // bands for carrying class schema information: + e_class_this, + e_class_super, + e_class_interface_count, + e_class_interface, + + // bands for class members + e_class_field_count, + e_class_method_count, + e_field_descr, + e_field_flags_hi, + e_field_flags_lo, + e_field_attr_count, + e_field_attr_indexes, + e_field_attr_calls, + e_field_ConstantValue_KQ, + e_field_Signature_RS, + e_field_metadata_bands, + e_field_attr_bands, + e_method_descr, + e_method_flags_hi, + e_method_flags_lo, + e_method_attr_count, + e_method_attr_indexes, + e_method_attr_calls, + e_method_Exceptions_N, + e_method_Exceptions_RC, + e_method_Signature_RS, + e_method_metadata_bands, + e_method_attr_bands, + e_class_flags_hi, + e_class_flags_lo, + e_class_attr_count, + e_class_attr_indexes, + e_class_attr_calls, + e_class_SourceFile_RUN, + e_class_EnclosingMethod_RC, + e_class_EnclosingMethod_RDN, + e_class_Signature_RS, + e_class_metadata_bands, + e_class_InnerClasses_N, + e_class_InnerClasses_RC, + e_class_InnerClasses_F, + e_class_InnerClasses_outer_RCN, + e_class_InnerClasses_name_RUN, + e_class_ClassFile_version_minor_H, + e_class_ClassFile_version_major_H, + e_class_attr_bands, + e_code_headers, + e_code_max_stack, + e_code_max_na_locals, + e_code_handler_count, + e_code_handler_start_P, + e_code_handler_end_PO, + e_code_handler_catch_PO, + e_code_handler_class_RCN, + + // code attributes + e_code_flags_hi, + e_code_flags_lo, + e_code_attr_count, + e_code_attr_indexes, + e_code_attr_calls, + e_code_StackMapTable_N, + e_code_StackMapTable_frame_T, + e_code_StackMapTable_local_N, + e_code_StackMapTable_stack_N, + e_code_StackMapTable_offset, + e_code_StackMapTable_T, + e_code_StackMapTable_RC, + e_code_StackMapTable_P, + e_code_LineNumberTable_N, + e_code_LineNumberTable_bci_P, + e_code_LineNumberTable_line, + e_code_LocalVariableTable_N, + e_code_LocalVariableTable_bci_P, + e_code_LocalVariableTable_span_O, + e_code_LocalVariableTable_name_RU, + e_code_LocalVariableTable_type_RS, + e_code_LocalVariableTable_slot, + e_code_LocalVariableTypeTable_N, + e_code_LocalVariableTypeTable_bci_P, + e_code_LocalVariableTypeTable_span_O, + e_code_LocalVariableTypeTable_name_RU, + e_code_LocalVariableTypeTable_type_RS, + e_code_LocalVariableTypeTable_slot, + e_code_attr_bands, + + // bands for bytecodes + e_bc_codes, + // remaining bands provide typed opcode fields required by the bc_codes + e_bc_case_count, + e_bc_case_value, + e_bc_byte, + e_bc_short, + e_bc_local, + e_bc_label, + + // ldc* operands: + e_bc_intref, + e_bc_floatref, + e_bc_longref, + e_bc_doubleref, + e_bc_stringref, + e_bc_classref, + e_bc_fieldref, + e_bc_methodref, + e_bc_imethodref, + + // _self_linker_op family + e_bc_thisfield, + e_bc_superfield, + e_bc_thismethod, + e_bc_supermethod, + + // bc_invokeinit family: + e_bc_initref, + + // bytecode escape sequences + e_bc_escref, + e_bc_escrefsize, + e_bc_escsize, + e_bc_escbyte, + + // file attributes and contents + e_file_name, + e_file_size_hi, + e_file_size_lo, + e_file_modtime, + e_file_options, + // e_file_bits, // handled specially as an appendix + BAND_LIMIT +}; + +// Symbolic names for bands, as if in a giant global struct: +//#define archive_magic all_bands[e_archive_magic] +//#define archive_header all_bands[e_archive_header] +//#define band_headers all_bands[e_band_headers] +#define cp_Utf8_prefix all_bands[e_cp_Utf8_prefix] +#define cp_Utf8_suffix all_bands[e_cp_Utf8_suffix] +#define cp_Utf8_chars all_bands[e_cp_Utf8_chars] +#define cp_Utf8_big_suffix all_bands[e_cp_Utf8_big_suffix] +#define cp_Utf8_big_chars all_bands[e_cp_Utf8_big_chars] +#define cp_Int all_bands[e_cp_Int] +#define cp_Float all_bands[e_cp_Float] +#define cp_Long_hi all_bands[e_cp_Long_hi] +#define cp_Long_lo all_bands[e_cp_Long_lo] +#define cp_Double_hi all_bands[e_cp_Double_hi] +#define cp_Double_lo all_bands[e_cp_Double_lo] +#define cp_String all_bands[e_cp_String] +#define cp_Class all_bands[e_cp_Class] +#define cp_Signature_form all_bands[e_cp_Signature_form] +#define cp_Signature_classes all_bands[e_cp_Signature_classes] +#define cp_Descr_name all_bands[e_cp_Descr_name] +#define cp_Descr_type all_bands[e_cp_Descr_type] +#define cp_Field_class all_bands[e_cp_Field_class] +#define cp_Field_desc all_bands[e_cp_Field_desc] +#define cp_Method_class all_bands[e_cp_Method_class] +#define cp_Method_desc all_bands[e_cp_Method_desc] +#define cp_Imethod_class all_bands[e_cp_Imethod_class] +#define cp_Imethod_desc all_bands[e_cp_Imethod_desc] +#define attr_definition_headers all_bands[e_attr_definition_headers] +#define attr_definition_name all_bands[e_attr_definition_name] +#define attr_definition_layout all_bands[e_attr_definition_layout] +#define ic_this_class all_bands[e_ic_this_class] +#define ic_flags all_bands[e_ic_flags] +#define ic_outer_class all_bands[e_ic_outer_class] +#define ic_name all_bands[e_ic_name] +#define class_this all_bands[e_class_this] +#define class_super all_bands[e_class_super] +#define class_interface_count all_bands[e_class_interface_count] +#define class_interface all_bands[e_class_interface] +#define class_field_count all_bands[e_class_field_count] +#define class_method_count all_bands[e_class_method_count] +#define field_descr all_bands[e_field_descr] +#define field_flags_hi all_bands[e_field_flags_hi] +#define field_flags_lo all_bands[e_field_flags_lo] +#define field_attr_count all_bands[e_field_attr_count] +#define field_attr_indexes all_bands[e_field_attr_indexes] +#define field_ConstantValue_KQ all_bands[e_field_ConstantValue_KQ] +#define field_Signature_RS all_bands[e_field_Signature_RS] +#define field_attr_bands all_bands[e_field_attr_bands] +#define method_descr all_bands[e_method_descr] +#define method_flags_hi all_bands[e_method_flags_hi] +#define method_flags_lo all_bands[e_method_flags_lo] +#define method_attr_count all_bands[e_method_attr_count] +#define method_attr_indexes all_bands[e_method_attr_indexes] +#define method_Exceptions_N all_bands[e_method_Exceptions_N] +#define method_Exceptions_RC all_bands[e_method_Exceptions_RC] +#define method_Signature_RS all_bands[e_method_Signature_RS] +#define method_attr_bands all_bands[e_method_attr_bands] +#define class_flags_hi all_bands[e_class_flags_hi] +#define class_flags_lo all_bands[e_class_flags_lo] +#define class_attr_count all_bands[e_class_attr_count] +#define class_attr_indexes all_bands[e_class_attr_indexes] +#define class_SourceFile_RUN all_bands[e_class_SourceFile_RUN] +#define class_EnclosingMethod_RC all_bands[e_class_EnclosingMethod_RC] +#define class_EnclosingMethod_RDN all_bands[e_class_EnclosingMethod_RDN] +#define class_Signature_RS all_bands[e_class_Signature_RS] +#define class_InnerClasses_N all_bands[e_class_InnerClasses_N] +#define class_InnerClasses_RC all_bands[e_class_InnerClasses_RC] +#define class_InnerClasses_F all_bands[e_class_InnerClasses_F] +#define class_InnerClasses_outer_RCN all_bands[e_class_InnerClasses_outer_RCN] +#define class_InnerClasses_name_RUN all_bands[e_class_InnerClasses_name_RUN] +#define class_ClassFile_version_minor_H all_bands[e_class_ClassFile_version_minor_H] +#define class_ClassFile_version_major_H all_bands[e_class_ClassFile_version_major_H] +#define class_attr_bands all_bands[e_class_attr_bands] +#define code_headers all_bands[e_code_headers] +#define code_max_stack all_bands[e_code_max_stack] +#define code_max_na_locals all_bands[e_code_max_na_locals] +#define code_handler_count all_bands[e_code_handler_count] +#define code_handler_start_P all_bands[e_code_handler_start_P] +#define code_handler_end_PO all_bands[e_code_handler_end_PO] +#define code_handler_catch_PO all_bands[e_code_handler_catch_PO] +#define code_handler_class_RCN all_bands[e_code_handler_class_RCN] +#define code_flags_hi all_bands[e_code_flags_hi] +#define code_flags_lo all_bands[e_code_flags_lo] +#define code_attr_count all_bands[e_code_attr_count] +#define code_attr_indexes all_bands[e_code_attr_indexes] +#define code_StackMapTable_N all_bands[e_code_StackMapTable_N] +#define code_StackMapTable_frame_T all_bands[e_code_StackMapTable_frame_T] +#define code_StackMapTable_local_N all_bands[e_code_StackMapTable_local_N] +#define code_StackMapTable_stack_N all_bands[e_code_StackMapTable_stack_N] +#define code_StackMapTable_offset all_bands[e_code_StackMapTable_offset] +#define code_StackMapTable_T all_bands[e_code_StackMapTable_T] +#define code_StackMapTable_RC all_bands[e_code_StackMapTable_RC] +#define code_StackMapTable_P all_bands[e_code_StackMapTable_P] +#define code_LineNumberTable_N all_bands[e_code_LineNumberTable_N] +#define code_LineNumberTable_bci_P all_bands[e_code_LineNumberTable_bci_P] +#define code_LineNumberTable_line all_bands[e_code_LineNumberTable_line] +#define code_LocalVariableTable_N all_bands[e_code_LocalVariableTable_N] +#define code_LocalVariableTable_bci_P all_bands[e_code_LocalVariableTable_bci_P] +#define code_LocalVariableTable_span_O all_bands[e_code_LocalVariableTable_span_O] +#define code_LocalVariableTable_name_RU all_bands[e_code_LocalVariableTable_name_RU] +#define code_LocalVariableTable_type_RS all_bands[e_code_LocalVariableTable_type_RS] +#define code_LocalVariableTable_slot all_bands[e_code_LocalVariableTable_slot] +#define code_LocalVariableTypeTable_N all_bands[e_code_LocalVariableTypeTable_N] +#define code_LocalVariableTypeTable_bci_P all_bands[e_code_LocalVariableTypeTable_bci_P] +#define code_LocalVariableTypeTable_span_O all_bands[e_code_LocalVariableTypeTable_span_O] +#define code_LocalVariableTypeTable_name_RU all_bands[e_code_LocalVariableTypeTable_name_RU] +#define code_LocalVariableTypeTable_type_RS all_bands[e_code_LocalVariableTypeTable_type_RS] +#define code_LocalVariableTypeTable_slot all_bands[e_code_LocalVariableTypeTable_slot] +#define code_attr_bands all_bands[e_code_attr_bands] +#define bc_codes all_bands[e_bc_codes] +#define bc_case_count all_bands[e_bc_case_count] +#define bc_case_value all_bands[e_bc_case_value] +#define bc_byte all_bands[e_bc_byte] +#define bc_short all_bands[e_bc_short] +#define bc_local all_bands[e_bc_local] +#define bc_label all_bands[e_bc_label] +#define bc_intref all_bands[e_bc_intref] +#define bc_floatref all_bands[e_bc_floatref] +#define bc_longref all_bands[e_bc_longref] +#define bc_doubleref all_bands[e_bc_doubleref] +#define bc_stringref all_bands[e_bc_stringref] +#define bc_classref all_bands[e_bc_classref] +#define bc_fieldref all_bands[e_bc_fieldref] +#define bc_methodref all_bands[e_bc_methodref] +#define bc_imethodref all_bands[e_bc_imethodref] +#define bc_thisfield all_bands[e_bc_thisfield] +#define bc_superfield all_bands[e_bc_superfield] +#define bc_thismethod all_bands[e_bc_thismethod] +#define bc_supermethod all_bands[e_bc_supermethod] +#define bc_initref all_bands[e_bc_initref] +#define bc_escref all_bands[e_bc_escref] +#define bc_escrefsize all_bands[e_bc_escrefsize] +#define bc_escsize all_bands[e_bc_escsize] +#define bc_escbyte all_bands[e_bc_escbyte] +#define file_name all_bands[e_file_name] +#define file_size_hi all_bands[e_file_size_hi] +#define file_size_lo all_bands[e_file_size_lo] +#define file_modtime all_bands[e_file_modtime] +#define file_options all_bands[e_file_options] diff --git a/libraries/pack200/src/bytes.cpp b/libraries/pack200/src/bytes.cpp new file mode 100644 index 00000000..d3808afa --- /dev/null +++ b/libraries/pack200/src/bytes.cpp @@ -0,0 +1,217 @@ +/* + * Copyright (c) 2001, 2010, 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. + */ + +#include +#include +#include +#include +#include +#include "defines.h" +#include "bytes.h" +#include "utils.h" + +static byte dummy[1 << 10]; + +bool bytes::inBounds(const void *p) +{ + return p >= ptr && p < limit(); +} + +void bytes::malloc(size_t len_) +{ + len = len_; + ptr = NEW(byte, add_size(len_, 1)); // add trailing zero byte always + if (ptr == nullptr) + { + // set ptr to some victim memory, to ease escape + set(dummy, sizeof(dummy) - 1); + unpack_abort(ERROR_ENOMEM); + } +} + +void bytes::realloc(size_t len_) +{ + if (len == len_) + return; // nothing to do + if (ptr == dummy) + return; // escaping from an error + if (ptr == nullptr) + { + malloc(len_); + return; + } + byte *oldptr = ptr; + ptr = (len_ >= PSIZE_MAX) ? nullptr : (byte *)::realloc(ptr, add_size(len_, 1)); + if (ptr != nullptr) + { + if (len < len_) + memset(ptr + len, 0, len_ - len); + ptr[len_] = 0; + len = len_; + } + else + { + ptr = oldptr; // ease our escape + unpack_abort(ERROR_ENOMEM); + } +} + +void bytes::free() +{ + if (ptr == dummy) + return; // escaping from an error + if (ptr != nullptr) + { + ::free(ptr); + } + len = 0; + ptr = 0; +} + +int bytes::indexOf(byte c) +{ + byte *p = (byte *)memchr(ptr, c, len); + return (p == 0) ? -1 : (int)(p - ptr); +} + +byte *bytes::writeTo(byte *bp) +{ + memcpy(bp, ptr, len); + return bp + len; +} + +int bytes::compareTo(bytes &other) +{ + size_t l1 = len; + size_t l2 = other.len; + int cmp = memcmp(ptr, other.ptr, (l1 < l2) ? l1 : l2); + if (cmp != 0) + return cmp; + return (l1 < l2) ? -1 : (l1 > l2) ? 1 : 0; +} + +void bytes::saveFrom(const void *ptr_, size_t len_) +{ + malloc(len_); + // Save as much as possible. + if (len_ > len) + { + assert(ptr == dummy); // error recovery + len_ = len; + } + copyFrom(ptr_, len_); +} + +//#TODO: Need to fix for exception handling +void bytes::copyFrom(const void *ptr_, size_t len_, size_t offset) +{ + assert(len_ == 0 || inBounds(ptr + offset)); + assert(len_ == 0 || inBounds(ptr + offset + len_ - 1)); + memcpy(ptr + offset, ptr_, len_); +} + +// Make sure there are 'o' bytes beyond the fill pointer, +// advance the fill pointer, and return the old fill pointer. +byte *fillbytes::grow(size_t s) +{ + size_t nlen = add_size(b.len, s); + if (nlen <= allocated) + { + b.len = nlen; + return limit() - s; + } + size_t maxlen = nlen; + if (maxlen < 128) + maxlen = 128; + if (maxlen < allocated * 2) + maxlen = allocated * 2; + if (allocated == 0) + { + // Initial buffer was not malloced. Do not reallocate it. + bytes old = b; + b.malloc(maxlen); + if (b.len == maxlen) + old.writeTo(b.ptr); + } + else + { + b.realloc(maxlen); + } + allocated = b.len; + if (allocated != maxlen) + { + b.len = nlen - s; // back up + return dummy; // scribble during error recov. + } + // after realloc, recompute pointers + b.len = nlen; + assert(b.len <= allocated); + return limit() - s; +} + +void fillbytes::ensureSize(size_t s) +{ + if (allocated >= s) + return; + size_t len0 = b.len; + grow(s - size()); + b.len = len0; // put it back +} + +int ptrlist::indexOf(const void *x) +{ + int len = length(); + for (int i = 0; i < len; i++) + { + if (get(i) == x) + return i; + } + return -1; +} + +void ptrlist::freeAll() +{ + int len = length(); + for (int i = 0; i < len; i++) + { + void *p = (void *)get(i); + if (p != nullptr) + { + ::free(p); + } + } + free(); +} + +int intlist::indexOf(int x) +{ + int len = length(); + for (int i = 0; i < len; i++) + { + if (get(i) == x) + return i; + } + return -1; +} diff --git a/libraries/pack200/src/bytes.h b/libraries/pack200/src/bytes.h new file mode 100644 index 00000000..b116efda --- /dev/null +++ b/libraries/pack200/src/bytes.h @@ -0,0 +1,286 @@ +/* + * Copyright (c) 2001, 2008, 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. + */ + +#pragma once + +struct bytes +{ + int8_t *ptr; + size_t len; + int8_t *limit() + { + return ptr + len; + } + + void set(int8_t *ptr_, size_t len_) + { + ptr = ptr_; + len = len_; + } + void set(const char *str) + { + ptr = (int8_t *)str; + len = strlen(str); + } + bool inBounds(const void *p); // p in [ptr, limit) + void malloc(size_t len_); + void realloc(size_t len_); + void free(); + void copyFrom(const void *ptr_, size_t len_, size_t offset = 0); + void saveFrom(const void *ptr_, size_t len_); + void saveFrom(const char *str) + { + saveFrom(str, strlen(str)); + } + void copyFrom(bytes &other, size_t offset = 0) + { + copyFrom(other.ptr, other.len, offset); + } + void saveFrom(bytes &other) + { + saveFrom(other.ptr, other.len); + } + void clear(int fill_byte = 0) + { + memset(ptr, fill_byte, len); + } + int8_t *writeTo(int8_t *bp); + bool equals(bytes &other) + { + return 0 == compareTo(other); + } + int compareTo(bytes &other); + bool contains(int8_t c) + { + return indexOf(c) >= 0; + } + int indexOf(int8_t c); + // substrings: + static bytes of(int8_t *ptr, size_t len) + { + bytes res; + res.set(ptr, len); + return res; + } + bytes slice(size_t beg, size_t end) + { + bytes res; + res.ptr = ptr + beg; + res.len = end - beg; + assert(res.len == 0 ||(inBounds(res.ptr) && inBounds(res.limit() - 1))); + return res; + } + // building C strings inside byte buffers: + bytes &strcat(const char *str) + { + ::strcat((char *)ptr, str); + return *this; + } + bytes &strcat(bytes &other) + { + ::strncat((char *)ptr, (char *)other.ptr, other.len); + return *this; + } + char *strval() + { + assert(strlen((char *)ptr) == len); + return (char *)ptr; + } +}; +#define BYTES_OF(var) (bytes::of((int8_t *)&(var), sizeof(var))) + +struct fillbytes +{ + bytes b; + size_t allocated; + + int8_t *base() + { + return b.ptr; + } + size_t size() + { + return b.len; + } + int8_t *limit() + { + return b.limit(); + } // logical limit + void setLimit(int8_t *lp) + { + assert(isAllocated(lp)); + b.len = lp - b.ptr; + } + int8_t *end() + { + return b.ptr + allocated; + } // physical limit + int8_t *loc(size_t o) + { + assert(o < b.len); + return b.ptr + o; + } + void init() + { + allocated = 0; + b.set(nullptr, 0); + } + void init(size_t s) + { + init(); + ensureSize(s); + } + void free() + { + if (allocated != 0) + b.free(); + allocated = 0; + } + void empty() + { + b.len = 0; + } + int8_t *grow(size_t s); // grow so that limit() += s + int getByte(uint32_t i) + { + return *loc(i) & 0xFF; + } + void addByte(int8_t x) + { + *grow(1) = x; + } + void ensureSize(size_t s); // make sure allocated >= s + void trimToSize() + { + if (allocated > size()) + b.realloc(allocated = size()); + } + bool canAppend(size_t s) + { + return allocated > b.len + s; + } + bool isAllocated(int8_t *p) + { + return p >= base() && p <= end(); + } // asserts + void set(bytes &src) + { + set(src.ptr, src.len); + } + + void set(int8_t *ptr, size_t len) + { + b.set(ptr, len); + allocated = 0; // mark as not reallocatable + } + + // block operations on resizing byte buffer: + fillbytes &append(const void *ptr_, size_t len_) + { + memcpy(grow(len_), ptr_, len_); + return (*this); + } + fillbytes &append(bytes &other) + { + return append(other.ptr, other.len); + } + fillbytes &append(const char *str) + { + return append(str, strlen(str)); + } +}; + +struct ptrlist : fillbytes +{ + typedef const void *cvptr; + int length() + { + return (int)(size() / sizeof(cvptr)); + } + cvptr *base() + { + return (cvptr *)fillbytes::base(); + } + cvptr &get(int i) + { + return *(cvptr *)loc(i * sizeof(cvptr)); + } + cvptr *limit() + { + return (cvptr *)fillbytes::limit(); + } + void add(cvptr x) + { + *(cvptr *)grow(sizeof(x)) = x; + } + void popTo(int l) + { + assert(l <= length()); + b.len = l * sizeof(cvptr); + } + int indexOf(cvptr x); + bool contains(cvptr x) + { + return indexOf(x) >= 0; + } + void freeAll(); // frees every ptr on the list, plus the list itself +}; +// Use a macro rather than mess with subtle mismatches +// between member and non-member function pointers. +#define PTRLIST_QSORT(ptrls, fn) ::qsort((ptrls).base(), (ptrls).length(), sizeof(void *), fn) + +struct intlist : fillbytes +{ + int length() + { + return (int)(size() / sizeof(int)); + } + int *base() + { + return (int *)fillbytes::base(); + } + int &get(int i) + { + return *(int *)loc(i * sizeof(int)); + } + int *limit() + { + return (int *)fillbytes::limit(); + } + void add(int x) + { + *(int *)grow(sizeof(x)) = x; + } + void popTo(int l) + { + assert(l <= length()); + b.len = l * sizeof(int); + } + int indexOf(int x); + bool contains(int x) + { + return indexOf(x) >= 0; + } +}; diff --git a/libraries/pack200/src/coding.cpp b/libraries/pack200/src/coding.cpp new file mode 100644 index 00000000..6bd17a3c --- /dev/null +++ b/libraries/pack200/src/coding.cpp @@ -0,0 +1,1044 @@ +/* + * Copyright (c) 2002, 2009, 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. + */ + +// -*- C++ -*- +// Small program for unpacking specially compressed Java packages. +// John R. Rose + +#include +#include +#include +#include +#include +#include + +#include "defines.h" +#include "bytes.h" +#include "utils.h" +#include "coding.h" + +#include "constants.h" +#include "unpack.h" + +extern coding basic_codings[]; + +// CODING_PRIVATE causes a lot of them +#pragma GCC diagnostic ignored "-Wunused-variable" + +#define CODING_PRIVATE(spec) \ + int spec_ = spec; \ + int B = CODING_B(spec_); \ + int H = CODING_H(spec_); \ + int L = 256 - H; \ + int S = CODING_S(spec_); \ + int D = CODING_D(spec_) + +#define IS_NEG_CODE(S, codeVal) ((((int)(codeVal) + 1) & ((1 << S) - 1)) == 0) + +#define DECODE_SIGN_S1(ux) (((uint32_t)(ux) >> 1) ^ -((int)(ux) & 1)) + +static int decode_sign(int S, uint32_t ux) +{ // == Coding.decodeSign32 + assert(S > 0); + uint32_t sigbits = (ux >> S); + if (IS_NEG_CODE(S, ux)) + return (int)(~sigbits); + else + return (int)(ux - sigbits); + // Note that (int)(ux-sigbits) can be negative, if ux is large enough. +} + +coding *coding::init() +{ + if (umax > 0) + return this; // already done + assert(spec != 0); // sanity + + // fill in derived fields + CODING_PRIVATE(spec); + + // Return nullptr if 'arb(BHSD)' parameter constraints are not met: + if (B < 1 || B > B_MAX) + return nullptr; + if (H < 1 || H > 256) + return nullptr; + if (S < 0 || S > 2) + return nullptr; + if (D < 0 || D > 1) + return nullptr; + if (B == 1 && H != 256) + return nullptr; // 1-byte coding must be fixed-size + if (B >= 5 && H == 256) + return nullptr; // no 5-byte fixed-size coding + + // first compute the range of the coding, in 64 bits + int64_t range = 0; + { + int64_t H_i = 1; + for (int i = 0; i < B; i++) + { + range += H_i; + H_i *= H; + } + range *= L; + range += H_i; + } + assert(range > 0); // no useless codings, please + + int this_umax; + + // now, compute min and max + if (range >= ((int64_t)1 << 32)) + { + this_umax = INT_MAX_VALUE; + this->umin = INT_MIN_VALUE; + this->max = INT_MAX_VALUE; + this->min = INT_MIN_VALUE; + } + else + { + this_umax = (range > INT_MAX_VALUE) ? INT_MAX_VALUE : (int)range - 1; + this->max = this_umax; + this->min = this->umin = 0; + if (S != 0 && range != 0) + { + int64_t maxPosCode = range - 1; + int64_t maxNegCode = range - 1; + while (IS_NEG_CODE(S, maxPosCode)) + --maxPosCode; + while (!IS_NEG_CODE(S, maxNegCode)) + --maxNegCode; + int maxPos = decode_sign(S, (uint32_t)maxPosCode); + if (maxPos < 0) + this->max = INT_MAX_VALUE; // 32-bit wraparound + else + this->max = maxPos; + if (maxNegCode < 0) + this->min = 0; // No negative codings at all. + else + this->min = decode_sign(S, (uint32_t)maxNegCode); + } + } + + assert(!(isFullRange | isSigned | isSubrange)); // init + if (min < 0) + this->isSigned = true; + if (max < INT_MAX_VALUE && range <= INT_MAX_VALUE) + this->isSubrange = true; + if (max == INT_MAX_VALUE && min == INT_MIN_VALUE) + this->isFullRange = true; + + // do this last, to reduce MT exposure (should have a membar too) + this->umax = this_umax; + + return this; +} + +coding *coding::findBySpec(int spec) +{ + for (coding *scan = &basic_codings[0];; scan++) + { + if (scan->spec == spec) + return scan->init(); + if (scan->spec == 0) + break; + } + coding *ptr = NEW(coding, 1); + if (!ptr) + return nullptr; + coding *c = ptr->initFrom(spec); + if (c == nullptr) + { + ::free(ptr); + } + else + // else caller should free it... + c->isMalloc = true; + return c; +} + +coding *coding::findBySpec(int B, int H, int S, int D) +{ + if (B < 1 || B > B_MAX) + return nullptr; + if (H < 1 || H > 256) + return nullptr; + if (S < 0 || S > 2) + return nullptr; + if (D < 0 || D > 1) + return nullptr; + return findBySpec(CODING_SPEC(B, H, S, D)); +} + +void coding::free() +{ + if (isMalloc) + { + ::free(this); + } +} + +void coding_method::reset(value_stream *state) +{ + assert(state->rp == state->rplimit); // not in mid-stream, please + // assert(this == vs0.cm); + state[0] = vs0; + if (uValues != nullptr) + { + uValues->reset(state->helper()); + } +} + +uint32_t coding::parse(byte *&rp, int B, int H) +{ + int L = 256 - H; + byte *ptr = rp; + // hand peel the i==0 part of the loop: + uint32_t b_i = *ptr++ & 0xFF; + if (B == 1 || b_i < (uint32_t)L) + { + rp = ptr; + return b_i; + } + uint32_t sum = b_i; + uint32_t H_i = H; + assert(B <= B_MAX); + for (int i = 2; i <= B_MAX; i++) + { // easy for compilers to unroll if desired + b_i = *ptr++ & 0xFF; + sum += b_i * H_i; + if (i == B || b_i < (uint32_t)L) + { + rp = ptr; + return sum; + } + H_i *= H; + } + assert(false); + return 0; +} + +uint32_t coding::parse_lgH(byte *&rp, int B, int H, int lgH) +{ + assert(H == (1 << lgH)); + int L = 256 - (1 << lgH); + byte *ptr = rp; + // hand peel the i==0 part of the loop: + uint32_t b_i = *ptr++ & 0xFF; + if (B == 1 || b_i < (uint32_t)L) + { + rp = ptr; + return b_i; + } + uint32_t sum = b_i; + uint32_t lg_H_i = lgH; + assert(B <= B_MAX); + for (int i = 2; i <= B_MAX; i++) + { // easy for compilers to unroll if desired + b_i = *ptr++ & 0xFF; + sum += b_i << lg_H_i; + if (i == B || b_i < (uint32_t)L) + { + rp = ptr; + return sum; + } + lg_H_i += lgH; + } + assert(false); + return 0; +} + +static const char ERB[] = "EOF reading band"; + +void coding::parseMultiple(byte *&rp, int N, byte *limit, int B, int H) +{ + if (N < 0) + { + unpack_abort("bad value count"); + return; + } + byte *ptr = rp; + if (B == 1 || H == 256) + { + size_t len = (size_t)N * B; + if (len / B != (size_t)N || ptr + len > limit) + { + unpack_abort(ERB); + return; + } + rp = ptr + len; + return; + } + // Note: We assume rp has enough zero-padding. + int L = 256 - H; + int n = B; + while (N > 0) + { + ptr += 1; + if (--n == 0) + { + // end of encoding at B bytes, regardless of byte value + } + else + { + int b = (ptr[-1] & 0xFF); + if (b >= L) + { + // keep going, unless we find a byte < L + continue; + } + } + // found the last byte + N -= 1; + n = B; // reset length counter + // do an error check here + if (ptr > limit) + { + unpack_abort(ERB); + return; + } + } + rp = ptr; + return; +} + +bool value_stream::hasHelper() +{ + // If my coding method is a pop-style method, + // then I need a second value stream to transmit + // unfavored values. + // This can be determined by examining fValues. + return cm->fValues != nullptr; +} + +void value_stream::init(byte *rp_, byte *rplimit_, coding *defc) +{ + rp = rp_; + rplimit = rplimit_; + sum = 0; + cm = nullptr; // no need in the simple case + setCoding(defc); +} + +void value_stream::setCoding(coding *defc) +{ + if (defc == nullptr) + { + unpack_abort("bad coding"); + defc = coding::findByIndex(_meta_canon_min); // random pick for recovery + } + + c = (*defc); + + // choose cmk + cmk = cmk_ERROR; + switch (c.spec) + { + case BYTE1_spec: + cmk = cmk_BYTE1; + break; + case CHAR3_spec: + cmk = cmk_CHAR3; + break; + case UNSIGNED5_spec: + cmk = cmk_UNSIGNED5; + break; + case DELTA5_spec: + cmk = cmk_DELTA5; + break; + case BCI5_spec: + cmk = cmk_BCI5; + break; + case BRANCH5_spec: + cmk = cmk_BRANCH5; + break; + default: + if (c.D() == 0) + { + switch (c.S()) + { + case 0: + cmk = cmk_BHS0; + break; + case 1: + cmk = cmk_BHS1; + break; + default: + cmk = cmk_BHS; + break; + } + } + else + { + if (c.S() == 1) + { + if (c.isFullRange) + cmk = cmk_BHS1D1full; + if (c.isSubrange) + cmk = cmk_BHS1D1sub; + } + if (cmk == cmk_ERROR) + cmk = cmk_BHSD1; + } + } +} + +static int getPopValue(value_stream *self, uint32_t uval) +{ + if (uval > 0) + { + // note that the initial parse performed a range check + assert(uval <= (uint32_t)self->cm->fVlength); + return self->cm->fValues[uval - 1]; + } + else + { + // take an unfavored value + return self->helper()->getInt(); + } +} + +int coding::sumInUnsignedRange(int x, int y) +{ + assert(isSubrange); + int range = (int)(umax + 1); + assert(range > 0); + x += y; + if (x != (int)((int64_t)(x - y) + (int64_t)y)) + { + // 32-bit overflow interferes with range reduction. + // Back off from the overflow by adding a multiple of range: + if (x < 0) + { + x -= range; + assert(x >= 0); + } + else + { + x += range; + assert(x < 0); + } + } + if (x < 0) + { + x += range; + if (x >= 0) + return x; + } + else if (x >= range) + { + x -= range; + if (x < range) + return x; + } + else + { + // in range + return x; + } + // do it the hard way + x %= range; + if (x < 0) + x += range; + return x; +} + +static int getDeltaValue(value_stream *self, uint32_t uval, bool isSubrange) +{ + assert((uint32_t)(self->c.isSubrange) == (uint32_t)isSubrange); + assert(self->c.isSubrange | self->c.isFullRange); + if (isSubrange) + return self->sum = self->c.sumInUnsignedRange(self->sum, (int)uval); + else + return self->sum += (int)uval; +} + +bool value_stream::hasValue() +{ + if (rp < rplimit) + return true; + if (cm == nullptr) + return false; + if (cm->next == nullptr) + return false; + cm->next->reset(this); + return hasValue(); +} + +int value_stream::getInt() +{ + if (rp >= rplimit) + { + // Advance to next coding segment. + if (rp > rplimit || cm == nullptr || cm->next == nullptr) + { + // Must perform this check and throw an exception on bad input. + unpack_abort(ERB); + return 0; + } + cm->next->reset(this); + return getInt(); + } + + CODING_PRIVATE(c.spec); + uint32_t uval; + enum + { + B5 = 5, + B3 = 3, + H128 = 128, + H64 = 64, + H4 = 4 + }; + switch (cmk) + { + case cmk_BHS: + assert(D == 0); + uval = coding::parse(rp, B, H); + if (S == 0) + return (int)uval; + return decode_sign(S, uval); + + case cmk_BHS0: + assert(S == 0 && D == 0); + uval = coding::parse(rp, B, H); + return (int)uval; + + case cmk_BHS1: + assert(S == 1 && D == 0); + uval = coding::parse(rp, B, H); + return DECODE_SIGN_S1(uval); + + case cmk_BYTE1: + assert(c.spec == BYTE1_spec); + assert(B == 1 && H == 256 && S == 0 && D == 0); + return *rp++ & 0xFF; + + case cmk_CHAR3: + assert(c.spec == CHAR3_spec); + assert(B == B3 && H == H128 && S == 0 && D == 0); + return coding::parse_lgH(rp, B3, H128, 7); + + case cmk_UNSIGNED5: + assert(c.spec == UNSIGNED5_spec); + assert(B == B5 && H == H64 && S == 0 && D == 0); + return coding::parse_lgH(rp, B5, H64, 6); + + case cmk_BHSD1: + assert(D == 1); + uval = coding::parse(rp, B, H); + if (S != 0) + uval = (uint32_t)decode_sign(S, uval); + return getDeltaValue(this, uval, (bool)c.isSubrange); + + case cmk_BHS1D1full: + assert(S == 1 && D == 1 && c.isFullRange); + uval = coding::parse(rp, B, H); + uval = (uint32_t)DECODE_SIGN_S1(uval); + return getDeltaValue(this, uval, false); + + case cmk_BHS1D1sub: + assert(S == 1 && D == 1 && c.isSubrange); + uval = coding::parse(rp, B, H); + uval = (uint32_t)DECODE_SIGN_S1(uval); + return getDeltaValue(this, uval, true); + + case cmk_DELTA5: + assert(c.spec == DELTA5_spec); + assert(B == B5 && H == H64 && S == 1 && D == 1 && c.isFullRange); + uval = coding::parse_lgH(rp, B5, H64, 6); + sum += DECODE_SIGN_S1(uval); + return sum; + + case cmk_BCI5: + assert(c.spec == BCI5_spec); + assert(B == B5 && H == H4 && S == 0 && D == 0); + return coding::parse_lgH(rp, B5, H4, 2); + + case cmk_BRANCH5: + assert(c.spec == BRANCH5_spec); + assert(B == B5 && H == H4 && S == 2 && D == 0); + uval = coding::parse_lgH(rp, B5, H4, 2); + return decode_sign(S, uval); + + case cmk_pop: + uval = coding::parse(rp, B, H); + if (S != 0) + { + uval = (uint32_t)decode_sign(S, uval); + } + if (D != 0) + { + assert(c.isSubrange | c.isFullRange); + if (c.isSubrange) + sum = c.sumInUnsignedRange(sum, (int)uval); + else + sum += (int)uval; + uval = (uint32_t)sum; + } + return getPopValue(this, uval); + + case cmk_pop_BHS0: + assert(S == 0 && D == 0); + uval = coding::parse(rp, B, H); + return getPopValue(this, uval); + + case cmk_pop_BYTE1: + assert(c.spec == BYTE1_spec); + assert(B == 1 && H == 256 && S == 0 && D == 0); + return getPopValue(this, *rp++ & 0xFF); + + default: + break; + } + assert(false); + return 0; +} + +static int moreCentral(int x, int y) +{ // used to find end of Pop.{F} + // Suggested implementation from the Pack200 specification: + uint32_t kx = (x >> 31) ^ (x << 1); + uint32_t ky = (y >> 31) ^ (y << 1); + return (kx < ky ? x : y); +} +// static maybe_inline +// int moreCentral2(int x, int y, int min) { +// // Strict implementation of buggy 150.7 specification. +// // The bug is that the spec. says absolute-value ties are broken +// // in favor of positive numbers, but the suggested implementation +// // (also mentioned in the spec.) breaks ties in favor of negative numbers. +// if ((x + y) != 0) +// return min; +// else +// // return the other value, which breaks a tie in the positive direction +// return (x > y)? x: y; +//} + +static const byte *no_meta[] = {nullptr}; +#define NO_META (*(byte **)no_meta) +enum +{ + POP_FAVORED_N = -2 +}; + +// mode bits +#define DISABLE_RUN 1 // used immediately inside ACodee +#define DISABLE_POP 2 // used recursively in all pop sub-bands + +// This function knows all about meta-coding. +void coding_method::init(byte *&band_rp, byte *band_limit, byte *&meta_rp, int mode, + coding *defc, int N, intlist *valueSink) +{ + assert(N != 0); + + assert(u != nullptr); // must be pre-initialized + // if (u == nullptr) u = unpacker::current(); // expensive + + int op = (meta_rp == nullptr) ? _meta_default : (*meta_rp++ & 0xFF); + coding *foundc = nullptr; + coding *to_free = nullptr; + + if (op == _meta_default) + { + foundc = defc; + // and fall through + } + else if (op >= _meta_canon_min && op <= _meta_canon_max) + { + foundc = coding::findByIndex(op); + // and fall through + } + else if (op == _meta_arb) + { + int args = (*meta_rp++ & 0xFF); + // args = (D:[0..1] + 2*S[0..2] + 8*(B:[1..5]-1)) + int D = ((args >> 0) & 1); + int S = ((args >> 1) & 3); + int B = ((args >> 3) & -1) + 1; + // & (H[1..256]-1) + int H = (*meta_rp++ & 0xFF) + 1; + foundc = coding::findBySpec(B, H, S, D); + to_free = foundc; // findBySpec may dynamically allocate + if (foundc == nullptr) + { + unpack_abort("illegal arbitrary coding"); + return; + } + // and fall through + } + else if (op >= _meta_run && op < _meta_pop) + { + int args = (op - _meta_run); + // args: KX:[0..3] + 4*(KBFlag:[0..1]) + 8*(ABDef:[0..2]) + int KX = ((args >> 0) & 3); + int KBFlag = ((args >> 2) & 1); + int ABDef = ((args >> 3) & -1); + assert(ABDef <= 2); + // & KB: one of [0..255] if KBFlag=1 + int KB = (!KBFlag ? 3 : (*meta_rp++ & 0xFF)); + int K = (KB + 1) << (KX * 4); + int N2 = (N >= 0) ? N - K : N; + if (N == 0 || (N2 <= 0 && N2 != N)) + { + unpack_abort("illegal run encoding"); + } + if ((mode & DISABLE_RUN) != 0) + { + unpack_abort("illegal nested run encoding"); + } + + // & Enc{ ACode } if ADef=0 (ABDef != 1) + // No direct nesting of 'run' in ACode, but in BCode it's OK. + int disRun = mode | DISABLE_RUN; + if (ABDef == 1) + { + this->init(band_rp, band_limit, NO_META, disRun, defc, K, valueSink); + } + else + { + this->init(band_rp, band_limit, meta_rp, disRun, defc, K, valueSink); + } + + // & Enc{ BCode } if BDef=0 (ABDef != 2) + coding_method *tail = U_NEW(coding_method, 1); + if (!tail) + return; + tail->u = u; + + // The 'run' codings may be nested indirectly via 'pop' codings. + // This means that this->next may already be filled in, if + // ACode was of type 'pop' with a 'run' token coding. + // No problem: Just chain the upcoming BCode onto the end. + for (coding_method *self = this;; self = self->next) + { + if (self->next == nullptr) + { + self->next = tail; + break; + } + } + + if (ABDef == 2) + { + tail->init(band_rp, band_limit, NO_META, mode, defc, N2, valueSink); + } + else + { + tail->init(band_rp, band_limit, meta_rp, mode, defc, N2, valueSink); + } + // Note: The preceding calls to init should be tail-recursive. + + return; // done; no falling through + } + else if (op >= _meta_pop && op < _meta_limit) + { + int args = (op - _meta_pop); + // args: (FDef:[0..1]) + 2*UDef:[0..1] + 4*(TDefL:[0..11]) + int FDef = ((args >> 0) & 1); + int UDef = ((args >> 1) & 1); + int TDefL = ((args >> 2) & -1); + assert(TDefL <= 11); + int TDef = (TDefL > 0); + int TL = (TDefL <= 6) ? (2 << TDefL) : (256 - (4 << (11 - TDefL))); + int TH = (256 - TL); + if (N <= 0) + { + unpack_abort("illegal pop encoding"); + } + if ((mode & DISABLE_POP) != 0) + { + unpack_abort("illegal nested pop encoding"); + } + + // No indirect nesting of 'pop', but 'run' is OK. + int disPop = DISABLE_POP; + + // & Enc{ FCode } if FDef=0 + int FN = POP_FAVORED_N; + assert(valueSink == nullptr); + intlist fValueSink; + fValueSink.init(); + coding_method fval; + BYTES_OF(fval).clear(); + fval.u = u; + if (FDef != 0) + { + fval.init(band_rp, band_limit, NO_META, disPop, defc, FN, &fValueSink); + } + else +