/src/ghostpdl/pcl/pcl/rtrstcmp.c
Line | Count | Source |
1 | | /* Copyright (C) 2001-2026 Artifex Software, Inc. |
2 | | All Rights Reserved. |
3 | | |
4 | | This software is provided AS-IS with no warranty, either express or |
5 | | implied. |
6 | | |
7 | | This software is distributed under license and may not be copied, |
8 | | modified or distributed except as expressly authorized under the terms |
9 | | of the license contained in the file LICENSE in this distribution. |
10 | | |
11 | | Refer to licensing information at http://www.artifex.com or contact |
12 | | Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco, |
13 | | CA 94129, USA, for further information. |
14 | | */ |
15 | | |
16 | | |
17 | | /* rtrstcmp.c - raster decompression routines */ |
18 | | |
19 | | #include "string_.h" |
20 | | #include "pcstate.h" |
21 | | #include "rtrstcmp.h" |
22 | | |
23 | | /* |
24 | | * Each of the decompression methods has the same structure. The operands are |
25 | | * are the seed row to be filled in and the buffer from which it is to be |
26 | | * filled. A size is provided for the latter. |
27 | | * |
28 | | * Adpative compression (mode 5) is not handled at this level, though it will |
29 | | * make use of these routines for decompressing individual raster rows. |
30 | | */ |
31 | | |
32 | | /* |
33 | | * Uncompressed data. |
34 | | */ |
35 | | static void |
36 | | uncompress_0(pcl_seed_row_t * pout, const byte * pin, int in_size) |
37 | 91.9k | { |
38 | 91.9k | int nbytes = (in_size > pout->size ? pout->size : in_size); |
39 | | |
40 | 91.9k | if (in_size >= 0) { |
41 | 91.9k | memcpy(pout->pdata, pin, nbytes); |
42 | 91.9k | if (!pout->is_blank) |
43 | 46.0k | memset(pout->pdata + nbytes, 0, pout->size - nbytes); |
44 | 91.9k | pout->is_blank = (in_size == 0); |
45 | 91.9k | } |
46 | 91.9k | } |
47 | | |
48 | | /* |
49 | | * Run-length compression. |
50 | | */ |
51 | | static void |
52 | | uncompress_1(pcl_seed_row_t * pout, const byte * pin, int in_size) |
53 | 128 | { |
54 | 128 | int i = in_size / 2; |
55 | 128 | byte *pb = pout->pdata; |
56 | 128 | byte *plim = pb + pout->size; |
57 | | |
58 | 2.19k | while (i-- > 0) { |
59 | 2.06k | int cnt = *pin++ + 1; |
60 | 2.06k | byte val = *pin++; |
61 | | |
62 | 2.06k | if (cnt > plim - pb) |
63 | 1.64k | cnt = plim - pb; |
64 | 23.2k | while (cnt-- > 0) |
65 | 21.2k | *pb++ = val; |
66 | 2.06k | } |
67 | 128 | if (!pout->is_blank) |
68 | 85 | memset(pb, 0, plim - pb); |
69 | 128 | pout->is_blank = (in_size == 0); |
70 | 128 | } |
71 | | |
72 | | /* |
73 | | * TIFF "Packbits" compression. |
74 | | */ |
75 | | static void |
76 | | uncompress_2(pcl_seed_row_t * pout, const byte * pin, int in_size) |
77 | 12.4k | { |
78 | 12.4k | int i = in_size; |
79 | 12.4k | byte *pb = pout->pdata; |
80 | 12.4k | byte *plim = pb + pout->size; |
81 | | |
82 | 73.6k | while (i-- > 0) { |
83 | 61.2k | int cntrl = *pin++; |
84 | | |
85 | 61.2k | if (cntrl < 128) { |
86 | 33.8k | uint cnt = min(cntrl + 1, i); |
87 | 33.8k | const byte *ptmp = pin; |
88 | | |
89 | 33.8k | i -= cnt; |
90 | 33.8k | pin += cnt; |
91 | 33.8k | if (cnt > plim - pb) |
92 | 472 | cnt = plim - pb; |
93 | 298k | while (cnt-- > 0) |
94 | 264k | *pb++ = *ptmp++; |
95 | | |
96 | 33.8k | } else if ((cntrl > 128) && (i-- > 0)) { |
97 | 27.4k | int cnt = min(257 - cntrl, plim - pb); |
98 | 27.4k | int val = *pin++; |
99 | | |
100 | 27.4k | memset(pb, val, cnt); |
101 | 27.4k | pb += cnt; |
102 | 27.4k | } |
103 | 61.2k | } |
104 | 12.4k | if (!pout->is_blank) |
105 | 9.89k | memset(pb, 0, plim - pb); |
106 | 12.4k | pout->is_blank = (in_size == 0); |
107 | 12.4k | } |
108 | | |
109 | | /* |
110 | | * Delta row compression |
111 | | */ |
112 | | static void |
113 | | uncompress_3(pcl_seed_row_t * pout, const byte * pin, int in_size) |
114 | 766 | { |
115 | 766 | int i = in_size; |
116 | 766 | byte *pb = pout->pdata; |
117 | 766 | byte *plim = pb + pout->size; |
118 | | |
119 | 7.23k | while (i-- > 0) { |
120 | 6.78k | uint val = *pin++; |
121 | 6.78k | uint cnt = (val >> 5) + 1; |
122 | 6.78k | uint offset = val & 0x1f; |
123 | 6.78k | const byte *ptmp = 0; |
124 | | |
125 | 6.78k | if ((offset == 0x1f) && (i-- > 0)) { |
126 | 330 | uint add_offset; |
127 | 330 | do |
128 | 404 | offset += (add_offset = *pin++); |
129 | 404 | while ((add_offset == 0xff) && (i-- > 0)); |
130 | 330 | } |
131 | | |
132 | 6.78k | if (cnt > i) |
133 | 463 | cnt = i; |
134 | 6.78k | i -= cnt; |
135 | 6.78k | ptmp = pin; |
136 | 6.78k | pin += cnt; |
137 | 6.78k | if ((pb += offset) >= plim) |
138 | 316 | break; |
139 | 6.47k | if (cnt > plim - pb) |
140 | 8 | cnt = plim - pb; |
141 | 27.9k | while (cnt-- > 0) |
142 | 21.5k | *pb++ = *ptmp++; |
143 | 6.47k | } |
144 | 766 | pout->is_blank = (pout->is_blank && (in_size == 0)); |
145 | 766 | } |
146 | | |
147 | | /* |
148 | | * Adpative compression (mode 5) is handled at a higher level. |
149 | | */ |
150 | | |
151 | | /* |
152 | | * Compression mode 9. |
153 | | */ |
154 | | static void |
155 | | uncompress_9(pcl_seed_row_t * pout, const byte * pin, int in_size) |
156 | 9 | { |
157 | 9 | int i = in_size; |
158 | 9 | byte *pb = pout->pdata; |
159 | 9 | byte *plim = pb + pout->size; |
160 | 18 | while (i-- > 0) { |
161 | 9 | uint val = *pin++; |
162 | 9 | uint cnt = 0; |
163 | 9 | uint offset = 0; |
164 | 9 | bool more_cnt = false; |
165 | 9 | bool more_offset = false; |
166 | 9 | bool comp = ((val & 0x80) != 0); |
167 | | |
168 | 9 | if (comp) { |
169 | 0 | offset = (val >> 5) & 0x3; |
170 | 0 | more_offset = (offset == 0x3); |
171 | 0 | cnt = (val & 0x1f) + 2; |
172 | 0 | more_cnt = (cnt == 0x21); |
173 | 9 | } else { |
174 | 9 | offset = (val >> 3) & 0xf; |
175 | 9 | more_offset = (offset == 0xf); |
176 | 9 | cnt = (val & 0x7) + 1; |
177 | 9 | more_cnt = (cnt == 0x8); |
178 | 9 | } |
179 | | |
180 | 9 | while (more_offset && (i > 0)) { |
181 | 0 | uint extra = *pin++; |
182 | 0 | i -= 1; |
183 | |
|
184 | 0 | more_offset = (extra == 0xff); |
185 | 0 | offset += extra; |
186 | 0 | } |
187 | 33 | while (more_cnt && (i > 0)) { |
188 | 24 | uint extra = *pin++; |
189 | 24 | i -= 1; |
190 | | |
191 | 24 | more_cnt = (extra == 0xff); |
192 | 24 | cnt += extra; |
193 | 24 | } |
194 | | |
195 | 9 | if ((pb += offset) >= plim) |
196 | 0 | break; |
197 | 9 | if (i <= 0) |
198 | 0 | break; |
199 | | |
200 | 9 | if (comp) { |
201 | 0 | if(i-- > 0) { |
202 | 0 | uint rep_val = *pin++; |
203 | |
|
204 | 0 | if (cnt > plim - pb) |
205 | 0 | cnt = plim - pb; |
206 | 0 | while (cnt-- > 0) |
207 | 0 | *pb++ = rep_val; |
208 | 0 | } |
209 | 9 | } else { |
210 | 9 | if (cnt > i) |
211 | 3 | cnt = i; |
212 | 9 | i -= cnt; |
213 | 9 | if (cnt > plim - pb) |
214 | 0 | cnt = plim - pb; |
215 | 66 | while (cnt-- > 0) |
216 | 57 | *pb++ = *pin++; |
217 | 9 | } |
218 | | |
219 | 9 | } |
220 | 9 | pout->is_blank = (pout->is_blank && (in_size == 0)); |
221 | | |
222 | 9 | } |
223 | | |
224 | | enum |
225 | | { |
226 | | eeNewPixel = 0x0, |
227 | | eeWPixel = 0x20, |
228 | | eeNEPixel = 0x40, |
229 | | eeCachedColor = 0x60 |
230 | | }; |
231 | | |
232 | | static inline uint32_t |
233 | | mode10_merge_delta(const uint8_t ** src, uint32_t oldpixel, int *countdown) |
234 | 0 | { |
235 | 0 | uint32_t pixel; |
236 | |
|
237 | 0 | if (*countdown < 2) { |
238 | 0 | return 0xffffff; |
239 | 0 | } |
240 | 0 | if (**src & 0x80) { |
241 | 0 | uint16_t delta; |
242 | 0 | int32_t dr, dg, db; |
243 | 0 | int r, g, b; |
244 | |
|
245 | 0 | if_debug2('w', "delta %02X %02X\n", **src, *(*src + 1)); |
246 | |
|
247 | 0 | delta = (**src << 8) | *(*src + 1); |
248 | 0 | dr = (delta >> 10) & 0x1f; |
249 | 0 | dg = (delta >> 5) & 0x1f; |
250 | 0 | db = (delta & 0x1f) << 1; |
251 | 0 | if (dr & 0x10) { |
252 | 0 | dr |= 0xffffffe0; |
253 | 0 | } |
254 | 0 | if (dg & 0x10) { |
255 | 0 | dg |= 0xffffffe0; |
256 | 0 | } |
257 | 0 | if (db & 0x20) { |
258 | 0 | db |= 0xffffffd0; |
259 | 0 | } |
260 | 0 | r = ((oldpixel >> 16) + dr) & 0xff; |
261 | 0 | g = ((oldpixel >> 8) + dg) & 0xff; |
262 | 0 | b = ((oldpixel >> 0) + db) & 0xff; |
263 | 0 | pixel = (r << 16) | (g << 8) | (b); |
264 | 0 | (*src) += 2; |
265 | 0 | *countdown -= 2; |
266 | 0 | } else { |
267 | 0 | if (*countdown < 3) { |
268 | 0 | return 0xffffff; |
269 | 0 | } |
270 | 0 | if_debug3('w', "lit %02X %02X %02X\n", **src, *(*src + 1), |
271 | 0 | *(*src + 2)); |
272 | |
|
273 | 0 | pixel = ((**src << 16) | (*(*src + 1) << 8) | (*(*src + 2))) << 1; |
274 | 0 | if (pixel & 0x80) { |
275 | 0 | pixel |= 1; |
276 | 0 | } |
277 | 0 | (*src) += 3; |
278 | 0 | *countdown -= 3; |
279 | 0 | } |
280 | 0 | return pixel; |
281 | 0 | } |
282 | | |
283 | | static void |
284 | | uncompress_10(pcl_seed_row_t * pout, const byte * pin, int in_size) |
285 | 0 | { |
286 | 0 | int i = in_size; |
287 | 0 | byte *pb = pout->pdata; |
288 | 0 | byte *plim = pb + pout->size; |
289 | 0 | uint32_t cachedColor = 0x00ffffff; |
290 | 0 | uint32_t pixel = 0xffffff; |
291 | 0 | uint8_t val; |
292 | 0 | int comp; |
293 | 0 | int j; |
294 | |
|
295 | 0 | while (i-- > 0) { |
296 | 0 | int offset; |
297 | 0 | int cnt; |
298 | 0 | int more_cnt; |
299 | 0 | int pixel_source; |
300 | 0 | val = *pin++; |
301 | 0 | if_debug1('w', "command %02X ", val); |
302 | 0 | comp = val & 0x80; |
303 | 0 | pixel_source = val & 0x60; |
304 | |
|
305 | 0 | offset = (val >> 3) & 0x3; |
306 | 0 | if (offset == 3) { |
307 | | /* MAX_INT is MAX_UINT / 2 and we will multiply offset by 3. */ |
308 | 0 | int max = ARCH_MAX_UINT / 6; |
309 | |
|
310 | 0 | do { |
311 | 0 | if (i <= 0) { |
312 | 0 | if_debug0('w', "source end premature 1\n"); |
313 | 0 | goto tidy_up; |
314 | 0 | } |
315 | 0 | offset += *pin; |
316 | 0 | if (offset >= max) { |
317 | 0 | if_debug0('w', "offset overflowed\n"); |
318 | 0 | goto tidy_up; |
319 | 0 | } |
320 | 0 | i--; |
321 | 0 | } while (*pin++ == 0xff); |
322 | 0 | } |
323 | 0 | cnt = (val & 0x7); |
324 | 0 | if (cnt == 7) |
325 | 0 | more_cnt = 1; |
326 | 0 | else |
327 | 0 | more_cnt = 0; |
328 | 0 | if_debug1('w', "offset %d ", offset); |
329 | 0 | pb += offset * 3; |
330 | 0 | if (pixel_source == eeNewPixel) { |
331 | | /* deal with later */ |
332 | 0 | } else if (pixel_source == eeWPixel) { |
333 | 0 | if (((pb - pout->pdata) > 2) && (pb <= plim)) { |
334 | 0 | pixel = (*(pb - 3) << 16) | (*(pb - 2) << 8) | (*(pb - 1)); |
335 | 0 | } else |
336 | 0 | break; |
337 | 0 | } else if (pixel_source == eeNEPixel) { |
338 | 0 | if (pb + 5 < plim) { |
339 | 0 | pixel = (*(pb + 3) << 16) | (*(pb + 4) << 8) | *(pb + 5); |
340 | 0 | } else |
341 | 0 | break; |
342 | 0 | } else { |
343 | 0 | pixel = cachedColor; |
344 | 0 | } |
345 | 0 | if (comp) { |
346 | | /* RLE */ |
347 | 0 | cnt += 2; |
348 | 0 | if (pixel_source == eeNewPixel) { |
349 | 0 | if ((pb + 3) > plim) |
350 | 0 | break; |
351 | 0 | pixel = (*pb << 16) | (*(pb + 1) << 8) | (*(pb + 2)); |
352 | 0 | pixel = mode10_merge_delta(&pin, pixel, &i); |
353 | 0 | cachedColor = pixel; |
354 | 0 | } |
355 | 0 | if (more_cnt) { |
356 | 0 | do { |
357 | 0 | if (i <= 0) { |
358 | 0 | if_debug0('w', "source end premature 2\n"); |
359 | 0 | goto tidy_up; |
360 | 0 | } |
361 | 0 | cnt += *pin; |
362 | 0 | i--; |
363 | 0 | } while (*pin++ == 0xff); |
364 | 0 | } |
365 | 0 | if_debug1('w', "rcnt %d\n", cnt); |
366 | 0 | for (j = 0; j < cnt; j++) { |
367 | 0 | if ((pb + 3) > plim) { |
368 | 0 | if_debug0('|', "pixel over run 1\n"); |
369 | 0 | } else { |
370 | 0 | *pb++ = (pixel >> 16) & 0xff; |
371 | 0 | *pb++ = (pixel >> 8) & 0xff; |
372 | 0 | *pb++ = (pixel >> 0) & 0xff; |
373 | 0 | } |
374 | 0 | } |
375 | 0 | } else { |
376 | 0 | if ((pb + 3) > plim) |
377 | 0 | break; |
378 | 0 | if (pixel_source == eeNewPixel) { |
379 | 0 | pixel = (*pb << 16) | (*(pb + 1) << 8) | (*(pb + 2)); |
380 | 0 | pixel = mode10_merge_delta(&pin, pixel, &i); |
381 | 0 | cachedColor = pixel; |
382 | 0 | } |
383 | 0 | *pb++ = (pixel >> 16) & 0xff; |
384 | 0 | *pb++ = (pixel >> 8) & 0xff; |
385 | 0 | *pb++ = (pixel >> 0) & 0xff; |
386 | 0 | if_debug1('w', "lcnt %d\n", cnt + 1); |
387 | 0 | while (1) { |
388 | 0 | for (j = 0; j < cnt; j++) { |
389 | 0 | if ((pb + 3) > plim) |
390 | 0 | goto tidy_up; |
391 | 0 | pixel = (*pb << 16) | (*(pb + 1) << 8) | (*(pb + 2)); |
392 | 0 | pixel = mode10_merge_delta(&pin, pixel, &i); |
393 | | /* cachedColor only updated on first literal pixel */ |
394 | 0 | *pb++ = (pixel >> 16) & 0xff; |
395 | 0 | *pb++ = (pixel >> 8) & 0xff; |
396 | 0 | *pb++ = (pixel >> 0) & 0xff; |
397 | 0 | } |
398 | 0 | if (more_cnt) { |
399 | 0 | cnt = *pin++; |
400 | 0 | i--; |
401 | 0 | if (cnt != 255) { |
402 | 0 | more_cnt = 0; |
403 | 0 | } |
404 | 0 | } else { |
405 | 0 | break; |
406 | 0 | } |
407 | 0 | } |
408 | 0 | } |
409 | 0 | } |
410 | 0 | tidy_up: |
411 | 0 | if (in_size) |
412 | 0 | if_debug2('w', "data count raw %d out %ld\n", in_size, |
413 | 0 | pb - pout->pdata); |
414 | 0 | else |
415 | 0 | if_debug0('w', "*"); |
416 | 0 | pout->is_blank = (pout->is_blank && (in_size == 0)); |
417 | |
|
418 | 0 | } |
419 | | |
420 | | void (*const pcl_decomp_proc[10 + 1]) (pcl_seed_row_t * pout, |
421 | | const byte * pin, int in_size) = { |
422 | | uncompress_0, |
423 | | uncompress_1, |
424 | | uncompress_2, |
425 | | uncompress_3, |
426 | | 0, 0, 0, 0, 0, /* modes 4 - 8 handled separately */ |
427 | | uncompress_9, |
428 | | uncompress_10 |
429 | | }; |