Coverage Report

Created: 2025-01-28 06:17

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