summaryrefslogtreecommitdiffstats
path: root/common/lz_decompress_tmpl.c
diff options
context:
space:
mode:
Diffstat (limited to 'common/lz_decompress_tmpl.c')
-rw-r--r--common/lz_decompress_tmpl.c317
1 files changed, 317 insertions, 0 deletions
diff --git a/common/lz_decompress_tmpl.c b/common/lz_decompress_tmpl.c
new file mode 100644
index 00000000..36502c66
--- /dev/null
+++ b/common/lz_decompress_tmpl.c
@@ -0,0 +1,317 @@
+/*
+
+ Copyright 2009 Red Hat, Inc. and/or its affiliates.
+
+ This program is licensed to you under the GNU General Public License,
+ version 2 or (at your option) any later version published by the Free
+ Software Foundation. See the file COPYING for details.
+
+ There is NO WARRANTY for this software, not even the implied
+ warranties of MERCHANTABILITY, NONINFRINGEMENT, or FITNESS FOR A
+ PARTICULAR PURPOSE.
+
+ This file incorporates work covered by the following copyright and
+ permission notice:
+ Copyright (C) 2007 Ariya Hidayat (ariya@kde.org)
+ Copyright (C) 2006 Ariya Hidayat (ariya@kde.org)
+ Copyright (C) 2005 Ariya Hidayat (ariya@kde.org)
+
+ Permission is hereby granted, free of charge, to any person
+ obtaining a copy of this software and associated documentation
+ files (the "Software"), to deal in the Software without
+ restriction, including without limitation the rights to use, copy,
+ modify, merge, publish, distribute, sublicense, and/or sell copies
+ of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be
+ included in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+
+*/
+
+// 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) lz_plt_##name
+#define COPY_COMP_PIXEL(encoder, out) {out->a = decode(encoder); 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) lz_plt8_to_rgb32_##name
+#define COPY_COMP_PIXEL(encoder, out) { \
+ uint32_t rgb = encoder->palette->ents[decode(encoder)]; \
+ COPY_PLT_ENTRY(rgb, out); \
+ out++;}
+#elif defined(PLT4_BE)
+#define FNAME(name) lz_plt4_be_to_rgb32_##name
+#define COPY_COMP_PIXEL(encoder, out){ \
+ uint8_t byte = decode(encoder); \
+ uint32_t rgb = encoder->palette->ents[((byte >> 4) & 0x0f) % (encoder->palette->num_ents)]; \
+ COPY_PLT_ENTRY(rgb, out); \
+ out++; \
+ rgb = encoder->palette->ents[(byte & 0x0f) % (encoder->palette->num_ents)]; \
+ COPY_PLT_ENTRY(rgb, out); \
+ out++; \
+}
+#define CAST_PLT_DISTANCE(dist) (dist*2)
+#elif defined(PLT4_LE)
+#define FNAME(name) lz_plt4_le_to_rgb32_##name
+#define COPY_COMP_PIXEL(encoder, out){ \
+ uint8_t byte = decode(encoder); \
+ uint32_t rgb = encoder->palette->ents[(byte & 0x0f) % (encoder->palette->num_ents)]; \
+ COPY_PLT_ENTRY(rgb, out); \
+ out++; \
+ rgb = encoder->palette->ents[((byte >> 4) & 0x0f) % (encoder->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) lz_plt1_be_to_rgb32_##name
+#define COPY_COMP_PIXEL(encoder, out){ \
+ uint8_t byte = decode(encoder); \
+ int i; \
+ uint32_t fore = encoder->palette->ents[1]; \
+ uint32_t back = encoder->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) lz_plt1_le_to_rgb32_##name
+#define COPY_COMP_PIXEL(encoder, out){ \
+ uint8_t byte = decode(encoder); \
+ int i; \
+ uint32_t fore = encoder->palette->ents[1]; \
+ uint32_t back = encoder->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) lz_rgb16_##name
+#define COPY_COMP_PIXEL(e, out) {*out = ((decode(e) << 8) | decode(e)); out++;}
+#else
+#define OUT_PIXEL rgb32_pixel_t
+#define FNAME(name) lz_rgb16_to_rgb32_##name
+#define COPY_COMP_PIXEL(e, out) { \
+ out->r = decode(e); \
+ out->b = decode(e); \
+ 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) lz_rgb24_##name
+#define COPY_COMP_PIXEL(e, out) {out->b = decode(e); out->g = decode(e); out->r = decode(e); out++;}
+#endif
+
+#ifdef LZ_RGB32
+#define OUT_PIXEL rgb32_pixel_t
+#define FNAME(name) lz_rgb32_##name
+#define COPY_COMP_PIXEL(e, out) { \
+ out->b = decode(e); \
+ out->g = decode(e); \
+ out->r = decode(e); \
+ out->pad = 0; \
+ out++; \
+}
+#endif
+
+#ifdef LZ_RGB_ALPHA
+#define OUT_PIXEL rgb32_pixel_t
+#define FNAME(name) lz_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(e, out) {out->pad = decode(e); out++;}
+#endif
+
+// return num of bytes in out_buf
+static size_t FNAME(decompress)(Encoder *encoder, OUT_PIXEL *out_buf, int size)
+{
+ OUT_PIXEL *op = out_buf;
+ OUT_PIXEL *op_limit = out_buf + size;
+ uint32_t ctrl = decode(encoder);
+ int loop = TRUE;
+
+ do {
+ const OUT_PIXEL *ref = op;
+ uint32_t len = ctrl >> 5;
+ uint32_t ofs = (ctrl & 31) << 8; // 5 MSb of distance
+
+ if (ctrl >= MAX_COPY) { // reference (dictionary/RLE)
+ /* retrieving the reference and the match length */
+
+ uint8_t code;
+ len--;
+ //ref -= ofs;
+ if (len == 7 - 1) { // match length is bigger than 7
+ do {
+ code = decode(encoder);
+ len += code;
+ } while (code == 255); // remaining of len
+ }
+ code = decode(encoder);
+ ofs += code;
+
+ /* match from 16-bit distance */
+ if (LZ_UNEXPECT_CONDITIONAL(code == 255)) {
+ if (LZ_EXPECT_CONDITIONAL((ofs - code) == (31 << 8))) {
+ ofs = decode(encoder) << 8;
+ ofs += decode(encoder);
+ ofs += MAX_DISTANCE;
+ }
+ }
+
+#if defined(LZ_PLT) || defined(LZ_RGB_ALPHA)
+ len += 3; // length is biased by 2 + 1 (fixing bias)
+#elif defined(LZ_RGB16)
+ len += 2; // length is biased by 1 + 1 (fixing bias)
+#else
+ len += 1;
+#endif
+ 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)
+ ofs = CAST_PLT_DISTANCE(ofs);
+ len = CAST_PLT_DISTANCE(len);
+#endif
+#endif
+ ref -= ofs;
+
+ ASSERT(encoder->usr, op + len <= op_limit);
+ ASSERT(encoder->usr, ref + len <= op_limit);
+ ASSERT(encoder->usr, ref >= out_buf);
+
+ // TODO: optimize by not calling loop at least 3 times when not PLT_TO_RGB32 (len is
+ // always >=3). in PLT_TO_RGB32 len >= 3*number_of_pixels_per_byte
+
+ /* copying the match*/
+
+ if (ref == (op - 1)) { // run // TODO: 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);
+ ASSERT(encoder->usr, op <= op_limit);
+ }
+ } else {
+ for (; len; --len) {
+ COPY_REF_PIXEL(ref, op);
+ ASSERT(encoder->usr, 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))
+ ASSERT(encoder->usr, op + CAST_PLT_DISTANCE(ctrl) <= op_limit);
+#else
+ ASSERT(encoder->usr, op + ctrl <= op_limit);
+#endif
+ COPY_COMP_PIXEL(encoder, op);
+
+ ASSERT(encoder->usr, op <= op_limit);
+
+ for (--ctrl; ctrl; ctrl--) {
+ COPY_COMP_PIXEL(encoder, op);
+ ASSERT(encoder->usr, op <= op_limit);
+ }
+ }
+
+ if (LZ_EXPECT_CONDITIONAL(op < op_limit)) {
+ ctrl = decode(encoder);
+ } else {
+ loop = FALSE;
+ }
+ } while (LZ_EXPECT_CONDITIONAL(loop));
+
+ return (op - out_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
+