--- a/jdk/src/jdk.pack200/share/native/common-unpack/coding.cpp Wed Dec 14 19:46:21 2016 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,989 +0,0 @@
-/*
- * 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 <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <stdarg.h>
-
-#include "jni_util.h"
-
-#include "defines.h"
-#include "bytes.h"
-#include "utils.h"
-#include "coding.h"
-
-#include "constants.h"
-#include "unpack.h"
-
-extern coding basic_codings[];
-
-#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) \
- ( ((uint)(ux) >> 1) ^ -((int)(ux) & 1) )
-
-static maybe_inline
-int decode_sign(int S, uint ux) { // == Coding.decodeSign32
- assert(S > 0);
- uint 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 null if 'arb(BHSD)' parameter constraints are not met:
- if (B < 1 || B > B_MAX) return null;
- if (H < 1 || H > 256) return null;
- if (S < 0 || S > 2) return null;
- if (D < 0 || D > 1) return null;
- if (B == 1 && H != 256) return null; // 1-byte coding must be fixed-size
- if (B >= 5 && H == 256) return null; // no 5-byte fixed-size coding
-
- // first compute the range of the coding, in 64 bits
- jlong range = 0;
- {
- jlong 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 >= ((jlong)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) {
- int Smask = (1<<S)-1;
- jlong maxPosCode = range-1;
- jlong maxNegCode = range-1;
- while (IS_NEG_CODE(S, maxPosCode)) --maxPosCode;
- while (!IS_NEG_CODE(S, maxNegCode)) --maxNegCode;
- int maxPos = decode_sign(S, (uint)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, (uint)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);
- CHECK_NULL_RETURN(ptr, 0);
- coding* c = ptr->initFrom(spec);
- if (c == null) {
- mtrace('f', ptr, 0);
- ::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 null;
- if (H < 1 || H > 256) return null;
- if (S < 0 || S > 2) return null;
- if (D < 0 || D > 1) return null;
- return findBySpec(CODING_SPEC(B, H, S, D));
-}
-
-void coding::free() {
- if (isMalloc) {
- mtrace('f', this, 0);
- ::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 != null) {
- uValues->reset(state->helper());
- }
-}
-
-maybe_inline
-uint coding::parse(byte* &rp, int B, int H) {
- int L = 256-H;
- byte* ptr = rp;
- // hand peel the i==0 part of the loop:
- uint b_i = *ptr++ & 0xFF;
- if (B == 1 || b_i < (uint)L)
- { rp = ptr; return b_i; }
- uint sum = b_i;
- uint 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 < (uint)L)
- { rp = ptr; return sum; }
- H_i *= H;
- }
- assert(false);
- return 0;
-}
-
-maybe_inline
-uint 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:
- uint b_i = *ptr++ & 0xFF;
- if (B == 1 || b_i < (uint)L)
- { rp = ptr; return b_i; }
- uint sum = b_i;
- uint 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 < (uint)L)
- { rp = ptr; return sum; }
- lg_H_i += lgH;
- }
- assert(false);
- return 0;
-}
-
-static const char ERB[] = "EOF reading band";
-
-maybe_inline
-void coding::parseMultiple(byte* &rp, int N, byte* limit, int B, int H) {
- if (N < 0) {
- 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) {
- 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) {
- 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 != null;
-}
-
-void value_stream::init(byte* rp_, byte* rplimit_, coding* defc) {
- rp = rp_;
- rplimit = rplimit_;
- sum = 0;
- cm = null; // no need in the simple case
- setCoding(defc);
-}
-
-void value_stream::setCoding(coding* defc) {
- if (defc == null) {
- 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 maybe_inline
-int getPopValue(value_stream* self, uint uval) {
- if (uval > 0) {
- // note that the initial parse performed a range check
- assert(uval <= (uint)self->cm->fVlength);
- return self->cm->fValues[uval-1];
- } else {
- // take an unfavored value
- return self->helper()->getInt();
- }
-}
-
-maybe_inline
-int coding::sumInUnsignedRange(int x, int y) {
- assert(isSubrange);
- int range = (int)(umax+1);
- assert(range > 0);
- x += y;
- if (x != (int)((jlong)(x-y) + (jlong)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 maybe_inline
-int getDeltaValue(value_stream* self, uint uval, bool isSubrange) {
- assert((uint)(self->c.isSubrange) == (uint)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 == null) return false;
- if (cm->next == null) return false;
- cm->next->reset(this);
- return hasValue();
-}
-
-int value_stream::getInt() {
- if (rp >= rplimit) {
- // Advance to next coding segment.
- if (rp > rplimit || cm == null || cm->next == null) {
- // 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);
- uint 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 = (uint) 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 = (uint) 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 = (uint) 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 = (uint) 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 = (uint) 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 maybe_inline
-int moreCentral(int x, int y) { // used to find end of Pop.{F}
- // Suggested implementation from the Pack200 specification:
- uint kx = (x >> 31) ^ (x << 1);
- uint 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[] = {null};
-#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 != null); // must be pre-initialized
- //if (u == null) u = unpacker::current(); // expensive
-
- int op = (meta_rp == null) ? _meta_default : (*meta_rp++ & 0xFF);
- coding* foundc = null;
- coding* to_free = null;
-
- 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 == null) {
- abort("illegal arb. 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)) {
- abort("illegal run encoding");
- return;
- }
- if ((mode & DISABLE_RUN) != 0) {
- abort("illegal nested run encoding");
- return;
- }
-
- // & 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);
- }
- CHECK;
-
- // & Enc{ BCode } if BDef=0 (ABDef != 2)
- coding_method* tail = U_NEW(coding_method, 1);
- CHECK_NULL(tail);
- 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 == null) {
- 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) {
- abort("illegal pop encoding");
- return;
- }
- if ((mode & DISABLE_POP) != 0) {
- abort("illegal nested pop encoding");
- return;
- }
-
- // 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 == null);
- 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 {
- fval.init(band_rp, band_limit, meta_rp, disPop, defc, FN, &fValueSink);
- }
- bytes fvbuf;
- fValues = (u->saveTo(fvbuf, fValueSink.b), (int*) fvbuf.ptr);
- fVlength = fValueSink.length(); // i.e., the parameter K
- fValueSink.free();
- CHECK;
-
- // Skip the first {F} run in all subsequent passes.
- // The next call to this->init(...) will set vs0.rp to point after the {F}.
-
- // & Enc{ TCode } if TDef=0 (TDefL==0)
- if (TDef != 0) {
- coding* tcode = coding::findBySpec(1, 256); // BYTE1
- // find the most narrowly sufficient code:
- for (int B = 2; B <= B_MAX; B++) {
- if (fVlength <= tcode->umax) break; // found it
- tcode->free();
- tcode = coding::findBySpec(B, TH);
- CHECK_NULL(tcode);
- }
- if (!(fVlength <= tcode->umax)) {
- abort("pop.L value too small");
- return;
- }
- this->init(band_rp, band_limit, NO_META, disPop, tcode, N, null);
- tcode->free();
- } else {
- this->init(band_rp, band_limit, meta_rp, disPop, defc, N, null);
- }
- CHECK;
-
- // Count the number of zero tokens right now.
- // Also verify that they are in bounds.
- int UN = 0; // one {U} for each zero in {T}
- value_stream vs = vs0;
- for (int i = 0; i < N; i++) {
- uint val = vs.getInt();
- if (val == 0) UN += 1;
- if (!(val <= (uint)fVlength)) {
- abort("pop token out of range");
- return;
- }
- }
- vs.done();
-
- // & Enc{ UCode } if UDef=0
- if (UN != 0) {
- uValues = U_NEW(coding_method, 1);
- CHECK_NULL(uValues);
- uValues->u = u;
- if (UDef != 0) {
- uValues->init(band_rp, band_limit, NO_META, disPop, defc, UN, null);
- } else {
- uValues->init(band_rp, band_limit, meta_rp, disPop, defc, UN, null);
- }
- } else {
- if (UDef == 0) {
- int uop = (*meta_rp++ & 0xFF);
- if (uop > _meta_canon_max)
- // %%% Spec. requires the more strict (uop != _meta_default).
- abort("bad meta-coding for empty pop/U");
- }
- }
-
- // Bug fix for 6259542
- // Last of all, adjust vs0.cmk to the 'pop' flavor
- for (coding_method* self = this; self != null; self = self->next) {
- coding_method_kind cmk2 = cmk_pop;
- switch (self->vs0.cmk) {
- case cmk_BHS0: cmk2 = cmk_pop_BHS0; break;
- case cmk_BYTE1: cmk2 = cmk_pop_BYTE1; break;
- default: break;
- }
- self->vs0.cmk = cmk2;
- if (self != this) {
- assert(self->fValues == null); // no double init
- self->fValues = this->fValues;
- self->fVlength = this->fVlength;
- assert(self->uValues == null); // must stay null
- }
- }
-
- return; // done; no falling through
-
- } else {
- abort("bad meta-coding");
- return;
- }
-
- // Common code here skips a series of values with one coding.
- assert(foundc != null);
-
- assert(vs0.cmk == cmk_ERROR); // no garbage, please
- assert(vs0.rp == null); // no garbage, please
- assert(vs0.rplimit == null); // no garbage, please
- assert(vs0.sum == 0); // no garbage, please
-
- vs0.init(band_rp, band_limit, foundc);
-
- // Done with foundc. Free if necessary.
- if (to_free != null) {
- to_free->free();
- to_free = null;
- }
- foundc = null;
-
- coding& c = vs0.c;
- CODING_PRIVATE(c.spec);
- // assert sane N
- assert((uint)N < INT_MAX_VALUE || N == POP_FAVORED_N);
-
- // Look at the values, or at least skip over them quickly.
- if (valueSink == null) {
- // Skip and ignore values in the first pass.
- c.parseMultiple(band_rp, N, band_limit, B, H);
- } else if (N >= 0) {
- // Pop coding, {F} sequence, initial run of values...
- assert((mode & DISABLE_POP) != 0);
- value_stream vs = vs0;
- for (int n = 0; n < N; n++) {
- int val = vs.getInt();
- valueSink->add(val);
- }
- band_rp = vs.rp;
- } else {
- // Pop coding, {F} sequence, final run of values...
- assert((mode & DISABLE_POP) != 0);
- assert(N == POP_FAVORED_N);
- int min = INT_MIN_VALUE; // farthest from the center
- // min2 is based on the buggy specification of centrality in version 150.7
- // no known implementations transmit this value, but just in case...
- //int min2 = INT_MIN_VALUE;
- int last = 0;
- // if there were initial runs, find the potential sentinels in them:
- for (int i = 0; i < valueSink->length(); i++) {
- last = valueSink->get(i);
- min = moreCentral(min, last);
- //min2 = moreCentral2(min2, last, min);
- }
- value_stream vs = vs0;
- for (;;) {
- int val = vs.getInt();
- if (valueSink->length() > 0 &&
- (val == last || val == min)) //|| val == min2
- break;
- valueSink->add(val);
- CHECK;
- last = val;
- min = moreCentral(min, last);
- //min2 = moreCentral2(min2, last, min);
- }
- band_rp = vs.rp;
- }
- CHECK;
-
- // Get an accurate upper limit now.
- vs0.rplimit = band_rp;
- vs0.cm = this;
-
- return; // success
-}
-
-coding basic_codings[] = {
- // This one is not a usable irregular coding, but is used by cp_Utf8_chars.
- CODING_INIT(3,128,0,0),
-
- // Fixed-length codings:
- CODING_INIT(1,256,0,0),
- CODING_INIT(1,256,1,0),
- CODING_INIT(1,256,0,1),
- CODING_INIT(1,256,1,1),
- CODING_INIT(2,256,0,0),
- CODING_INIT(2,256,1,0),
- CODING_INIT(2,256,0,1),
- CODING_INIT(2,256,1,1),
- CODING_INIT(3,256,0,0),
- CODING_INIT(3,256,1,0),
- CODING_INIT(3,256,0,1),
- CODING_INIT(3,256,1,1),
- CODING_INIT(4,256,0,0),
- CODING_INIT(4,256,1,0),
- CODING_INIT(4,256,0,1),
- CODING_INIT(4,256,1,1),
-
- // Full-range variable-length codings:
- CODING_INIT(5, 4,0,0),
- CODING_INIT(5, 4,1,0),
- CODING_INIT(5, 4,2,0),
- CODING_INIT(5, 16,0,0),
- CODING_INIT(5, 16,1,0),
- CODING_INIT(5, 16,2,0),
- CODING_INIT(5, 32,0,0),
- CODING_INIT(5, 32,1,0),
- CODING_INIT(5, 32,2,0),
- CODING_INIT(5, 64,0,0),
- CODING_INIT(5, 64,1,0),
- CODING_INIT(5, 64,2,0),
- CODING_INIT(5,128,0,0),
- CODING_INIT(5,128,1,0),
- CODING_INIT(5,128,2,0),
-
- CODING_INIT(5, 4,0,1),
- CODING_INIT(5, 4,1,1),
- CODING_INIT(5, 4,2,1),
- CODING_INIT(5, 16,0,1),
- CODING_INIT(5, 16,1,1),
- CODING_INIT(5, 16,2,1),
- CODING_INIT(5, 32,0,1),
- CODING_INIT(5, 32,1,1),
- CODING_INIT(5, 32,2,1),
- CODING_INIT(5, 64,0,1),
- CODING_INIT(5, 64,1,1),
- CODING_INIT(5, 64,2,1),
- CODING_INIT(5,128,0,1),
- CODING_INIT(5,128,1,1),
- CODING_INIT(5,128,2,1),
-
- // Variable length subrange codings:
- CODING_INIT(2,192,0,0),
- CODING_INIT(2,224,0,0),
- CODING_INIT(2,240,0,0),
- CODING_INIT(2,248,0,0),
- CODING_INIT(2,252,0,0),
-
- CODING_INIT(2, 8,0,1),
- CODING_INIT(2, 8,1,1),
- CODING_INIT(2, 16,0,1),
- CODING_INIT(2, 16,1,1),
- CODING_INIT(2, 32,0,1),
- CODING_INIT(2, 32,1,1),
- CODING_INIT(2, 64,0,1),
- CODING_INIT(2, 64,1,1),
- CODING_INIT(2,128,0,1),
- CODING_INIT(2,128,1,1),
- CODING_INIT(2,192,0,1),
- CODING_INIT(2,192,1,1),
- CODING_INIT(2,224,0,1),
- CODING_INIT(2,224,1,1),
- CODING_INIT(2,240,0,1),
- CODING_INIT(2,240,1,1),
- CODING_INIT(2,248,0,1),
- CODING_INIT(2,248,1,1),
-
- CODING_INIT(3,192,0,0),
- CODING_INIT(3,224,0,0),
- CODING_INIT(3,240,0,0),
- CODING_INIT(3,248,0,0),
- CODING_INIT(3,252,0,0),
-
- CODING_INIT(3, 8,0,1),
- CODING_INIT(3, 8,1,1),
- CODING_INIT(3, 16,0,1),
- CODING_INIT(3, 16,1,1),
- CODING_INIT(3, 32,0,1),
- CODING_INIT(3, 32,1,1),
- CODING_INIT(3, 64,0,1),
- CODING_INIT(3, 64,1,1),
- CODING_INIT(3,128,0,1),
- CODING_INIT(3,128,1,1),
- CODING_INIT(3,192,0,1),
- CODING_INIT(3,192,1,1),
- CODING_INIT(3,224,0,1),
- CODING_INIT(3,224,1,1),
- CODING_INIT(3,240,0,1),
- CODING_INIT(3,240,1,1),
- CODING_INIT(3,248,0,1),
- CODING_INIT(3,248,1,1),
-
- CODING_INIT(4,192,0,0),
- CODING_INIT(4,224,0,0),
- CODING_INIT(4,240,0,0),
- CODING_INIT(4,248,0,0),
- CODING_INIT(4,252,0,0),
-
- CODING_INIT(4, 8,0,1),
- CODING_INIT(4, 8,1,1),
- CODING_INIT(4, 16,0,1),
- CODING_INIT(4, 16,1,1),
- CODING_INIT(4, 32,0,1),
- CODING_INIT(4, 32,1,1),
- CODING_INIT(4, 64,0,1),
- CODING_INIT(4, 64,1,1),
- CODING_INIT(4,128,0,1),
- CODING_INIT(4,128,1,1),
- CODING_INIT(4,192,0,1),
- CODING_INIT(4,192,1,1),
- CODING_INIT(4,224,0,1),
- CODING_INIT(4,224,1,1),
- CODING_INIT(4,240,0,1),
- CODING_INIT(4,240,1,1),
- CODING_INIT(4,248,0,1),
- CODING_INIT(4,248,1,1),
- CODING_INIT(0,0,0,0)
-};
-#define BASIC_INDEX_LIMIT \
- (int)(sizeof(basic_codings)/sizeof(basic_codings[0])-1)
-
-coding* coding::findByIndex(int idx) {
-#ifndef PRODUCT
- /* Tricky assert here, constants and gcc complains about it without local. */
- int index_limit = BASIC_INDEX_LIMIT;
- assert(_meta_canon_min == 1 && _meta_canon_max+1 == index_limit);
-#endif
- if (idx >= _meta_canon_min && idx <= _meta_canon_max)
- return basic_codings[idx].init();
- else
- return null;
-}
-
-#ifndef PRODUCT
-const char* coding::string() {
- CODING_PRIVATE(spec);
- bytes buf;
- buf.malloc(100);
- char maxS[20], minS[20];
- sprintf(maxS, "%d", max);
- sprintf(minS, "%d", min);
- if (max == INT_MAX_VALUE) strcpy(maxS, "max");
- if (min == INT_MIN_VALUE) strcpy(minS, "min");
- sprintf((char*)buf.ptr, "(%d,%d,%d,%d) L=%d r=[%s,%s]",
- B,H,S,D,L,minS,maxS);
- return (const char*) buf.ptr;
-}
-#endif