Coverage Report

Created: 2023-06-07 06:20

/src/mupdf/source/fitz/printf.c
Line
Count
Source (jump to first uncovered line)
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
25
#include <float.h>
26
#include <math.h>
27
#include <stdarg.h>
28
#include <stdio.h>
29
30
#ifdef _MSC_VER
31
#if _MSC_VER < 1500 /* MSVC 2008 */
32
int snprintf(char *s, size_t n, const char *fmt, ...)
33
{
34
    int r;
35
    va_list ap;
36
    va_start(ap, fmt);
37
    r = vsprintf(s, fmt, ap);
38
    va_end(ap);
39
    return r;
40
}
41
#else if _MSC_VER < 1900 /* MSVC 2015 */
42
#define snprintf _snprintf
43
#endif
44
#endif
45
46
static const char *fz_hex_digits = "0123456789abcdef";
47
48
struct fmtbuf
49
{
50
  fz_context *ctx;
51
  void *user;
52
  void (*emit)(fz_context *ctx, void *user, int c);
53
};
54
55
static inline void fmtputc(struct fmtbuf *out, int c)
56
1.44G
{
57
1.44G
  out->emit(out->ctx, out->user, c);
58
1.44G
}
59
60
/*
61
 * Convert float to shortest possible string that won't lose precision, except:
62
 * NaN to 0, +Inf to FLT_MAX, -Inf to -FLT_MAX.
63
 */
