Coverage Report

Created: 2026-03-31 07:17

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/mupdf/source/fitz/buffer.c
Line
Count
Source
1
// Copyright (C) 2004-2026 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
25
#include <string.h>
26
#include <stdarg.h>
27
28
fz_buffer *
29
fz_new_buffer(fz_context *ctx, size_t size)
30
3
{
31
3
  fz_buffer *b;
32
33
3
  size = size > 1 ? size : 16;
34
35
3
  b = fz_malloc_struct(ctx, fz_buffer);
36
3
  b->refs = 1;
37
6
  fz_try(ctx)
38
6
  {
39
3
    b->data = Memento_label(fz_malloc(ctx, size), "fz_buffer_data");
40
3
  }
41
6
  fz_catch(ctx)
42
0
  {
43
0
    fz_free(ctx, b);
44
0
    fz_rethrow(ctx);
45
0
  }
46
3
  b->cap = size;
47
3
  b->len = 0;
48
3
  b->unused_bits = 0;
49
50
3
  return b;
51
3
}
52
53
fz_buffer *
54
fz_new_buffer_from_data(fz_context *ctx, unsigned char *data, size_t size)
55
0
{
56
0
  fz_buffer *b = NULL;
57
58
0
  fz_try(ctx)
59
0
  {
60
0
    b = fz_malloc_struct(ctx, fz_buffer);
61
0
    b->refs = 1;
62
0
    b->data = data;
63
0
    b->cap = size;
64
0
    b->len = size;
65
0
    b->unused_bits = 0;
66
0
  }
67
0
  fz_catch(ctx)
68
0
  {
69
0
    fz_free(ctx, data);
70
0
    fz_rethrow(ctx);
71
0
  }
72
73
0
  return b;
74
0
}
75
76
fz_buffer *
77
fz_new_buffer_from_shared_data(fz_context *ctx, const unsigned char *data, size_t size)
78
85
{
79
85
  fz_buffer *b;
80
81
85
  b = fz_malloc_struct(ctx, fz_buffer);
82
85
  b->refs = 1;
83
85
  b->data = (unsigned char *)data; /* cast away const */
84
85
  b->cap = size;
85
85
  b->len = size;
86
85
  b->unused_bits = 0;
87
85
  b->shared = 1;
88
89
85
  return b;
90
85
}
91
92
fz_buffer *
93
fz_new_buffer_from_copied_data(fz_context *ctx, const unsigned char *data, size_t size)
94
0
{
95
0
  fz_buffer *b;
96
0
  if (size > 0 && data == NULL)
97
0
    fz_throw(ctx, FZ_ERROR_ARGUMENT, "no data provided");
98
0
  b = fz_new_buffer(ctx, size);
99
0
  b->len = size;
100
0
  memcpy(b->data, data, size);
101
0
  return b;
102
0
}
103
104
fz_buffer *
105
fz_new_buffer_from_printf(fz_context *ctx, const char *fmt, ...)
106
0
{
107
0
  size_t len;
108
0
  fz_buffer *buf;
109
0
  va_list ap;
110
0
  va_start(ap, fmt);
111
0
  len = fz_vsnprintf(NULL, 0, fmt, ap);
112
0
  va_end(ap);
113
0
  buf = fz_new_buffer(ctx, len+1);
114
0
  va_start(ap, fmt);
115
0
  fz_append_vprintf(ctx, buf, fmt, ap);
116
0
  va_end(ap);
117
0
  return buf;
118
0
}
119
120
fz_buffer *fz_clone_buffer(fz_context *ctx, fz_buffer *buf)
121
0
{
122
0
  return fz_new_buffer_from_copied_data(ctx, buf ? buf->data : NULL, buf ? buf->len : 0);
123
0
}
124
125
static inline int iswhite(int a)
126
0
{
127
0
  switch (a) {
128
0
  case '\n': case '\r': case '\t': case ' ':
129
0
  case '\f':
130
0
    return 1;
131
0
  }
132
0
  return 0;
133
0
}
134
135
fz_buffer *
136
fz_new_buffer_from_base64(fz_context *ctx, const char *data, size_t size)
137
0
{
138
0
  fz_buffer *out = fz_new_buffer(ctx, size > 0 ? size : strlen(data));
139
0
  const char *end = data + (size > 0 ? size : strlen(data));
140
0
  const char *s = data;
141
0
  uint32_t buf = 0;
142
0
  int bits = 0;
143
144
  /* This is https://infra.spec.whatwg.org/#forgiving-base64-decode
145
   * but even more relaxed. We allow any number of trailing '=' code
146
   * points and instead of returning failure on invalid characters, we
147
   * warn and truncate.
148
   */
149
150
0
  while (s < end && iswhite(*s))
151
0
    s++;
152
0
  while (s < end && iswhite(end[-1]))
153
0
    end--;
154
0
  while (s < end && end[-1] == '=')
155
0
    end--;
156
157
0
  fz_try(ctx)
158
0
  {
159
0
    while (s < end)
160
0
    {
161
0
      int c = *s++;
162
163
0
      if (c >= 'A' && c <= 'Z')
164
0
        c = c - 'A';
165
0
      else if (c >= 'a' && c <= 'z')
166
0
        c = c - 'a' + 26;
167
0
      else if (c >= '0' && c <= '9')
168
0
        c = c - '0' + 52;
169
0
      else if (c == '+')
170
0
        c = 62;
171
0
      else if (c == '/')
172
0
        c = 63;
173
0
      else if (iswhite(c))
174
0
        continue;
175
0
      else
176
0
      {
177
0
        fz_warn(ctx, "invalid character in base64");
178
0
        break;
179
0
      }
180
181
0
      buf <<= 6;
182
0
      buf |= c & 0x3f;
183
0
      bits += 6;
184
185
0
      if (bits == 24)
186
0
      {
187
0
        fz_append_byte(ctx, out, buf >> 16);
188
0
        fz_append_byte(ctx, out, buf >> 8);
189
0
        fz_append_byte(ctx, out, buf >> 0);
190
0
        bits = 0;
191
0
      }
192
0
    }
193
194
0
    if (bits == 18)
195
0
    {
196
0
      fz_append_byte(ctx, out, buf >> 10);
197
0
      fz_append_byte(ctx, out, buf >> 2);
198
0
    }
199
0
    else if (bits == 12)
200
0
    {
201
0
      fz_append_byte(ctx, out, buf >> 4);
202
0
    }
203
0
  }
204
0
  fz_catch(ctx)
205
0
  {
206
0
    fz_drop_buffer(ctx, out);
207
0
    fz_rethrow(ctx);
208
0
  }
209
0
  return out;
210
0
}
211
212
fz_buffer *
213
fz_keep_buffer(fz_context *ctx, fz_buffer *buf)
214
111
{
215
111
  return fz_keep_imp(ctx, buf, &buf->refs);
216
111
}
217
218
void
219
fz_drop_buffer(fz_context *ctx, fz_buffer *buf)
220
11.0k
{
221
11.0k
  if (fz_drop_imp(ctx, buf, &buf->refs))
222
88
  {
223
88
    if (!buf->shared)
224
3
      fz_free(ctx, buf->data);
225
88
    fz_free(ctx, buf);
226
88
  }
227
11.0k
}
228
229
void
230
fz_resize_buffer(fz_context *ctx, fz_buffer *buf, size_t size)
231
36
{
232
36
  if (buf->shared)
233
0
    fz_throw(ctx, FZ_ERROR_ARGUMENT, "cannot resize a buffer with shared storage");
234
36
  buf->data = fz_realloc(ctx, buf->data, size);
235
36
  buf->cap = size;
236
36
  if (buf->len > buf->cap)
237
0
    buf->len = buf->cap;
238
36
}
239
240
void
241
fz_grow_buffer(fz_context *ctx, fz_buffer *buf)
242
36
{
243
36
  size_t newsize = 256;
244
36
  if (buf->cap == SIZE_MAX)
245
0
    fz_throw(ctx, FZ_ERROR_SYSTEM, "buffer too large");
246
36
  else if (buf->cap == 0)
247
0
    newsize = 256;
248
36
  else
249
36
  {
250
36
    newsize = buf->cap + (buf->cap >> 1);
251
    // check for integer overflow
252
36
    if (newsize < buf->cap)
253
0
      newsize = SIZE_MAX;
254
36
  }
255
36
  fz_resize_buffer(ctx, buf, newsize);
256
36
}
257
258
static void
259
fz_ensure_buffer(fz_context *ctx, fz_buffer *buf, size_t min)
260
0
{
261
0
  size_t newsize = buf->cap;
262
0
  if (newsize < 16)
263
0
    newsize = 16;
264
0
  while (newsize < min)
265
0
  {
266
0
    size_t tmp = newsize + (newsize >> 1);
267
    // check for integer overflow
268
0
    if (tmp < newsize)
269
0
      newsize = min;
270
0
    else
271
0
      newsize = tmp;
272
0
  }
273
0
  fz_resize_buffer(ctx, buf, newsize);
274
0
}
275
276
void
277
fz_trim_buffer(fz_context *ctx, fz_buffer *buf)
278
0
{
279
0
  if (buf->cap > buf->len+1)
280
0
    fz_resize_buffer(ctx, buf, buf->len);
281
0
}
282
283
void
284
fz_clear_buffer(fz_context *ctx, fz_buffer *buf)
285
0
{
286
0
  buf->len = 0;
287
0
}
288
289
void
290
fz_terminate_buffer(fz_context *ctx, fz_buffer *buf)
291
0
{
292
  /* ensure that there is a zero-byte after the end of the data */
293
0
  if (buf->len + 1 > buf->cap)
294
0
    fz_grow_buffer(ctx, buf);
295
0
  buf->data[buf->len] = 0;
296
0
}
297
298
size_t
299
fz_buffer_storage(fz_context *ctx, fz_buffer *buf, unsigned char **datap)
300
111
{
301
111
  if (datap)
302
111
    *datap = (buf ? buf->data : NULL);
303
111
  return (buf ? buf->len : 0);
304
111
}
305
306
const char *
307
fz_string_from_buffer(fz_context *ctx, fz_buffer *buf)
308
0
{
309
0
  if (!buf)
310
0
    return "";
311
0
  fz_terminate_buffer(ctx, buf);
312
0
  return (const char *)buf->data;
313
0
}
314
315
size_t
316
fz_buffer_extract(fz_context *ctx, fz_buffer *buf, unsigned char **datap)
317
0
{
318
0
  size_t len = buf ? buf->len : 0;
319
0
  *datap = (buf ? buf->data : NULL);
320
321
0
  if (buf)
322
0
  {
323
0
    buf->data = NULL;
324
0
    buf->len = 0;
325
0
  }
326
0
  return len;
327
0
}
328
329
fz_buffer *
330
fz_slice_buffer(fz_context *ctx, fz_buffer *buf, int64_t start, int64_t end)
331
0
{
332
0
  unsigned char *src = NULL;
333
0
  size_t size = fz_buffer_storage(ctx, buf, &src);
334
0
  size_t s, e;
335
336
0
  if (start < 0)
337
0
    start += size;
338
0
  if (end < 0)
339
0
    end += size;
340
341
0
  s = fz_clamp64(start, 0, size);
342
0
  e = fz_clamp64(end, 0, size);
343
344
0
  if (s == size || e <= s)
345
0
    return fz_new_buffer(ctx, 0);
346
347
0
  return fz_new_buffer_from_copied_data(ctx, &src[s], e - s);
348
0
}
349
350
void
351
fz_append_buffer(fz_context *ctx, fz_buffer *buf, fz_buffer *extra)
352
0
{
353
0
  if (extra == NULL)
354
0
    return;
355
0
  if (buf->cap - buf->len < extra->len)
356
0
  {
357
0
    buf->data = fz_realloc(ctx, buf->data, buf->len + extra->len);
358
0
    buf->cap = buf->len + extra->len;
359
0
  }
360
361
0
  memcpy(buf->data + buf->len, extra->data, extra->len);
362
0
  buf->len += extra->len;
363
0
}
364
365
void
366
fz_append_data(fz_context *ctx, fz_buffer *buf, const void *data, size_t len)
367
0
{
368
0
  if (buf->len + len > buf->cap)
369
0
    fz_ensure_buffer(ctx, buf, buf->len + len);
370
0
  memcpy(buf->data + buf->len, data, len);
371
0
  buf->len += len;
372
0
  buf->unused_bits = 0;
373
0
}
374
375
void
376
fz_append_string(fz_context *ctx, fz_buffer *buf, const char *data)
377
0
{
378
0
  size_t len = strlen(data);
379
0
  if (buf->len + len > buf->cap)
380
0
    fz_ensure_buffer(ctx, buf, buf->len + len);
381
0
  memcpy(buf->data + buf->len, data, len);
382
0
  buf->len += len;
383
0
  buf->unused_bits = 0;
384
0
}
385
386
void
387
fz_append_byte(fz_context *ctx, fz_buffer *buf, int val)
388
0
{
389
0
  if (buf->len + 1 > buf->cap)
390
0
    fz_grow_buffer(ctx, buf);
391
0
  buf->data[buf->len++] = val;
392
0
  buf->unused_bits = 0;
393
0
}
394
395
void
396
fz_append_rune(fz_context *ctx, fz_buffer *buf, int c)
397
0
{
398
0
  char data[10];
399
0
  int len = fz_runetochar(data, c);
400
0
  if (buf->len + len > buf->cap)
401
0
    fz_ensure_buffer(ctx, buf, buf->len + len);
402
0
  memcpy(buf->data + buf->len, data, len);
403
0
  buf->len += len;
404
0
  buf->unused_bits = 0;
405
0
}
406
407
void
408
fz_append_uint32_be(fz_context *ctx, fz_buffer *buf, uint32_t x)
409
0
{
410
0
  fz_append_byte(ctx, buf, (x >> 24) & 0xFF);
411
0
  fz_append_byte(ctx, buf, (x >> 16) & 0xFF);
412
0
  fz_append_byte(ctx, buf, (x >> 8) & 0xFF);
413
0
  fz_append_byte(ctx, buf, (x) & 0xFF);
414
0
}
415
416
void
417
fz_append_uint16_be(fz_context *ctx, fz_buffer *buf, uint16_t x)
418
0
{
419
0
  fz_append_byte(ctx, buf, (x >> 8) & 0xFF);
420
0
  fz_append_byte(ctx, buf, (x) & 0xFF);
421
0
}
422
423
void
424
fz_append_uint32_le(fz_context *ctx, fz_buffer *buf, uint32_t x)
425
0
{
426
0
  fz_append_byte(ctx, buf, (x)&0xFF);
427
0
  fz_append_byte(ctx, buf, (x>>8)&0xFF);
428
0
  fz_append_byte(ctx, buf, (x>>16)&0xFF);
429
0
  fz_append_byte(ctx, buf, (x>>24)&0xFF);
430
0
}
431
432
void
433
fz_append_uint16_le(fz_context *ctx, fz_buffer *buf, uint16_t x)
434
0
{
435
0
  fz_append_byte(ctx, buf, (x)&0xFF);
436
0
  fz_append_byte(ctx, buf, (x>>8)&0xFF);
437
0
}
438
439
void
440
fz_append_int32_be(fz_context *ctx, fz_buffer *buf, int32_t x)
441
0
{
442
0
  fz_append_uint32_be(ctx, buf, x);
443
0
}
444
445
void
446
fz_append_int16_be(fz_context *ctx, fz_buffer *buf, int16_t x)
447
0
{
448
0
  fz_append_uint16_be(ctx, buf, x);
449
0
}
450
451
void
452
fz_append_int32_le(fz_context *ctx, fz_buffer *buf, int32_t x)
453
0
{
454
0
  fz_append_uint32_le(ctx, buf, x);
455
0
}
456
457
void
458
fz_append_int16_le(fz_context *ctx, fz_buffer *buf, int16_t x)
459
0
{
460
0
  fz_append_uint16_le(ctx, buf, x);
461
0
}
462
463
void
464
fz_append_bits(fz_context *ctx, fz_buffer *buf, int val, int bits)
465
0
{
466
0
  int shift;
467
468
  /* Throughout this code, the invariant is that we need to write the
469
   * bottom 'bits' bits of 'val' into the stream. On entry we assume
470
   * that val & ((1<<bits)-1) == val, but we do not rely on this after
471
   * having written the first partial byte. */
472
473
0
  if (bits == 0)
474
0
    return;
475
476
  /* buf->len always covers all the bits in the buffer, including
477
   * any unused ones in the last byte, which will always be 0.
478
   * buf->unused_bits = the number of unused bits in the last byte.
479
   */
480
481
  /* Find the amount we need to shift val up by so that it will be in
482
   * the correct position to be inserted into any existing data byte. */
483
0
  shift = (buf->unused_bits - bits);
484
485
  /* Extend the buffer as required before we start; that way we never
486
   * fail part way during writing. If shift < 0, then we'll need -shift
487
   * more bits. */
488
0
  if (shift < 0)
489
0
  {
490
0
    int extra = (7-shift)>>3; /* Round up to bytes */
491
0
    fz_ensure_buffer(ctx, buf, buf->len + extra);
492
0
  }
493
494
  /* Write any bits that will fit into the existing byte */
495
0
  if (buf->unused_bits)
496
0
  {
497
0
    buf->data[buf->len-1] |= (shift >= 0 ? (((unsigned int)val)<<shift) : (((unsigned int)val)>>-shift));
498
0
    if (shift >= 0)
499
0
    {
500
      /* If we were shifting up, we're done. */
501
0
      buf->unused_bits -= bits;
502
0
      return;
503
0
    }
504
    /* The number of bits left to write is the number that didn't
505
     * fit in this first byte. */
506
0
    bits = -shift;
507
0
  }
508
509
  /* Write any whole bytes */
510
0
  while (bits >= 8)
511
0
  {
512
0
    bits -= 8;
513
0
    buf->data[buf->len++] = val>>bits;
514
0
  }
515
516
  /* Write trailing bits (with 0's in unused bits) */
517
0
  if (bits > 0)
518
0
  {
519
0
    bits = 8-bits;
520
0
    buf->data[buf->len++] = val<<bits;
521
0
  }
522
0
  buf->unused_bits = bits;
523
0
}
524
525
void
526
fz_append_bits_pad(fz_context *ctx, fz_buffer *buf)
527
0
{
528
0
  buf->unused_bits = 0;
529
0
}
530
531
static void fz_append_emit(fz_context *ctx, void *buffer, int c)
532
0
{
533
0
  fz_append_byte(ctx, buffer, c);
534
0
}
535
536
void
537
fz_append_printf(fz_context *ctx, fz_buffer *buffer, const char *fmt, ...)
538
0
{
539
0
  va_list args;
540
0
  va_start(args, fmt);
541
0
  fz_format_string(ctx, buffer, fz_append_emit, fmt, args);
542
0
  va_end(args);
543
0
}
544
545
void
546
fz_append_vprintf(fz_context *ctx, fz_buffer *buffer, const char *fmt, va_list args)
547
0
{
548
0
  fz_format_string(ctx, buffer, fz_append_emit, fmt, args);
549
0
}
550
551
void
552
fz_append_pdf_string(fz_context *ctx, fz_buffer *buffer, const char *text)
553
0
{
554
0
  size_t len = 2;
555
0
  const char *s = text;
556
0
  char *d;
557
0
  char c;
558
559
0
  while ((c = *s++) != 0)
560
0
  {
561
0
    switch (c)
562
0
    {
563
0
    case '\n':
564
0
    case '\r':
565
0
    case '\t':
566
0
    case '\b':
567
0
    case '\f':
568
0
    case '(':
569
0
    case ')':
570
0
    case '\\':
571
0
      len++;
572
0
      break;
573
0
    }
574
0
    len++;
575
0
  }
576
577
0
  while(buffer->cap - buffer->len < len)
578
0
    fz_grow_buffer(ctx, buffer);
579
580
0
  s = text;
581
0
  d = (char *)buffer->data + buffer->len;
582
0
  *d++ = '(';
583
0
  while ((c = *s++) != 0)
584
0
  {
585
0
    switch (c)
586
0
    {
587
0
    case '\n':
588
0
      *d++ = '\\';
589
0
      *d++ = 'n';
590
0
      break;
591
0
    case '\r':
592
0
      *d++ = '\\';
593
0
      *d++ = 'r';
594
0
      break;
595
0
    case '\t':
596
0
      *d++ = '\\';
597
0
      *d++ = 't';
598
0
      break;
599
0
    case '\b':
600
0
      *d++ = '\\';
601
0
      *d++ = 'b';
602
0
      break;
603
0
    case '\f':
604
0
      *d++ = '\\';
605
0
      *d++ = 'f';
606
0
      break;
607
0
    case '(':
608
0
      *d++ = '\\';
609
0
      *d++ = '(';
610
0
      break;
611
0
    case ')':
612
0
      *d++ = '\\';
613
0
      *d++ = ')';
614
0
      break;
615
0
    case '\\':
616
0
      *d++ = '\\';
617
0
      *d++ = '\\';
618
0
      break;
619
0
    default:
620
0
      *d++ = c;
621
0
    }
622
0
  }
623
0
  *d = ')';
624
0
  buffer->len += len;
625
0
}
626
627
void
628
fz_md5_buffer(fz_context *ctx, fz_buffer *buffer, unsigned char digest[16])
629
108
{
630
108
  fz_md5 state;
631
108
  fz_md5_init(&state);
632
108
  if (buffer)
633
108
    fz_md5_update(&state, buffer->data, buffer->len);
634
108
  fz_md5_final(&state, digest);
635
108
}
636
637
#ifdef TEST_BUFFER_WRITE
638
639
#define TEST_LEN 1024
640
641
void
642
fz_test_buffer_write(fz_context *ctx)
643
{
644
  fz_buffer *master = fz_new_buffer(ctx, TEST_LEN);
645
  fz_buffer *copy = fz_new_buffer(ctx, TEST_LEN);
646
  fz_stream *stm;
647
  int i, j, k;
648
649
  /* Make us a dummy buffer */
650
  for (i = 0; i < TEST_LEN; i++)
651
  {
652
    master->data[i] = rand();
653
  }
654
  master->len = TEST_LEN;
655
656
  /* Now copy that buffer several times, checking it for validity */
657
  stm = fz_open_buffer(ctx, master);
658
  for (i = 0; i < 256; i++)
659
  {
660
    memset(copy->data, i, TEST_LEN);
661
    copy->len = 0;
662
    j = TEST_LEN * 8;
663
    do
664
    {
665
      k = (rand() & 31)+1;
666
      if (k > j)
667
        k = j;
668
      fz_append_bits(ctx, copy, fz_read_bits(ctx, stm, k), k);
669
      j -= k;
670
    }
671
    while (j);
672
673
    if (memcmp(copy->data, master->data, TEST_LEN) != 0)
674
      fprintf(stderr, "Copied buffer is different!\n");
675
    fz_seek(stm, 0, 0);
676
  }
677
  fz_drop_stream(stm);
678
  fz_drop_buffer(ctx, master);
679
  fz_drop_buffer(ctx, copy);
680
}
681
#endif