1 /*
2 Copyright (C) 2009 Red Hat, Inc.
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public
15 License along with this library; if not, see <http://www.gnu.org/licenses/>.
16 */
17
18 // External defines: PLT, RGBX/PLTXX/ALPHA, TO_RGB32.
19 // If PLT4/1 and TO_RGB32 are defined, we need CAST_PLT_DISTANCE (
20 // because then the number of pixels differ from the units used in the compression)
21
22 /*
23 For each output pixel type the following macros are defined:
24 OUT_PIXEL - the output pixel type
25 COPY_PIXEL(p, out) - assigns the pixel to the place pointed by out and
26 increases out. Used in RLE.
27 Need special handling because in alpha we copy only
28 the pad byte.
29 COPY_REF_PIXEL(ref, out) - copies the pixel pointed by ref to the pixel pointed by out.
30 Increases ref and out.
31 COPY_COMP_PIXEL(encoder, out) - copies pixel from the compressed buffer to the decompressed
32 buffer. Increases out.
33 */
34
35 #if !defined(LZ_RGB_ALPHA)
36 #define COPY_PIXEL(p, out) (*(out++) = p)
37 #define COPY_REF_PIXEL(ref, out) (*(out++) = *(ref++))
38 #endif
39
40 // decompressing plt to plt
41 #ifdef LZ_PLT
42 #ifndef TO_RGB32
43 #define OUT_PIXEL one_byte_pixel_t
44 #define FNAME(name) glz_plt_##name
45 #define COPY_COMP_PIXEL(in, out) {(out)->a = *(in++); out++;}
46 #else // TO_RGB32
47 #define OUT_PIXEL rgb32_pixel_t
48 #define COPY_PLT_ENTRY(ent, out) {\
49 (out)->b = ent; (out)->g = (ent >> 8); (out)->r = (ent >> 16); (out)->pad = 0;}
50 #ifdef PLT8
51 #define FNAME(name) glz_plt8_to_rgb32_##name
52 #define COPY_COMP_PIXEL(in, out, palette) { \
53 uint32_t rgb = palette->ents[*(in++)]; \
54 COPY_PLT_ENTRY(rgb, out); \
55 out++; \
56 }
57 #elif defined(PLT4_BE)
58 #define FNAME(name) glz_plt4_be_to_rgb32_##name
59 #define COPY_COMP_PIXEL(in, out, palette){ \
60 uint8_t byte = *(in++); \
61 uint32_t rgb = palette->ents[((byte >> 4) & 0x0f) % (palette->num_ents)]; \
62 COPY_PLT_ENTRY(rgb, out); \
63 out++; \
64 rgb = palette->ents[(byte & 0x0f) % (palette->num_ents)]; \
65 COPY_PLT_ENTRY(rgb, out); \
66 out++; \
67 }
68 #define CAST_PLT_DISTANCE(dist) (dist*2)
69 #elif defined(PLT4_LE)
70 #define FNAME(name) glz_plt4_le_to_rgb32_##name
71 #define COPY_COMP_PIXEL(in, out, palette){ \
72 uint8_t byte = *(in++); \
73 uint32_t rgb = palette->ents[(byte & 0x0f) % (palette->num_ents)]; \
74 COPY_PLT_ENTRY(rgb, out); \
75 out++; \
76 rgb = palette->ents[((byte >> 4) & 0x0f) % (palette->num_ents)]; \
77 COPY_PLT_ENTRY(rgb, out); \
78 out++; \
79 }
80 #define CAST_PLT_DISTANCE(dist) (dist*2)
81 #elif defined(PLT1_BE) // TODO store palette entries for direct access
82 #define FNAME(name) glz_plt1_be_to_rgb32_##name
83 #define COPY_COMP_PIXEL(in, out, palette){ \
84 uint8_t byte = *(in++); \
85 int i; \
86 uint32_t fore = palette->ents[1]; \
87 uint32_t back = palette->ents[0]; \
88 for (i = 7; i >= 0; i--) \
89 { \
90 if ((byte >> i) & 1) { \
91 COPY_PLT_ENTRY(fore, out); \
92 } else { \
93 COPY_PLT_ENTRY(back, out); \
94 } \
95 out++; \
96 } \
97 }
98 #define CAST_PLT_DISTANCE(dist) (dist*8)
99 #elif defined(PLT1_LE)
100 #define FNAME(name) glz_plt1_le_to_rgb32_##name
101 #define COPY_COMP_PIXEL(in, out, palette){ \
102 uint8_t byte = *(in++); \
103 int i; \
104 uint32_t fore = palette->ents[1]; \
105 uint32_t back = palette->ents[0]; \
106 for (i = 0; i < 8; i++) \
107 { \
108 if ((byte >> i) & 1) { \
109 COPY_PLT_ENTRY(fore, out); \
110 } else { \
111 COPY_PLT_ENTRY(back, out); \
112 } \
113 out++; \
114 } \
115 }
116 #define CAST_PLT_DISTANCE(dist) (dist*8)
117 #endif // PLT Type
118 #endif // TO_RGB32
119 #endif
120
121 #ifdef LZ_RGB16
122 #ifndef TO_RGB32
123 #define OUT_PIXEL rgb16_pixel_t
124 #define FNAME(name) glz_rgb16_##name
125 #define COPY_COMP_PIXEL(in, out) {*out = (*(in++)) << 8; *out |= *(in++); out++;}
126 #else
127 #define OUT_PIXEL rgb32_pixel_t
128 #define FNAME(name) glz_rgb16_to_rgb32_##name
129 #define COPY_COMP_PIXEL(in, out) {out->r = *(in++); out->b= *(in++); \
130 out->g = (((out->r) << 6) | ((out->b) >> 2)) & ~0x07; \
131 out->g |= (out->g >> 5); \
132 out->r = ((out->r << 1) & ~0x07) | ((out->r >> 4) & 0x07) ; \
133 out->b = (out->b << 3) | ((out->b >> 2) & 0x07); \
134 out->pad = 0; \
135 out++; \
136 }
137 #endif
138 #endif
139
140 #ifdef LZ_RGB24
141 #define OUT_PIXEL rgb24_pixel_t
142 #define FNAME(name) glz_rgb24_##name
143 #define COPY_COMP_PIXEL(in, out) { \
144 out->b = *(in++); \
145 out->g = *(in++); \
146 out->r = *(in++); \
147 out++; \
148 }
149 #endif
150
151 #ifdef LZ_RGB32
152 #define OUT_PIXEL rgb32_pixel_t
153 #define FNAME(name) glz_rgb32_##name
154 #define COPY_COMP_PIXEL(in, out) { \
155 out->b = *(in++); \
156 out->g = *(in++); \
157 out->r = *(in++); \
158 out->pad = 0; \
159 out++; \
160 }
161 #endif
162
163 #ifdef LZ_RGB_ALPHA
164 #define OUT_PIXEL rgb32_pixel_t
165 #define FNAME(name) glz_rgb_alpha_##name
166 #define COPY_PIXEL(p, out) {out->pad = p.pad; out++;}
167 #define COPY_REF_PIXEL(ref, out) {out->pad = ref->pad; out++; ref++;}
168 #define COPY_COMP_PIXEL(in, out) {out->pad = *(in++); out++;}
169 #endif
170
171 // TODO: separate into routines that decode to dist,len. and to a routine that
172 // actually copies the data.
173
174 /* returns num of bytes read from in buf.
175 size should be in PIXEL */
FNAME(decode)176 static size_t FNAME(decode)(SpiceGlzDecoderWindow *window,
177 uint8_t* in_buf, uint8_t *out_buf, int size,
178 uint64_t image_id, SpicePalette *plt)
179 {
180 uint8_t *ip = in_buf;
181 OUT_PIXEL *out_pix_buf = SPICE_ALIGNED_CAST(OUT_PIXEL *, out_buf);
182 OUT_PIXEL *op = out_pix_buf;
183 OUT_PIXEL *op_limit = out_pix_buf + size;
184
185 uint32_t ctrl = *(ip++);
186 int loop = true;
187
188 do {
189 if (ctrl >= MAX_COPY) { // reference (dictionary/RLE)
190 OUT_PIXEL *ref = op;
191 uint32_t len = ctrl >> 5;
192 uint8_t pixel_flag = (ctrl >> 4) & 0x01;
193 uint32_t pixel_ofs = (ctrl & 0x0f);
194 uint8_t image_flag;
195 uint32_t image_dist;
196
197 /* retrieving the referenced images, the offset of the first pixel,
198 and the match length */
199
200 uint8_t code;
201 //len--; // TODO: why do we do this?
202
203 if (len == 7) { // match length is bigger than 7
204 do {
205 code = *(ip++);
206 len += code;
207 } while (code == 255); // remaining of len
208 }
209 code = *(ip++);
210 pixel_ofs += (code << 4);
211
212 code = *(ip++);
213 image_flag = (code >> 6) & 0x03;
214 if (!pixel_flag) { // short pixel offset
215 int i;
216 image_dist = code & 0x3f;
217 for (i = 0; i < image_flag; i++) {
218 code = *(ip++);
219 image_dist += (code << (6 + (8 * i)));
220 }
221 } else {
222 int i;
223 pixel_flag = (code >> 5) & 0x01;
224 pixel_ofs += (code & 0x1f) << 12;
225 image_dist = 0;
226 for (i = 0; i < image_flag; i++) {
227 code = *(ip++);
228 image_dist += (code << 8 * i);
229 }
230
231
232 if (pixel_flag) { // very long pixel offset
233 code = *(ip++);
234 pixel_ofs += code << 17;
235 }
236 }
237
238 #if defined(LZ_PLT) || defined(LZ_RGB_ALPHA)
239 len += 2; // length is biased by 2 (fixing bias)
240 #elif defined(LZ_RGB16)
241 len += 1; // length is biased by 1 (fixing bias)
242 #endif
243 if (!image_dist) {
244 pixel_ofs += 1; // offset is biased by 1 (fixing bias)
245 }
246
247 #if defined(TO_RGB32)
248 #if defined(PLT4_BE) || defined(PLT4_LE) || defined(PLT1_BE) || defined(PLT1_LE)
249 pixel_ofs = CAST_PLT_DISTANCE(pixel_ofs);
250 len = CAST_PLT_DISTANCE(len);
251 #endif
252 #endif
253
254 if (!image_dist) { // reference is inside the same image
255 ref -= pixel_ofs;
256 g_return_val_if_fail(ref + len <= op_limit, 0);
257 g_return_val_if_fail(ref >= out_pix_buf, 0);
258 } else {
259 ref = glz_decoder_window_bits(window, image_id,
260 image_dist, pixel_ofs);
261 }
262
263 g_return_val_if_fail(ref != NULL, 0);
264 g_return_val_if_fail(op + len <= op_limit, 0);
265
266 /* copying the match*/
267
268 if (ref == (op - 1)) { // run (this will never be called in PLT4/1_TO_RGB because the
269 // number of pixel copied is larger then one...
270 /* optimize copy for a run */
271 OUT_PIXEL b = *ref;
272 for (; len; --len) {
273 COPY_PIXEL(b, op);
274 g_return_val_if_fail(op <= op_limit, 0);
275 }
276 } else {
277 for (; len; --len) {
278 COPY_REF_PIXEL(ref, op);
279 g_return_val_if_fail(op <= op_limit, 0);
280 }
281 }
282 } else { // copy
283 ctrl++; // copy count is biased by 1
284 #if defined(TO_RGB32) && (defined(PLT4_BE) || defined(PLT4_LE) || defined(PLT1_BE) || \
285 defined(PLT1_LE))
286 g_return_val_if_fail(op + CAST_PLT_DISTANCE(ctrl) <= op_limit, 0);
287 #else
288 g_return_val_if_fail(op + ctrl <= op_limit, 0);
289 #endif
290
291 #if defined(TO_RGB32) && defined(LZ_PLT)
292 g_return_val_if_fail(plt, 0);
293 COPY_COMP_PIXEL(ip, op, plt);
294 #else
295 COPY_COMP_PIXEL(ip, op);
296 #endif
297 g_return_val_if_fail(op <= op_limit, 0);
298
299 for (--ctrl; ctrl; ctrl--) {
300 #if defined(TO_RGB32) && defined(LZ_PLT)
301 g_return_val_if_fail(plt, 0);
302 COPY_COMP_PIXEL(ip, op, plt);
303 #else
304 COPY_COMP_PIXEL(ip, op);
305 #endif
306 g_return_val_if_fail(op <= op_limit, 0);
307 }
308 } // END REF/COPY
309
310 if (LZ_EXPECT_CONDITIONAL(op < op_limit)) {
311 ctrl = *(ip++);
312 } else {
313 loop = false;
314 }
315 } while (LZ_EXPECT_CONDITIONAL(loop));
316
317 return (ip - in_buf);
318 }
319 #undef LZ_PLT
320 #undef PLT8
321 #undef PLT4_BE
322 #undef PLT4_LE
323 #undef PLT1_BE
324 #undef PLT1_LE
325 #undef LZ_RGB16
326 #undef LZ_RGB24
327 #undef LZ_RGB32
328 #undef LZ_RGB_ALPHA
329 #undef TO_RGB32
330 #undef OUT_PIXEL
331 #undef FNAME
332 #undef COPY_PIXEL
333 #undef COPY_REF_PIXEL
334 #undef COPY_COMP_PIXEL
335 #undef COPY_PLT_ENTRY
336 #undef CAST_PLT_DISTANCE
337