64
static void fmtfloat(struct fmtbuf *out, float f)
65
1.29M
{
66
1.29M
  char digits[40], *s = digits;
67
1.29M
  int exp, ndigits, point;
68
69
1.29M
  if (isnan(f)) f = 0;
70
1.29M
  if (isinf(f)) f = f < 0 ? -FLT_MAX : FLT_MAX;
71
72
1.29M
  if (signbit(f))
73
592k
    fmtputc(out, '-');
74
75
1.29M
  if (f == 0)
76
17.1k
  {
77
17.1k
    fmtputc(out, '0');
78
17.1k
    return;
79
17.1k
  }
80
81
1.28M
  ndigits = fz_grisu(f, digits, &exp);
82
1.28M
  point = exp + ndigits;
83
84
1.28M
  if (point <= 0)
85
6.27k
  {
86
6.27k
    fmtputc(out, '.');
87
6.66k
    while (point++ < 0)
88
386
      fmtputc(out, '0');
89
30.2k
    while (ndigits-- > 0)
90
24.0k
      fmtputc(out, *s++);
91
6.27k
  }
92
93
1.27M
  else
94
1.27M
  {
95
10.8M
    while (ndigits-- > 0)
96
9.57M
    {
97
9.57M
      fmtputc(out, *s++);
98
9.57M
      if (--point == 0 && ndigits > 0)
99
657k
        fmtputc(out, '.');
100
9.57M
    }
101
2.14M
    while (point-- > 0)
102
869k
      fmtputc(out, '0');
103
1.27M
  }
104
1.28M
}
105
106
static void fmtfloat_e(struct fmtbuf *out, double f, int w, int p)
107
0
{
108
0
  char buf[100], *s = buf;
109
0
  snprintf(buf, sizeof buf, "%*.*e", w, p, f);
110
0
  while (*s)
111
0
    fmtputc(out, *s++);
112
0
}
113
114
static void fmtfloat_f(struct fmtbuf *out, double f, int w, int p)
115
0
{
116
0
  char buf[100], *s = buf;
117
0
  snprintf(buf, sizeof buf, "%*.*f", w, p, f);
118
0
  while (*s)
119
0
    fmtputc(out, *s++);
120
0
}
121
122
static void fmtuint32(struct fmtbuf *out, unsigned int a, int s, int z, int w, int base)
123
1.91M
{
124
1.91M
  char buf[40];
125
1.91M
  int i;
126
127
1.91M
  i = 0;
128
1.91M
  if (a == 0)
129
180k
    buf[i++] = '0';
130
7.43M
  while (a) {
131
5.51M
    buf[i++] = fz_hex_digits[a % base];
132
5.51M
    a /= base;
133
5.51M
  }
134
1.91M
  if (s) {
135
5.10k
    if (z == '0')
136
0
      while (i < w - 1)
137
0
        buf[i++] = z;
138
5.10k
    buf[i++] = s;
139
5.10k
  }
140
1.91M
  while (i < w)
141
27
    buf[i++] = z;
142
7.62M
  while (i > 0)
143
5.70M
    fmtputc(out, buf[--i]);
144
1.91M
}
145
146
static void fmtuint64(struct fmtbuf *out, uint64_t a, int s, int z, int w, int base)
147
75
{
148
75
  char buf[80];
149
75
  int i;
150
151
75
  i = 0;
152
75
  if (a == 0)
153
0
    buf[i++] = '0';
154
739
  while (a) {
155
664
    buf[i++] = fz_hex_digits[a % base];
156
664
    a /= base;
157
664
  }
158
75
  if (s) {
159
0
    if (z == '0')
160
0
      while (i < w - 1)
161
0
        buf[i++] = z;
162
0
    buf[i++] = s;
163
0
  }
164
75
  while (i < w)
165
0
    buf[i++] = z;
166
739
  while (i > 0)
167
664
    fmtputc(out, buf[--i]);
168
75
}
169
170
static void fmtint32(struct fmtbuf *out, int value, int s, int z, int w, int base)
171
1.38M
{
172
1.38M
  unsigned int a;
173
174
1.38M
  if (value < 0)
175
5.10k
  {
176
5.10k
    s = '-';
177
5.10k
    a = -value;
178
5.10k
  }
179
1.38M
  else if (s)
180
0
  {
181
0
    s = '+';
182
0
    a = value;
183
0
  }
184
1.38M
  else
185
1.38M
  {
186
1.38M
    s = 0;
187
1.38M
    a = value;
188
1.38M
  }
189
1.38M
  fmtuint32(out, a, s, z, w, base);
190
1.38M
}
191
192
static void fmtint64(struct fmtbuf *out, int64_t value, int s, int z, int w, int base)
193
0
{
194
0
  uint64_t a;
195
196
0
  if (value < 0)
197
0
  {
198
0
    s = '-';
199
0
    a = -value;
200
0
  }
201
0
  else if (s)
202
0
  {
203
0
    s = '+';
204
0
    a = value;
205
0
  }
206
0
  else
207
0
  {
208
0
    s = 0;
209
0
    a = value;
210
0
  }
211
0
  fmtuint64(out, a, s, z, w, base);
212
0
}
213
214
static void fmtquote(struct fmtbuf *out, const char *s, int sq, int eq, int verbatim)
215
0
{
216
0
  int i, n, c;
217
0
  fmtputc(out, sq);
218
0
  while (*s != 0) {
219
0
    n = fz_chartorune(&c, s);
220
0
    switch (c) {
221
0
    default:
222
0
      if (c < 32) {
223
0
        fmtputc(out, '\\');
224
0
        fmtputc(out, 'x');
225
0
        fmtputc(out, "0123456789ABCDEF"[(c>>4)&15]);
226
0
        fmtputc(out, "0123456789ABCDEF"[(c)&15]);
227
0
      } else if (c > 127) {
228
0
        if (verbatim)
229
0
        {
230
0
          for (i = 0; i < n; ++i)
231
0
            fmtputc(out, s[i]);
232
0
        }
233
0
        else
234
0
        {
235
0
          fmtputc(out, '\\');
236
0
          fmtputc(out, 'u');
237
0
          fmtputc(out, "0123456789ABCDEF"[(c>>12)&15]);
238
0
          fmtputc(out, "0123456789ABCDEF"[(c>>8)&15]);
239
0
          fmtputc(out, "0123456789ABCDEF"[(c>>4)&15]);
240
0
          fmtputc(out, "0123456789ABCDEF"[(c)&15]);
241
0
        }
242
0
      } else {
243
0
        if (c == sq || c == eq)
244
0
          fmtputc(out, '\\');
245
0
        fmtputc(out, c);
246
0
      }
247
0
      break;
248
0
    case '\\': fmtputc(out, '\\'); fmtputc(out, '\\'); break;
249
0
    case '\b': fmtputc(out, '\\'); fmtputc(out, 'b'); break;
250
0
    case '\f': fmtputc(out, '\\'); fmtputc(out, 'f'); break;
251
0
    case '\n': fmtputc(out, '\\'); fmtputc(out, 'n'); break;
252
0
    case '\r': fmtputc(out, '\\'); fmtputc(out, 'r'); break;
253
0
    case '\t': fmtputc(out, '\\'); fmtputc(out, 't'); break;
254
0
    }
255
0
    s += n;
256
0
  }
257
0
  fmtputc(out, eq);
258
0
}
259
260
static void fmtquote_pdf(struct fmtbuf *out, const char *s, int sq, int eq)
261
0
{
262
0
  int c;
263
0
  fmtputc(out, sq);
264
0
  while ((c = (unsigned char)*s++) != 0) {
265
0
    switch (c) {
266
0
    default:
267
0
      if (c < 32 || c > 127) {
268
0
        fmtputc(out, '\\');
269
0
        if (sq == '(')
270
0
        {
271
0
          fmtputc(out, '0' + ((c >> 6) & 7));
272
0
          fmtputc(out, '0' + ((c >> 3) & 7));
273
0
          fmtputc(out, '0' + ((c) & 7));
274
0
        }
275
0
        else
276
0
        {
277
0
          fmtputc(out, 'x');
278
0
          fmtputc(out, "0123456789ABCDEF"[(c>>4)&15]);
279
0
          fmtputc(out, "0123456789ABCDEF"[(c)&15]);
280
0
        }
281
0
      } else {
282
0
        if (c == sq || c == eq)
283
0
          fmtputc(out, '\\');
284
0
        fmtputc(out, c);
285
0
      }
286
0
      break;
287
0
    case '\\': fmtputc(out, '\\'); fmtputc(out, '\\'); break;
288
0
    case '\b': fmtputc(out, '\\'); fmtputc(out, 'b'); break;
289
0
    case '\f': fmtputc(out, '\\'); fmtputc(out, 'f'); break;
290
0
    case '\n': fmtputc(out, '\\'); fmtputc(out, 'n'); break;
291
0
    case '\r': fmtputc(out, '\\'); fmtputc(out, 'r'); break;
292
0
    case '\t': fmtputc(out, '\\'); fmtputc(out, 't'); break;
293
0
    }
294
0
  }
295
0
  fmtputc(out, eq);
296
0
}
297
298
static void fmtname(struct fmtbuf *out, const char *s)
299
0
{
300
0
  int c;
301
0
  fmtputc(out, '/');
302
0
  while ((c = *s++) != 0) {
303
0
    if (c <= 32 || c == '/' || c == '#') {
304
0
      fmtputc(out, '#');
305
0
      fmtputc(out, "0123456789ABCDEF"[(c>>4)&15]);
306
0
      fmtputc(out, "0123456789ABCDEF"[(c)&15]);
307
0
    } else {
308
0
      fmtputc(out, c);
309
0
    }
310
0
  }
311
0
}
312
313
void
314
fz_format_string(fz_context *ctx, void *user, void (*emit)(fz_context *ctx, void *user, int c), const char *fmt, va_list args)
315
41.9M
{
316
41.9M
  struct fmtbuf out;
317
41.9M
  int c, s, z, p, w;
318
41.9M
  int32_t i32;
319
41.9M
  int64_t i64;
320
41.9M
  const char *str;
321
41.9M
  size_t bits;
322
323
41.9M
  out.ctx = ctx;
324
41.9M
  out.user = user;
325
41.9M
  out.emit = emit;
326
327
1.26G
  while ((c = *fmt++) != 0)
328
1.21G
  {
329
1.21G
    if (c == '%')
330
11.4M
    {
331
11.4M
      s = 0;
332
11.4M
      z = ' ';
333
334
      /* flags */
335
11.4M
      while ((c = *fmt++) != 0)
336
11.4M
      {
337
        /* plus sign */
338
11.4M
        if (c == '+')
339
0
          s = 1;
340
        /* space sign */
341
11.4M
        else if (c == ' ')
342
0
          s = ' ';
343
        /* zero padding */
344
11.4M
        else if (c == '0')
345
5.97k
          z = '0';
346
        /* TODO: '-' to left justify */
347
11.4M
        else
348
11.4M
          break;
349
11.4M
      }
350
11.4M
      if (c == 0)
351
0
        break;
352
353
      /* width */
354
11.4M
      w = 0;
355
11.4M
      if (c == '*') {
356
0
        c = *fmt++;
357
0
        w = va_arg(args, int);
358
11.4M
      } else {
359
11.4M
        while (c >= '0' && c <= '9') {
360
5.97k
          w = w * 10 + c - '0';
361
5.97k
          c = *fmt++;
362
5.97k
        }
363
11.4M
      }
364
11.4M
      if (c == 0)
365
0
        break;
366
367
      /* precision */
368
11.4M
      p = 6;
369
11.4M
      if (c == '.') {
370
0
        c = *fmt++;
371
0
        if (c == 0)
372
0
          break;
373
0
        if (c == '*') {
374
0
          c = *fmt++;
375
0
          p = va_arg(args, int);
376
0
        } else {
377
0
          if (c >= '0' && c <= '9')
378
0
            p = 0;
379
0
          while (c >= '0' && c <= '9') {
380
0
            p = p * 10 + c - '0';
381
0
            c = *fmt++;
382
0
          }
383
0
        }
384
0
      }
385
11.4M
      if (c == 0)
386
0
        break;
387
388
      /* lengths */
389
11.4M
      bits = 0;
390
11.4M
      if (c == 'l') {
391
0
        c = *fmt++;
392
0
        bits = sizeof(int64_t) * 8;
393
0
        if (c == 0)
394
0
          break;
395
0
      }
396
11.4M
      if (c == 't') {
397
0
        c = *fmt++;
398
0
        bits = sizeof(ptrdiff_t) * 8;
399
0
        if (c == 0)
400
0
          break;
401
0
      }
402
11.4M
      if (c == 'z') {
403
75
        c = *fmt++;
404
75
        bits = sizeof(size_t) * 8;
405
75
        if (c == 0)
406
0
          break;
407
75
      }
408
409
11.4M
      switch (c) {
410
0
      default:
411
0
        fmtputc(&out, '%');
412
0
        fmtputc(&out, c);
413
0
        break;
414
0
      case '%':
415
0
        fmtputc(&out, '%');
416
0
        break;
417
418
0
      case 'M':
419
0
        {
420
0
          fz_matrix *matrix = va_arg(args, fz_matrix*);
421
0
          fmtfloat(&out, matrix->a); fmtputc(&out, ' ');
422
0
          fmtfloat(&out, matrix->b); fmtputc(&out, ' ');
423
0
          fmtfloat(&out, matrix->c); fmtputc(&out, ' ');
424
0
          fmtfloat(&out, matrix->d); fmtputc(&out, ' ');
425
0
          fmtfloat(&out, matrix->e); fmtputc(&out, ' ');
426
0
          fmtfloat(&out, matrix->f);
427
0
        }
428
0
        break;
429
0
      case 'R':
430
0
        {
431
0
          fz_rect *rect = va_arg(args, fz_rect*);
432
0
          fmtfloat(&out, rect->x0); fmtputc(&out, ' ');
433
0
          fmtfloat(&out, rect->y0); fmtputc(&out, ' ');
434
0
          fmtfloat(&out, rect->x1); fmtputc(&out, ' ');
435
0
          fmtfloat(&out, rect->y1);
436
0
        }
437
0
        break;
438
0
      case 'P':
439
0
        {
440
0
          fz_point *point = va_arg(args, fz_point*);
441
0
          fmtfloat(&out, point->x); fmtputc(&out, ' ');
442
0
          fmtfloat(&out, point->y);
443
0
        }
444
0
        break;
445
446
0
      case 'C': /* unicode char */
447
0
        c = va_arg(args, int);
448
0
        if (c < 128)
449
0
          fmtputc(&out, c);
450
0
        else {
451
0
          char buf[10];
452
0
          int i, n = fz_runetochar(buf, c);
453
0
          for (i=0; i < n; ++i)
454
0
            fmtputc(&out, buf[i]);
455
0
        }
456
0
        break;
457
5.34k
      case 'c':
458
5.34k
        c = va_arg(args, int);
459
5.34k
        fmtputc(&out, c);
460
5.34k
        break;
461
462
0
      case 'e':
463
0
        fmtfloat_e(&out, va_arg(args, double), w, p);
464
0
        break;
465
0
      case 'f':
466
0
        fmtfloat_f(&out, va_arg(args, double), w, p);
467
0
        break;
468
1.29M
      case 'g':
469
1.29M
        fmtfloat(&out, va_arg(args, double));
470
1.29M
        break;
471
472
0
      case 'p':
473
0
        bits = 8 * sizeof(void *);
474
0
        z = '0';
475
0
        fmtputc(&out, '0');
476
0
        fmtputc(&out, 'x');
477
        /* fallthrough */
478
5.99k
      case 'x':
479
5.99k
        if (bits == 64)
480
0
        {
481
0
          i64 = va_arg(args, int64_t);
482
0
          fmtuint64(&out, i64, 0, z, w, 16);
483
0
        }
484
5.99k
        else
485
5.99k
        {
486
5.99k
          i32 = va_arg(args, int);
487
5.99k
          fmtuint32(&out, i32, 0, z, w, 16);
488
5.99k
        }
489
5.99k
        break;
490
1.38M
      case 'd':
491
1.38M
      case 'i':
492
1.38M
        if (bits == 64)
493
0
        {
494
0
          i64 = va_arg(args, int64_t);
495
0
          fmtint64(&out, i64, s, z, w, 10);
496
0
        }
497
1.38M
        else
498
1.38M
        {
499
1.38M
          i32 = va_arg(args, int);
500
1.38M
          fmtint32(&out, i32, s, z, w, 10);
501
1.38M
        }
502
1.38M
        break;
503
526k
      case 'u':
504
526k
        if (bits == 64)
505
75
        {
506
75
          i64 = va_arg(args, int64_t);
507
75
          fmtuint64(&out, i64, 0, z, w, 10);
508
75
        }
509
526k
        else
510
526k
        {
511
526k
          i32 = va_arg(args, int);
512
526k
          fmtuint32(&out, i32, 0, z, w, 10);
513
526k
        }
514
526k
        break;
515
516
8.25M
      case 's':
517
8.25M
        str = va_arg(args, const char*);
518
8.25M
        if (!str)
519
0
          str = "(null)";
520
231M
        while ((c = *str++) != 0)
521
223M
          fmtputc(&out, c);
522
8.25M
        break;
523
0
      case 'Q': /* quoted string (with verbatim unicode) */
524
0
        str = va_arg(args, const char*);
525
0
        if (!str) str = "";
526
0
        fmtquote(&out, str, '"', '"', 1);
527
0
        break;
528
0
      case 'q': /* quoted string */
529
0
        str = va_arg(args, const char*);
530
0
        if (!str) str = "";
531
0
        fmtquote(&out, str, '"', '"', 0);
532
0
        break;
533
0
      case '(': /* pdf string */
534
0
        str = va_arg(args, const char*);
535
0
        if (!str) str = "";
536
0
        fmtquote_pdf(&out, str, '(', ')');
537
0
        break;
538
0
      case 'n': /* pdf name */
539
0
        str = va_arg(args, const char*);
540
0
        if (!str) str = "";
541
0
        fmtname(&out, str);
542
0
        break;
543
11.4M
      }
544
11.4M
    }
545
1.20G
    else
546
1.20G
    {
547
1.20G
      fmtputc(&out, c);
548
1.20G
    }
549
1.21G
  }
550
41.9M
}
551
552
struct snprintf_buffer
553
{
554
  char *p;
555
  size_t s, n;
556
};
557
558
static void snprintf_emit(fz_context *ctx, void *out_, int c)
559
1.43G
{
560
1.43G
  struct snprintf_buffer *out = out_;
561
1.43G
  if (out->n < out->s)
562
1.43G
    out->p[out->n] = c;
563
1.43G
  ++(out->n);
564
1.43G
}
565
566
size_t
567
fz_vsnprintf(char *buffer, size_t space, const char *fmt, va_list args)
568
41.1M
{
569
41.1M
  struct snprintf_buffer out;
570
41.1M
  out.p = buffer;
571
41.1M
  out.s = space > 0 ? space - 1 : 0;
572
41.1M
  out.n = 0;
573
574
  /* Note: using a NULL context is safe here */
575
41.1M
  fz_format_string(NULL, &out, snprintf_emit, fmt, args);
576
41.1M
  if (space > 0)
577
41.1M
    out.p[out.n < space ? out.n : space - 1] = '\0';
578
579
41.1M
  return out.n;
580
41.1M
}
581
582
size_t
583
fz_snprintf(char *buffer, size_t space, const char *fmt, ...)
584
97.1k
{
585
97.1k
  va_list ap;
586
97.1k
  struct snprintf_buffer out;
587
97.1k
  out.p = buffer;
588
97.1k
  out.s = space > 0 ? space - 1 : 0;
589
97.1k
  out.n = 0;
590
591
97.1k
  va_start(ap, fmt);
592
  /* Note: using a NULL context is safe here */
593
97.1k
  fz_format_string(NULL, &out, snprintf_emit, fmt, ap);
594
97.1k
  if (space > 0)
595
97.1k
    out.p[out.n < space ? out.n : space - 1] = '\0';
596
97.1k
  va_end(ap);
597
598
97.1k
  return out.n;
599
97.1k
}
600
601
char *
602
fz_asprintf(fz_context *ctx, const char *fmt, ...)
603
813
{
604
813
  size_t len;
605
813
  char *mem;
606
813
  va_list ap;
607
813
  va_start(ap, fmt);
608
813
  len = fz_vsnprintf(NULL, 0, fmt, ap);
609
813
  va_end(ap);
610
813
  mem = Memento_label(fz_malloc(ctx, len+1), "asprintf");
611
813
  va_start(ap, fmt);
612
813
  fz_vsnprintf(mem, len+1, fmt, ap);
613
813
  va_end(ap);
614
813
  return mem;
615
813
}