summaryrefslogtreecommitdiff
path: root/client/glz_decode_tmpl.c
diff options
context:
space:
mode:
Diffstat (limited to 'client/glz_decode_tmpl.c')
-rw-r--r--client/glz_decode_tmpl.c335
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
+