Coverage Report

Created: 2026-04-09 07:06

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
};