248 lines
7.2 KiB
C
248 lines
7.2 KiB
C
/*
|
|
* Copyright (c) 2002, 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.
|
|
*/
|
|
|
|
struct unpacker;
|
|
|
|
#define INT_MAX_VALUE ((int)0x7FFFFFFF)
|
|
#define INT_MIN_VALUE ((int)0x80000000)
|
|
|
|
#define CODING_SPEC(B, H, S, D) ((B) << 20 | (H) << 8 | (S) << 4 | (D) << 0)
|
|
#define CODING_B(x) ((x) >> 20 & 0xF)
|
|
#define CODING_H(x) ((x) >> 8 & 0xFFF)
|
|
#define CODING_S(x) ((x) >> 4 & 0xF)
|
|
#define CODING_D(x) ((x) >> 0 & 0xF)
|
|
|
|
#define CODING_INIT(B, H, S, D) \
|
|
{ \
|
|
CODING_SPEC(B, H, S, D), 0, 0, 0, 0, 0, 0, 0, 0 \
|
|
}
|
|
|
|
// For debugging purposes, some compilers do not like this and will complain.
|
|
// #define long do_not_use_C_long_types_use_jlong_or_int
|
|
// Use of the type "long" is problematic, do not use it.
|
|
|
|
struct coding
|
|
{
|
|
int spec; // B,H,S,D
|
|
|
|
// Handy values derived from the spec:
|
|
int B()
|
|
{
|
|
return CODING_B(spec);
|
|
}
|
|
int H()
|
|
{
|
|
return CODING_H(spec);
|
|
}
|
|
int S()
|
|
{
|
|
return CODING_S(spec);
|
|
}
|
|
int D()
|
|
{
|
|
return CODING_D(spec);
|
|
}
|
|
int L()
|
|
{
|
|
return 256 - CODING_H(spec);
|
|
}
|
|
int min, max;
|
|
int umin, umax;
|
|
char isSigned, isSubrange, isFullRange, isMalloc;
|
|
|
|
coding *init(); // returns self or nullptr if error
|
|
coding *initFrom(int spec_)
|
|
{
|
|
assert(this->spec == 0);
|
|
this->spec = spec_;
|
|
return init();
|
|
}
|
|
|
|
static coding *findBySpec(int spec);
|
|
static coding *findBySpec(int B, int H, int S = 0, int D = 0);
|
|
static coding *findByIndex(int irregularCodingIndex);
|
|
|
|
static uint32_t parse(byte *&rp, int B, int H);
|
|
static uint32_t parse_lgH(byte *&rp, int B, int H, int lgH);
|
|
static void parseMultiple(byte *&rp, int N, byte *limit, int B, int H);
|
|
|
|
uint32_t parse(byte *&rp)
|
|
{
|
|
return parse(rp, CODING_B(spec), CODING_H(spec));
|
|
}
|
|
void parseMultiple(byte *&rp, int N, byte *limit)
|
|
{
|
|
parseMultiple(rp, N, limit, CODING_B(spec), CODING_H(spec));
|
|
}
|
|
|
|
bool canRepresent(int x)
|
|
{
|
|
return (x >= min && x <= max);
|
|
}
|
|
bool canRepresentUnsigned(int x)
|
|
{
|
|
return (x >= umin && x <= umax);
|
|
}
|
|
|
|
int sumInUnsignedRange(int x, int y);
|
|
|
|
int readFrom(byte *&rpVar, int *dbase);
|
|
void readArrayFrom(byte *&rpVar, int *dbase, int length, int *values);
|
|
void skipArrayFrom(byte *&rpVar, int length)
|
|
{
|
|
readArrayFrom(rpVar, (int *)NULL, length, (int *)NULL);
|
|
}
|
|
|
|
void free(); // free self if isMalloc
|
|
};
|
|
|
|
enum coding_method_kind
|
|
{
|
|
cmk_ERROR,
|
|
cmk_BHS,
|
|
cmk_BHS0,
|
|
cmk_BHS1,
|
|
cmk_BHSD1,
|
|
cmk_BHS1D1full, // isFullRange
|
|
cmk_BHS1D1sub, // isSubRange
|
|
|
|
// special cases hand-optimized (~50% of all decoded values)
|
|
cmk_BYTE1, //(1,256) 6%
|
|
cmk_CHAR3, //(3,128) 7%
|
|
cmk_UNSIGNED5, //(5,64) 13%
|
|
cmk_DELTA5, //(5,64,1,1) 5%
|
|
cmk_BCI5, //(5,4) 18%
|
|
cmk_BRANCH5, //(5,4,2) 4%
|
|
// cmk_UNSIGNED5H16, //(5,16) 5%
|
|
// cmk_UNSIGNED2H4, //(2,4) 6%
|
|
// cmk_DELTA4H8, //(4,8,1,1) 10%
|
|
// cmk_DELTA3H16, //(3,16,1,1) 9%
|
|
cmk_BHS_LIMIT,
|
|
cmk_pop,
|
|
cmk_pop_BHS0,
|
|
cmk_pop_BYTE1,
|
|
cmk_pop_LIMIT,
|
|
cmk_LIMIT
|
|
};
|
|
|
|
enum
|
|
{
|
|
BYTE1_spec = CODING_SPEC(1, 256, 0, 0),
|
|
CHAR3_spec = CODING_SPEC(3, 128, 0, 0),
|
|
UNSIGNED4_spec = CODING_SPEC(4, 256, 0, 0),
|
|
UNSIGNED5_spec = CODING_SPEC(5, 64, 0, 0),
|
|
SIGNED5_spec = CODING_SPEC(5, 64, 1, 0),
|
|
DELTA5_spec = CODING_SPEC(5, 64, 1, 1),
|
|
UDELTA5_spec = CODING_SPEC(5, 64, 0, 1),
|
|
MDELTA5_spec = CODING_SPEC(5, 64, 2, 1),
|
|
BCI5_spec = CODING_SPEC(5, 4, 0, 0),
|
|
BRANCH5_spec = CODING_SPEC(5, 4, 2, 0)
|
|
};
|
|
|
|
enum
|
|
{
|
|
B_MAX = 5,
|
|
C_SLOP = B_MAX * 10
|
|
};
|
|
|
|
struct coding_method;
|
|
|
|
// iterator under the control of a meta-coding
|
|
struct value_stream
|
|
{
|
|
// current coding of values or values
|
|
coding c; // B,H,S,D,etc.
|
|
coding_method_kind cmk; // type of decoding needed
|
|
byte *rp; // read pointer
|
|
byte *rplimit; // final value of read pointer
|
|
int sum; // partial sum of all values so far (D=1 only)
|
|
coding_method *cm; // coding method that defines this stream
|
|
|
|
void init(byte *band_rp, byte *band_limit, coding *defc);
|
|
void init(byte *band_rp, byte *band_limit, int spec)
|
|
{
|
|
init(band_rp, band_limit, coding::findBySpec(spec));
|
|
}
|
|
|
|
void setCoding(coding *c);
|
|
void setCoding(int spec)
|
|
{
|
|
setCoding(coding::findBySpec(spec));
|
|
}
|
|
|
|
// Parse and decode a single value.
|
|
int getInt();
|
|
|
|
// Parse and decode a single byte, with no error checks.
|
|
int getByte()
|
|
{
|
|
assert(cmk == cmk_BYTE1);
|
|
assert(rp < rplimit);
|
|
return *rp++ & 0xFF;
|
|
}
|
|
|
|
// Used only for asserts.
|
|
bool hasValue();
|
|
|
|
void done()
|
|
{
|
|
assert(!hasValue());
|
|
}
|
|
|
|
// Sometimes a value stream has an auxiliary (but there are never two).
|
|
value_stream *helper()
|
|
{
|
|
assert(hasHelper());
|
|
return this + 1;
|
|
}
|
|
bool hasHelper();
|
|
};
|
|
|
|
struct coding_method
|
|
{
|
|
value_stream vs0; // initial state snapshot (vs.meta==this)
|
|
|
|
coding_method *next; // what to do when we run out of bytes
|
|
|
|
// these fields are used for pop codes only:
|
|
int *fValues; // favored value array
|
|
int fVlength; // maximum favored value token
|
|
coding_method *uValues; // unfavored value stream
|
|
|
|
// pointer to outer unpacker, for error checks etc.
|
|
unpacker *u;
|
|
|
|
// Initialize a value stream.
|
|
void reset(value_stream *state);
|
|
|
|
// Parse a band header, size a band, and initialize for further action.
|
|
// band_rp advances (but not past band_limit), and meta_rp advances.
|
|
// The mode gives context, such as "inside a pop".
|
|
// The defc and N are the incoming parameters to a meta-coding.
|
|
// The value sink is used to collect output values, when desired.
|
|
void init(byte *&band_rp, byte *band_limit, byte *&meta_rp, int mode, coding *defc, int N,
|
|
intlist *valueSink);
|
|
};
|