Coverage Report

Created: 2026-05-16 07:03

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/mupdf/source/fitz/draw-unpack.c
Line
Count
Source
1
// Copyright (C) 2004-2021 Artifex Software, Inc.
2
//
3
// This file is part of MuPDF.
4
//
5
// MuPDF is free software: you can redistribute it and/or modify it under the
6
// terms of the GNU Affero General Public License as published by the Free
7
// Software Foundation, either version 3 of the License, or (at your option)
8
// any later version.
9
//
10
// MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY
11
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12
// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
13
// details.
14
//
15
// You should have received a copy of the GNU Affero General Public License
16
// along with MuPDF. If not, see <https://www.gnu.org/licenses/agpl-3.0.en.html>
17
//
18
// Alternative licensing terms are available from the licensor.
19
// For commercial licensing, see <https://www.artifex.com/> or contact
20
// Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco,
21
// CA 94129, USA, for further information.
22
23
#include "mupdf/fitz.h"
24
#include "draw-imp.h"
25
26
#include <string.h>
27
28
/* Unpack image samples and optionally pad pixels with opaque alpha */
29
30
2.04k
#define get1(buf,x) ((buf[x >> 3] >> ( 7 - (x & 7) ) ) & 1 )
31
0
#define get2(buf,x) ((buf[x >> 2] >> ( ( 3 - (x & 3) ) << 1 ) ) & 3 )
32
0
#define get4(buf,x) ((buf[x >> 1] >> ( ( 1 - (x & 1) ) << 2 ) ) & 15 )
33
0
#define get8(buf,x) (buf[x])
34
0
#define get16(buf,x) (buf[x << 1])
35
0
#define get24(buf,x) (buf[(x << 1) + x])
36
0
#define get32(buf,x) (buf[x << 2])
37
38
static unsigned char get1_tab_1[256][8];
39
static unsigned char get1_tab_1p[256][16];
40
static unsigned char get1_tab_255[256][8];
41
static unsigned char get1_tab_255p[256][16];
42
43
/*
44
  Bug 697012 shows that the unpacking code can confuse valgrind due
45
  to the use of undefined bits in the padding at the end of lines.
46
  We unpack from bits to bytes by copying from a lookup table.
47
  Valgrind is not capable of understanding that it doesn't matter
48
  what the undefined bits are, as the bytes we copy that correspond
49
  to the defined bits will always agree regardless of these
50
  undefined bits by construction of the table.
51
52
  We therefore have a VGMASK macro that explicitly masks off these
53
  bits in PACIFY_VALGRIND builds.
54
*/
55
#ifdef PACIFY_VALGRIND
56
static const unsigned char mask[9] = { 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff };
57
5.48k
#define VGMASK(v,m) (v & mask[(m)])
58
#else
59
#define VGMASK(v,m) (v)
60
#endif
61
62
static void
63
init_get1_tables(void)
64
103
{
65
103
  static int once = 0;
66
103
  unsigned char bits[1];
67
103
  int i, k, x;
68
69
  /* TODO: mutex lock here */
70
71
103
  if (once)
72
102
    return;
73
74
257
  for (i = 0; i < 256; i++)
75
256
  {
76
256
    bits[0] = i;
77
2.30k
    for (k = 0; k < 8; k++)
78
2.04k
    {
79
2.04k
      x = get1(bits, k);
80
81
2.04k
      get1_tab_1[i][k] = x;
82
2.04k
      get1_tab_1p[i][k * 2] = x;
83
2.04k
      get1_tab_1p[i][k * 2 + 1] = 255;
84
85
2.04k
      get1_tab_255[i][k] = x * 255;
86
2.04k
      get1_tab_255p[i][k * 2] = x * 255;
87
2.04k
      get1_tab_255p[i][k * 2 + 1] = 255;
88
2.04k
    }
89
256
  }
90
91
1
  once = 1;
92
1
}
93
94
static void
95
fz_unpack_mono_line_unscaled(unsigned char *dp, unsigned char *sp, int w, int n, int depth, int scale, int pad, int skip)
96
0
{
97
0
  int w3 = w >> 3;
98
0
  int x;
99
100
0
  for (x = 0; x < w3; x++)
101
0
  {
102
0
    memcpy(dp, get1_tab_1[*sp++], 8);
103
0
    dp += 8;
104
0
  }
105
0
  x = x << 3;
106
0
  if (x < w)
107
0
    memcpy(dp, get1_tab_1[VGMASK(*sp, w - x)], w - x);
108
0
}
109
110
static void
111
fz_unpack_mono_line_scaled(unsigned char *dp, unsigned char *sp, int w, int n, int depth, int scale, int pad, int skip)
112
6.29k
{
113
6.29k
  int w3 = w >> 3;
114
6.29k
  int x;
115
116
39.3k
  for (x = 0; x < w3; x++)
117
33.0k
  {
118
33.0k
    memcpy(dp, get1_tab_255[*sp++], 8);
119
33.0k
    dp += 8;
120
33.0k
  }
121
6.29k
  x = x << 3;
122
6.29k
  if (x < w)
123
5.48k
    memcpy(dp, get1_tab_255[VGMASK(*sp, w - x)], w - x);
124
6.29k
}
125
126
static void
127
fz_unpack_mono_line_unscaled_with_padding(unsigned char *dp, unsigned char *sp, int w, int n, int depth, int scale, int pad, int skip)
128
0
{
129
0
  int w3 = w >> 3;
130
0
  int x;
131
132
0
  for (x = 0; x < w3; x++)
133
0
  {
134
0
    memcpy(dp, get1_tab_1p[*sp++], 16);
135
0
    dp += 16;
136
0
  }
137
0
  x = x << 3;
138
0
  if (x < w)
139
0
    memcpy(dp, get1_tab_1p[VGMASK(*sp, w - x)], (w - x) << 1);
140
0
}
141
142
static void
143
fz_unpack_mono_line_scaled_with_padding(unsigned char *dp, unsigned char *sp, int w, int n, int depth, int scale, int pad, int skip)
144
0
{
145
0
  int w3 = w >> 3;
146
0
  int x;
147
148
0
  for (x = 0; x < w3; x++)
149
0
  {
150
0
    memcpy(dp, get1_tab_255p[*sp++], 16);
151
0
    dp += 16;
152
0
  }
153
0
  x = x << 3;
154
0
  if (x < w)
155
0
    memcpy(dp, get1_tab_255p[VGMASK(*sp, w - x)], (w - x) << 1);
156
0
}
157
158
static void
159
fz_unpack_line(unsigned char *dp, unsigned char *sp, int w, int n, int depth, int scale, int pad, int skip)
160
0
{
161
0
  int len = w * n;
162
0
  while (len--)
163
0
    *dp++ = *sp++;
164
0
}
165
166
static void
167
fz_unpack_line_with_padding(unsigned char *dp, unsigned char *sp, int w, int n, int depth, int scale, int pad, int skip)
168
0
{
169
0
  int x, k;
170
171
0
  for (x = 0; x < w; x++)
172
0
  {
173
0
    for (k = 0; k < n; k++)
174
0
      *dp++ = *sp++;
175
0
    *dp++ = 255;
176
0
  }
177
0
}
178
179
static void
180
fz_unpack_any_l2depth(unsigned char *dp, unsigned char *sp, int w, int n, int depth, int scale, int pad, int skip)
181
0
{
182
0
  unsigned char *p = dp;
183
0
  int b = 0;
184
0
  int x, k;
185
186
0
  for (x = 0; x < w; x++)
187
0
  {
188
0
    for (k = 0; k < n; k++)
189
0
    {
190
0
      switch (depth)
191
0
      {
192
0
      case 1: *p++ = get1(sp, b) * scale; break;
193
0
      case 2: *p++ = get2(sp, b) * scale; break;
194
0
      case 4: *p++ = get4(sp, b) * scale; break;
195
0
      case 8: *p++ = get8(sp, b); break;
196
0
      case 16: *p++ = get16(sp, b); break;
197
0
      case 24: *p++ = get24(sp, b); break;
198
0
      case 32: *p++ = get32(sp, b); break;
199
0
      }
200
0
      b++;
201
0
    }
202
0
    b += skip;
203
0
    if (pad)
204
0
      *p++ = 255;
205
0
  }
206
0
}
207
208
typedef void (*fz_unpack_line_fn)(unsigned char *dp, unsigned char *sp, int w, int n, int depth, int scale, int pad, int skip);
209
210
void
211
fz_unpack_tile(fz_context *ctx, fz_pixmap *dst, unsigned char *src, int n, int depth, size_t stride, int scale)
212
0
{
213
0
  unsigned char *sp = src;
214
0
  unsigned char *dp = dst->samples;
215
0
  fz_unpack_line_fn unpack_line = NULL;
216
0
  int pad, y, skip;
217
0
  int w = dst->w;
218
0
  int h = dst->h;
219
220
0
  pad = 0;
221
0
  skip = 0;
222
0
  if (dst->n > n)
223
0
    pad = 255;
224
0
  if (dst->n < n)
225
0
  {
226
0
    skip = n - dst->n;
227
0
    n = dst->n;
228
0
  }
229
230
0
  if (depth == 1)
231
0
    init_get1_tables();
232
233
0
  if (scale == 0)
234
0
  {
235
0
    switch (depth)
236
0
    {
237
0
    case 1: scale = 255; break;
238
0
    case 2: scale = 85; break;
239
0
    case 4: scale = 17; break;
240
0
    }
241
0
  }
242
243
0
  if (n == 1 && depth == 1 && scale == 1 && !pad && !skip)
244
0
    unpack_line = fz_unpack_mono_line_unscaled;
245
0
  else if (n == 1 && depth == 1 && scale == 255 && !pad && !skip)
246
0
    unpack_line = fz_unpack_mono_line_scaled;
247
0
  else if (n == 1 && depth == 1 && scale == 1 && pad && !skip)
248
0
    unpack_line = fz_unpack_mono_line_unscaled_with_padding;
249
0
  else if (n == 1 && depth == 1 && scale == 255 && pad && !skip)
250
0
    unpack_line = fz_unpack_mono_line_scaled_with_padding;
251
0
  else if (depth == 8 && !pad && !skip)
252
0
    unpack_line = fz_unpack_line;
253
0
  else if (depth == 8 && pad && !skip)
254
0
    unpack_line = fz_unpack_line_with_padding;
255
0
  else if (depth == 1 || depth == 2 || depth == 4 || depth == 8 || depth  == 16 || depth == 24 || depth == 32)
256
0
    unpack_line = fz_unpack_any_l2depth;
257
258
0
  if (unpack_line)
259
0
  {
260
0
    for (y = 0; y < h; y++, sp += stride, dp += dst->stride)
261
0
      unpack_line(dp, sp, w, n, depth, scale, pad, skip);
262
0
  }
263
0
  else if (depth > 0 && depth <= 8 * (int)sizeof(int))
264
0
  {
265
0
    fz_stream *stm;
266
0
    int x, k;
267
0
    size_t skipbits = 8 * stride - (size_t)w * n * depth;
268
269
0
    if (skipbits > 32)
270
0
      fz_throw(ctx, FZ_ERROR_ARGUMENT, "Inappropriate stride!");
271
272
0
    stm = fz_open_memory(ctx, sp, h * stride);
273
0
    fz_try(ctx)
274
0
    {
275
0
      for (y = 0; y < h; y++)
276
0
      {
277
0
        for (x = 0; x < w; x++)
278
0
        {
279
0
          for (k = 0; k < n; k++)
280
0
          {
281
0
            if (depth <= 8)
282
0
              *dp++ = fz_read_bits(ctx, stm, depth) << (8 - depth);
283
0
            else
284
0
              *dp++ = fz_read_bits(ctx, stm, depth) >> (depth - 8);
285
0
          }
286
0
          if (pad)
287
0
            *dp++ = 255;
288
0
        }
289
290
0
        dp += dst->stride - (size_t)w * (n + (pad > 0));
291
0
        (void) fz_read_bits(ctx, stm, (int)skipbits);
292
0
      }
293
0
    }
294
0
    fz_always(ctx)
295
0
      fz_drop_stream(ctx, stm);
296
0
    fz_catch(ctx)
297
0
      fz_rethrow(ctx);
298
0
  }
299
0
  else
300
0
    fz_throw(ctx, FZ_ERROR_ARGUMENT, "cannot unpack tile with %d bits per component", depth);
301
0
}
302
303
/* Apply decode array */
304
305
void
306
fz_decode_indexed_tile(fz_context *ctx, fz_pixmap *pix, const float *decode, int maxval)
307
0
{
308
0
  int add[FZ_MAX_COLORS];
309
0
  int mul[FZ_MAX_COLORS];
310
0
  unsigned char *p = pix->samples;
311
0
  size_t stride = pix->stride - pix->w * (size_t)pix->n;
312
0
  int len;
313
0
  int pn = pix->n;
314
0
  int n = pn - pix->alpha;
315
0
  int needed;
316
0
  int k;
317
0
  int h;
318
319
0
  needed = 0;
320
0
  for (k = 0; k < n; k++)
321
0
  {
322
0
    int min = decode[k * 2] * 256;
323
0
    int max = decode[k * 2 + 1] * 256;
324
0
    add[k] = min;
325
0
    mul[k] = (max - min) / maxval;
326
0
    needed |= min != 0 || max != maxval * 256;
327
0
  }
328
329
0
  if (!needed)
330
0
    return;
331
332
0
  h = pix->h;
333
0
  while (h--)
334
0
  {
335
0
    len = pix->w;
336
0
    while (len--)
337
0
    {
338
0
      for (k = 0; k < n; k++)
339
0
      {
340
0
        int value = (add[k] + (((p[k] << 8) * mul[k]) >> 8)) >> 8;
341
0
        p[k] = fz_clampi(value, 0, 255);
342
0
      }
343
0
      p += pn;
344
0
    }
345
0
    p += stride;
346
0
  }
347
0
}
348
349
void
350
fz_decode_tile(fz_context *ctx, fz_pixmap *pix, const float *decode)
351
109
{
352
109
  int add[FZ_MAX_COLORS];
353
109
  int mul[FZ_MAX_COLORS];
354
109
  unsigned char *p = pix->samples;
355
109
  size_t stride = pix->stride - pix->w * (size_t)pix->n;
356
109
  int len;
357
109
  int n = fz_maxi(1, pix->n - pix->alpha);
358
109
  int k;
359
109
  int h;
360
361
218
  for (k = 0; k < n; k++)
362
109
  {
363
109
    int min = decode[k * 2] * 255;
364
109
    int max = decode[k * 2 + 1] * 255;
365
109
    add[k] = min;
366
109
    mul[k] = max - min;
367
109
  }
368
369
109
  h = pix->h;
370
6.64k
  while (h--)
371
6.53k
  {
372
6.53k
    len = pix->w;
373
1.50M
    while (len--)
374
1.49M
    {
375
2.98M
      for (k = 0; k < n; k++)
376
1.49M
      {
377
1.49M
        int value = add[k] + fz_mul255(p[k], mul[k]);
378
1.49M
        p[k] = fz_clampi(value, 0, 255);
379
1.49M
      }
380
1.49M
      p += pix->n;
381
1.49M
    }
382
6.53k
    p += stride;
383
6.53k
  }
384
109
}
385
386
typedef struct
387
{
388
  fz_stream *src;
389
  int depth;
390
  int w;
391
  int h;
392
  int n;
393
  int skip;
394
  int pad;
395
  int scale;
396
  size_t src_stride;
397
  size_t dst_stride;
398
  fz_unpack_line_fn unpack;
399
  unsigned char buf[1];
400
} unpack_state;
401
402
static int
403
unpack_next(fz_context *ctx, fz_stream *stm, size_t max)
404
6.29k
{
405
6.29k
  unpack_state *state = (unpack_state *)stm->state;
406
6.29k
  size_t n = state->src_stride;
407
408
6.29k
  stm->rp = state->buf;
409
6.29k
  do
410
6.29k
  {
411
6.29k
    size_t a = fz_available(ctx, state->src, n);
412
6.29k
    if (a == 0)
413
0
      return EOF;
414
6.29k
    if (a > n)
415
2.50k
      a = n;
416
6.29k
    memcpy(stm->rp, state->src->rp, a);
417
6.29k
    stm->rp += a;
418
6.29k
    state->src->rp += a;
419
6.29k
    n -= a;
420
6.29k
  }
421
6.29k
  while (n);
422
423
6.29k
  state->h--;
424
6.29k
  stm->pos += state->dst_stride;
425
6.29k
  stm->wp = stm->rp + state->dst_stride;
426
6.29k
  state->unpack(stm->rp, state->buf, state->w, state->n, state->depth, state->scale, state->pad, state->skip);
427
428
6.29k
  return *stm->rp++;
429
6.29k
}
430
431
static void
432
unpack_drop(fz_context *ctx, void *state)
433
103
{
434
103
  fz_free(ctx, state);
435
103
}
436
437
fz_stream *
438
fz_unpack_stream(fz_context *ctx, fz_stream *src, int depth, int w, int h, int n, int indexed, int pad, int skip)
439
103
{
440
103
  uint64_t u64;
441
103
  size_t src_stride, dst_stride;
442
103
  unpack_state *state;
443
103
  fz_unpack_line_fn unpack_line = NULL;
444
103
  int scale = 1;
445
446
103
  if (n < 1 || n > FZ_MAX_COLORS)
447
0
    fz_throw(ctx, FZ_ERROR_ARGUMENT, "n out of range in fz_unpack_stream");
448
103
  if (depth < 1 || depth > 32)
449
0
    fz_throw(ctx, FZ_ERROR_ARGUMENT, "depth out of range in fz_unpack_stream");
450
451
103
  if (fz_ckd_mul_u64(&u64, w, depth*n))
452
0
    fz_throw(ctx, FZ_ERROR_ARGUMENT, "area out of range in fz_unpack_stream");
453
103
  u64 = (u64+7)>>3;
454
103
  if (u64 > SIZE_MAX)
455
0
    fz_throw(ctx, FZ_ERROR_ARGUMENT, "area out of range in fz_unpack_stream");
456
103
  src_stride = (size_t)u64;
457
458
103
  if (depth == 1)
459
103
    init_get1_tables();
460
461
103
  if (!indexed)
462
103
    switch (depth)
463
103
    {
464
103
    case 1: scale = 255; break;
465
0
    case 2: scale = 85; break;
466
0
    case 4: scale = 17; break;
467
103
    }
468
469
103
  if (fz_ckd_mul_size(&dst_stride, w, n + !!pad))
470
0
    fz_throw(ctx, FZ_ERROR_ARGUMENT, "dst_stride out of range in fz_unpack_stream");
471
472
103
  if (n == 1 && depth == 1 && scale == 1 && !pad && !skip)
473
0
    unpack_line = fz_unpack_mono_line_unscaled;
474
103
  else if (n == 1 && depth == 1 && scale == 255 && !pad && !skip)
475
103
    unpack_line = fz_unpack_mono_line_scaled;
476
0
  else if (n == 1 && depth == 1 && scale == 1 && pad && !skip)
477
0
    unpack_line = fz_unpack_mono_line_unscaled_with_padding;
478
0
  else if (n == 1 && depth == 1 && scale == 255 && pad && !skip)
479
0
    unpack_line = fz_unpack_mono_line_scaled_with_padding;
480
0
  else if (depth == 8 && !pad && !skip)
481
0
    unpack_line = fz_unpack_line;
482
0
  else if (depth == 8 && pad && !skip)
483
0
    unpack_line = fz_unpack_line_with_padding;
484
0
  else if (depth == 1 || depth == 2 || depth == 4 || depth == 8 || depth  == 16 || depth == 24 || depth == 32)
485
0
    unpack_line = fz_unpack_any_l2depth;
486
0
  else
487
0
    fz_throw(ctx, FZ_ERROR_ARGUMENT, "Unsupported combination in fz_unpack_stream");
488
489
103
  state = fz_malloc(ctx, sizeof(unpack_state) + dst_stride + src_stride);
490
103
  state->src = src;
491
103
  state->depth = depth;
492
103
  state->w = w;
493
103
  state->h = h;
494
103
  state->n = n;
495
103
  state->skip = skip;
496
103
  state->pad = pad;
497
103
  state->scale = scale;
498
103
  state->unpack = unpack_line;
499
103
  state->src_stride = src_stride;
500
103
  state->dst_stride = dst_stride;
501
502
103
  return fz_new_stream(ctx, state, unpack_next, unpack_drop);
503
103
}