diff options
Diffstat (limited to 'client/glz_decode_tmpl.c')
-rw-r--r-- | client/glz_decode_tmpl.c | 335 |
1 files changed, 335 insertions, 0 deletions
diff --git a/client/glz_decode_tmpl.c b/client/glz_decode_tmpl.c new file mode 100644 index 00000000..6942b73c --- /dev/null +++ b/client/glz_decode_tmpl.c @@ -0,0 +1,335 @@ +/* + Copyright (C) 2009 Red Hat, Inc. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + This program 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 for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +// External defines: PLT, RGBX/PLTXX/ALPHA, TO_RGB32. +// If PLT4/1 and TO_RGB32 are defined, we need CAST_PLT_DISTANCE ( +// because then the number of pixels differ from the units used in the compression) + +/* + For each output pixel type the following macros are defined: + OUT_PIXEL - the output pixel type + COPY_PIXEL(p, out) - assignes the pixel to the place pointed by out and + increases out. Used in RLE. + Need special handling because in alpha we copy only + the pad byte. + COPY_REF_PIXEL(ref, out) - copies the pixel pointed by ref to the pixel pointed by out. + Increases ref and out. + COPY_COMP_PIXEL(encoder, out) - copies pixel from the compressed buffer to the decompressed + buffer. Increases out. +*/ + +#if !defined(LZ_RGB_ALPHA) +#define COPY_PIXEL(p, out) (*(out++) = p) +#define COPY_REF_PIXEL(ref, out) (*(out++) = *(ref++)) +#endif + +// decompressing plt to plt +#ifdef LZ_PLT +#ifndef TO_RGB32 +#define OUT_PIXEL one_byte_pixel_t +#define FNAME(name) glz_plt_##name +#define COPY_COMP_PIXEL(in, out) {(out)->a = *(in++); out++;} +#else // TO_RGB32 +#define OUT_PIXEL rgb32_pixel_t +#define COPY_PLT_ENTRY(ent, out) {\ + (out)->b = ent; (out)->g = (ent >> 8); (out)->r = (ent >> 16); (out)->pad = 0;} +#ifdef PLT8 +#define FNAME(name) glz_plt8_to_rgb32_##name +#define COPY_COMP_PIXEL(in, out, palette) { \ + uint32_t rgb = palette->ents[*(in++)]; \ + COPY_PLT_ENTRY(rgb, out); \ + out++; \ +} +#elif defined(PLT4_BE) +#define FNAME(name) glz_plt4_be_to_rgb32_##name +#define COPY_COMP_PIXEL(in, out, palette){ \ + uint8_t byte = *(in++); \ + uint32_t rgb = palette->ents[((byte >> 4) & 0x0f) % (palette->num_ents)]; \ + COPY_PLT_ENTRY(rgb, out); \ + out++; \ + rgb = palette->ents[(byte & 0x0f) % (palette->num_ents)]; \ + COPY_PLT_ENTRY(rgb, out); \ + out++; \ +} +#define CAST_PLT_DISTANCE(dist) (dist*2) +#elif defined(PLT4_LE) +#define FNAME(name) glz_plt4_le_to_rgb32_##name +#define COPY_COMP_PIXEL(in, out, palette){ \ + uint8_t byte = *(in++); \ + uint32_t rgb = palette->ents[(byte & 0x0f) % (palette->num_ents)]; \ + COPY_PLT_ENTRY(rgb, out); \ + out++; \ + rgb = palette->ents[((byte >> 4) & 0x0f) % (palette->num_ents)]; \ + COPY_PLT_ENTRY(rgb, out); \ + out++; \ +} +#define CAST_PLT_DISTANCE(dist) (dist*2) +#elif defined(PLT1_BE) // TODO store palette entries for direct access +#define FNAME(name) glz_plt1_be_to_rgb32_##name +#define COPY_COMP_PIXEL(in, out, palette){ \ + uint8_t byte = *(in++); \ + int i; \ + uint32_t fore = palette->ents[1]; \ + uint32_t back = palette->ents[0]; \ + for (i = 7; i >= 0; i--) \ + { \ + if ((byte >> i) & 1) { \ + COPY_PLT_ENTRY(fore, out); \ + } else { \ + COPY_PLT_ENTRY(back, out); \ + } \ + out++; \ + } \ +} +#define CAST_PLT_DISTANCE(dist) (dist*8) +#elif defined(PLT1_LE) +#define FNAME(name) glz_plt1_le_to_rgb32_##name +#define COPY_COMP_PIXEL(in, out, palette){ \ + uint8_t byte = *(in++); \ + int i; \ + uint32_t fore = palette->ents[1]; \ + uint32_t back = palette->ents[0]; \ + for (i = 0; i < 8; i++) \ + { \ + if ((byte >> i) & 1) { \ + COPY_PLT_ENTRY(fore, out); \ + } else { \ + COPY_PLT_ENTRY(back, out); \ + } \ + out++; \ + } \ +} +#define CAST_PLT_DISTANCE(dist) (dist*8) +#endif // PLT Type +#endif // TO_RGB32 +#endif + +#ifdef LZ_RGB16 +#ifndef TO_RGB32 +#define OUT_PIXEL rgb16_pixel_t +#define FNAME(name) glz_rgb16_##name +#define COPY_COMP_PIXEL(in, out) {*out = (*(in++)) << 8; *out |= *(in++); out++;} +#else +#define OUT_PIXEL rgb32_pixel_t +#define FNAME(name) glz_rgb16_to_rgb32_##name +#define COPY_COMP_PIXEL(in, out) {out->r = *(in++); out->b= *(in++); \ + out->g = (((out->r) << 6) | ((out->b) >> 2)) & ~0x07; \ + out->g |= (out->g >> 5); \ + out->r = ((out->r << 1) & ~0x07) | ((out->r >> 4) & 0x07) ; \ + out->b = (out->b << 3) | ((out->b >> 2) & 0x07); \ + out->pad = 0; \ + out++; \ +} +#endif +#endif + +#ifdef LZ_RGB24 +#define OUT_PIXEL rgb24_pixel_t +#define FNAME(name) glz_rgb24_##name +#define COPY_COMP_PIXEL(in, out) { \ + out->b = *(in++); \ + out->g = *(in++); \ + out->r = *(in++); \ + out++; \ +} +#endif + +#ifdef LZ_RGB32 +#define OUT_PIXEL rgb32_pixel_t +#define FNAME(name) glz_rgb32_##name +#define COPY_COMP_PIXEL(in, out) { \ + out->b = *(in++); \ + out->g = *(in++); \ + out->r = *(in++); \ + out->pad = 0; \ + out++; \ +} +#endif + +#ifdef LZ_RGB_ALPHA +#define OUT_PIXEL rgb32_pixel_t +#define FNAME(name) glz_rgb_alpha_##name +#define COPY_PIXEL(p, out) {out->pad = p.pad; out++;} +#define COPY_REF_PIXEL(ref, out) {out->pad = ref->pad; out++; ref++;} +#define COPY_COMP_PIXEL(in, out) {out->pad = *(in++); out++;} +#endif + +// TODO: seperate into routines that decode to dist,len. and to a routine that +// actualy copies the data. + +/* returns num of bytes read from in buf. + size should be in PIXEL */ +static size_t FNAME(decode)(GlzDecoderWindow &window, uint8_t* in_buf, + uint8_t *out_buf, int size, + DecodedImageWinId image_win_id, Palette *plt, + GlzDecoderDebug &debug_calls) +{ + uint8_t *ip = in_buf; + OUT_PIXEL *out_pix_buf = (OUT_PIXEL *)out_buf; + OUT_PIXEL *op = out_pix_buf; + OUT_PIXEL *op_limit = out_pix_buf + size; + + uint32_t ctrl = *(ip++); + int loop = true; + + do { + if (ctrl >= MAX_COPY) { // reference (dictionary/RLE) + OUT_PIXEL *ref = op; + uint32_t len = ctrl >> 5; + uint8_t pixel_flag = (ctrl >> 4) & 0x01; + uint32_t pixel_ofs = (ctrl & 0x0f); + uint8_t image_flag; + uint32_t image_dist; + + /* retrieving the referenced images, the offset of the first pixel, + and the match length */ + + uint8_t code; + //len--; // TODO: why do we do this? + + if (len == 7) { // match length is bigger than 7 + do { + code = *(ip++); + len += code; + } while (code == 255); // remaining of len + } + code = *(ip++); + pixel_ofs += (code << 4); + + code = *(ip++); + image_flag = (code >> 6) & 0x03; + if (!pixel_flag) { // short pixel offset + image_dist = code & 0x3f; + for (int i = 0; i < image_flag; i++) { + code = *(ip++); + image_dist += (code << (6 + (8 * i))); + } + } else { + pixel_flag = (code >> 5) & 0x01; + pixel_ofs += (code & 0x1f) << 12; + image_dist = 0; + for (int i = 0; i < image_flag; i++) { + code = *(ip++); + image_dist += (code << 8 * i); + } + + + if (pixel_flag) { // very long pixel offset + code = *(ip++); + pixel_ofs += code << 17; + } + } + +#if defined(LZ_PLT) || defined(LZ_RGB_ALPHA) + len += 2; // length is biased by 2 (fixing bias) +#elif defined(LZ_RGB16) + len += 1; // length is biased by 1 (fixing bias) +#endif + if (!image_dist) { + pixel_ofs += 1; // offset is biased by 1 (fixing bias) + } + +#if defined(TO_RGB32) +#if defined(PLT4_BE) || defined(PLT4_LE) || defined(PLT1_BE) || defined(PLT1_LE) + pixel_ofs = CAST_PLT_DISTANCE(pixel_ofs); + len = CAST_PLT_DISTANCE(len); +#endif +#endif + + if (!image_dist) { // reference is inside the same image + ref -= pixel_ofs; + GLZ_ASSERT(debug_calls, ref + len <= op_limit); + GLZ_ASSERT(debug_calls, ref >= out_pix_buf); + } else { + ref = (OUT_PIXEL *)window.get_ref_pixel(image_win_id, image_dist, + pixel_ofs); + } + + GLZ_ASSERT(debug_calls, op + len <= op_limit); + + /* copying the match*/ + + if (ref == (op - 1)) { // run (this will never be called in PLT4/1_TO_RGB because the + // number of pixel copied is larger then one... + /* optimize copy for a run */ + OUT_PIXEL b = *ref; + for (; len; --len) { + COPY_PIXEL(b, op); + GLZ_ASSERT(debug_calls, op <= op_limit); + } + } else { + for (; len; --len) { + COPY_REF_PIXEL(ref, op); + GLZ_ASSERT(debug_calls, op <= op_limit); + } + } + } else { // copy + ctrl++; // copy count is biased by 1 +#if defined(TO_RGB32) && (defined(PLT4_BE) || defined(PLT4_LE) || defined(PLT1_BE) || \ + defined(PLT1_LE)) + GLZ_ASSERT(debug_calls, op + CAST_PLT_DISTANCE(ctrl) <= op_limit); +#else + GLZ_ASSERT(debug_calls, op + ctrl <= op_limit); +#endif + +#if defined(TO_RGB32) && defined(LZ_PLT) + GLZ_ASSERT(debug_calls, plt); + COPY_COMP_PIXEL(ip, op, plt); +#else + COPY_COMP_PIXEL(ip, op); +#endif + GLZ_ASSERT(debug_calls, op <= op_limit); + + for (--ctrl; ctrl; ctrl--) { +#if defined(TO_RGB32) && defined(LZ_PLT) + GLZ_ASSERT(debug_calls, plt); + COPY_COMP_PIXEL(ip, op, plt); +#else + COPY_COMP_PIXEL(ip, op); +#endif + GLZ_ASSERT(debug_calls, op <= op_limit); + } + } // END REF/COPY + + if (LZ_EXPECT_CONDITIONAL(op < op_limit)) { + ctrl = *(ip++); + } else { + loop = false; + } + } while (LZ_EXPECT_CONDITIONAL(loop)); + + return (ip - in_buf); +} +#undef LZ_PLT +#undef PLT8 +#undef PLT4_BE +#undef PLT4_LE +#undef PLT1_BE +#undef PLT1_LE +#undef LZ_RGB16 +#undef LZ_RGB24 +#undef LZ_RGB32 +#undef LZ_RGB_ALPHA +#undef TO_RGB32 +#undef OUT_PIXEL +#undef FNAME +#undef COPY_PIXEL +#undef COPY_REF_PIXEL +#undef COPY_COMP_PIXEL +#undef COPY_PLT_ENTRY +#undef CAST_PLT_DISTANCE + |