Coverage Report

Created: 2026-05-16 07:03

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/mupdf/source/fitz/printf.c
Line
Count
Source
1
// Copyright (C) 2004-2025 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
static const char *fz_hex_digits_UC = "0123456789ABCDEF";
48
49
struct fmtbuf
50
{
51
  fz_context *ctx;
52
  void *user;
53
  void (*emit)(fz_context *ctx, void *user, int c);
54
};
55
56
static inline void fmtputc(struct fmtbuf *out, int c)
57
6.83M
{
58
6.83M
  out->emit(out->ctx, out->user, c);
59
6.83M
}
60
61
static inline void fmtputrune(struct fmtbuf *out, int c)
62
0
{
63
0
  char buf[10];
64
0
  int i, n;
65
0
  if (c < 128)
66
0
    fmtputc(out, c);
67
0
  else
68
0
  {
69
0
    n = fz_runetochar(buf, c);
70
0
    for (i = 0; i < n; ++i)
71
0
      fmtputc(out, buf[i]);
72
0
  }
73
0
}
74
75
/*
76
 * Convert float to shortest possible string that won't lose precision, except:
77
 * NaN to 0, +Inf to FLT_MAX, -Inf to -FLT_MAX.
78
 */
79
static void fmtfloat(struct fmtbuf *out, float f)
80
3.30k
{
81
3.30k
  char digits[40], *s = digits;
82
3.30k
  int exp, ndigits, point;
83
84
3.30k
  if (isnan(f)) f = 0;
85
3.30k
  if (isinf(f)) f = f < 0 ? -FLT_MAX : FLT_MAX;
86
87
3.30k
  if (signbit(f))
88
0
    fmtputc(out, '-');
89
90
3.30k
  if (f == 0)
91
560
  {
92
560
    fmtputc(out, '0');
93
560
    return;
94
560
  }
95
96
2.74k
  ndigits = fz_grisu(f, digits, &exp);
97
2.74k
  point = exp + ndigits;
98
99
2.74k
  if (point <= 0)
100
104
  {
101
104
    fmtputc(out, '.');
102
104
    while (point++ < 0)
103
0
      fmtputc(out, '0');
104
420
    while (ndigits-- > 0)
105
316
      fmtputc(out, *s++);
106
104
  }
107
108
2.64k
  else
109
2.64k
  {
110
14.9k
    while (ndigits-- > 0)
111
12.2k
    {
112
12.2k
      fmtputc(out, *s++);
113
12.2k
      if (--point == 0 && ndigits > 0)
114
1.51k
        fmtputc(out, '.');
115
12.2k
    }
116
2.69k
    while (point-- > 0)
117
51
      fmtputc(out, '0');
118
2.64k
  }
119
2.74k
}
120
121
static void fmtfloat_e(struct fmtbuf *out, double f, int w, int p)
122
0
{
123
0
  char buf[100], *s = buf;
124
0
  snprintf(buf, sizeof buf, "%*.*e", w, p, f);
125
0
  while (*s)
126
0
    fmtputc(out, *s++);
127
0
}
128
129
static void fmtfloat_f(struct fmtbuf *out, double f, int w, int p)
130
0
{
131
0
  char buf[100], *s = buf;
132
0
  snprintf(buf, sizeof buf, "%*.*f", w, p, f);
133
0
  while (*s)
134
0
    fmtputc(out, *s++);
135
0
}
136
137
static void fmtuint32(struct fmtbuf *out, unsigned int a, int s, int z, int w, int base, int q)
138
85.3k
{
139
85.3k
  char buf[40];
140
85.3k
  int i;
141
85.3k
  const char *hex_digits = fz_hex_digits;
142
143
85.3k
  if (base < 0)
144
0
  {
145
0
    base = -base;
146
0
    hex_digits = fz_hex_digits_UC;
147
0
  }
148
149
85.3k
  i = 0;
150
85.3k
  if (a == 0)
151
23
    buf[i++] = '0';
152
458k
  while (a) {
153
373k
    buf[i++] = hex_digits[a % base];
154
373k
    a /= base;
155
373k
  }
156
85.3k
  if (s) {
157
2
    if (z == '0')
158
0
      while (i < w - 1)
159
0
        buf[i++] = z;
160
2
    buf[i++] = s;
161
2
  }
162
85.3k
  while (i < w)
163
0
    buf[i++] = z;
164
458k
  while (i > 0)
165
373k
  {
166
373k
    fmtputc(out, buf[--i]);
167
373k
    if (q && i != 0 && i % 3 == 0)
168
0
      fmtputc(out, q);
169
373k
  }
170
85.3k
}
171
172
static void fmtuint64(struct fmtbuf *out, uint64_t a, int s, int z, int w, int base, int q)
173
3
{
174
3
  char buf[80];
175
3
  int i;
176
3
  const char *hex_digits = fz_hex_digits;
177
178
3
  if (base < 0)
179
0
  {
180
0
    base = -base;
181
0
    hex_digits = fz_hex_digits_UC;
182
0
  }
183
184
3
  i = 0;
185
3
  if (a == 0)
186
0
    buf[i++] = '0';
187
45
  while (a) {
188
42
    buf[i++] = hex_digits[a % base];
189
42
    a /= base;
190
42
  }
191
3
  if (s) {
192
0
    if (z == '0')
193
0
      while (i < w - 1)
194
0
        buf[i++] = z;
195
0
    buf[i++] = s;
196
0
  }
197
3
  while (i < w)
198
0
    buf[i++] = z;
199
45
  while (i > 0)
200
42
  {
201
42
    fmtputc(out, buf[--i]);
202
42
    if (q && i != 0 && i % 3 == 0)
203
0
      fmtputc(out, q);
204
42
  }
205
3
}
206
207
static void fmtint32(struct fmtbuf *out, int value, int s, int z, int w, int base, int q)
208
85.3k
{
209
85.3k
  unsigned int a;
210
211
85.3k
  if (value < 0)
212
2
  {
213
2
    s = '-';
214
2
    a = -value;
215
2
  }
216
85.3k
  else if (s)
217
0
  {
218
0
    s = '+';
219
0
    a = value;
220
0
  }
221
85.3k
  else
222
85.3k
  {
223
85.3k
    s = 0;
224
85.3k
    a = value;
225
85.3k
  }
226
85.3k
  fmtuint32(out, a, s, z, w, base, q);
227
85.3k
}
228
229
static void fmtint64(struct fmtbuf *out, int64_t value, int s, int z, int w, int base, int q)
230
3
{
231
3
  uint64_t a;
232
233
3
  if (value < 0)
234
0
  {
235
0
    s = '-';
236
0
    a = -value;
237
0
  }
238
3
  else if (s)
239
0
  {
240
0
    s = '+';
241
0
    a = value;
242
0
  }
243
3
  else
244
3
  {
245
3
    s = 0;
246
3
    a = value;
247
3
  }
248
3
  fmtuint64(out, a, s, z, w, base, q);
249
3
}
250
251
static void fmtquote(struct fmtbuf *out, const char *s, int sq, int eq, int verbatim)
252
0
{
253
0
  int i, n, c;
254
0
  fmtputc(out, sq);
255
0
  while (*s != 0) {
256
0
    n = fz_chartorune(&c, s);
257
0
    switch (c) {
258
0
    default:
259
0
      if (c < 32) {
260
0
        fmtputc(out, '\\');
261
0
        fmtputc(out, 'x');
262
0
        fmtputc(out, "0123456789ABCDEF"[(c>>4)&15]);
263
0
        fmtputc(out, "0123456789ABCDEF"[(c)&15]);
264
0
      } else if (c > 127) {
265
0
        if (verbatim)
266
0
        {
267
0
          for (i = 0; i < n; ++i)
268
0
            fmtputc(out, s[i]);
269
0
        }
270
0
        else if (c <= 0xffff)
271
0
        {
272
0
          fmtputc(out, '\\');
273
0
          fmtputc(out, 'u');
274
0
          fmtputc(out, "0123456789ABCDEF"[(c>>12)&15]);
275
0
          fmtputc(out, "0123456789ABCDEF"[(c>>8)&15]);
276
0
          fmtputc(out, "0123456789ABCDEF"[(c>>4)&15]);
277
0
          fmtputc(out, "0123456789ABCDEF"[(c)&15]);
278
0
        }
279
0
        else
280
0
        {
281
          /* Use a surrogate pair */
282
0
          int hi = 0xd800 + ((c - 0x10000) >> 10);
283
0
          int lo = 0xdc00 + ((c - 0x10000) & 0x3ff);
284
0
          fmtputc(out, '\\');
285
0
          fmtputc(out, 'u');
286
0
          fmtputc(out, "0123456789ABCDEF"[(hi>>12)&15]);
287
0
          fmtputc(out, "0123456789ABCDEF"[(hi>>8)&15]);
288
0
          fmtputc(out, "0123456789ABCDEF"[(hi>>4)&15]);
289
0
          fmtputc(out, "0123456789ABCDEF"[(hi)&15]);
290
0
          fmtputc(out, '\\');
291
0
          fmtputc(out, 'u');
292
0
          fmtputc(out, "0123456789ABCDEF"[(lo>>12)&15]);
293
0
          fmtputc(out, "0123456789ABCDEF"[(lo>>8)&15]);
294
0
          fmtputc(out, "0123456789ABCDEF"[(lo>>4)&15]);
295
0
          fmtputc(out, "0123456789ABCDEF"[(lo)&15]);
296
0
        }
297
0
      } else {
298
0
        if (c == sq || c == eq)
299
0
          fmtputc(out, '\\');
300
0
        fmtputc(out, c);
301
0
      }
302
0
      break;
303
0
    case '\\': fmtputc(out, '\\'); fmtputc(out, '\\'); break;
304
0
    case '\b': fmtputc(out, '\\'); fmtputc(out, 'b'); break;
305
0
    case '\f': fmtputc(out, '\\'); fmtputc(out, 'f'); break;
306
0
    case '\n': fmtputc(out, '\\'); fmtputc(out, 'n'); break;
307
0
    case '\r': fmtputc(out, '\\'); fmtputc(out, 'r'); break;
308
0
    case '\t': fmtputc(out, '\\'); fmtputc(out, 't'); break;
309
0
    }
310
0
    s += n;
311
0
  }
312
0
  fmtputc(out, eq);
313
0
}
314
315
static void fmtquote_pdf(struct fmtbuf *out, const char *s, int sq, int eq)
316
0
{
317
0
  int c;
318
0
  fmtputc(out, sq);
319
0
  while ((c = (unsigned char)*s++) != 0) {
320
0
    switch (c) {
321
0
    default:
322
0
      if (c < 32 || c > 127) {
323
0
        fmtputc(out, '\\');
324
0
        if (sq == '(')
325
0
        {
326
0
          fmtputc(out, '0' + ((c >> 6) & 7));
327
0
          fmtputc(out, '0' + ((c >> 3) & 7));
328
0
          fmtputc(out, '0' + ((c) & 7));
329
0
        }
330
0
        else
331
0
        {
332
0
          fmtputc(out, 'x');
333
0
          fmtputc(out, "0123456789ABCDEF"[(c>>4)&15]);
334
0
          fmtputc(out, "0123456789ABCDEF"[(c)&15]);
335
0
        }
336
0
      } else {
337
0
        if (c == sq || c == eq)
338
0
          fmtputc(out, '\\');
339
0
        fmtputc(out, c);
340
0
      }
341
0
      break;
342
0
    case '\\': fmtputc(out, '\\'); fmtputc(out, '\\'); break;
343
0
    case '\b': fmtputc(out, '\\'); fmtputc(out, 'b'); break;
344
0
    case '\f': fmtputc(out, '\\'); fmtputc(out, 'f'); break;
345
0
    case '\n': fmtputc(out, '\\'); fmtputc(out, 'n'); break;
346
0
    case '\r': fmtputc(out, '\\'); fmtputc(out, 'r'); break;
347
0
    case '\t': fmtputc(out, '\\'); fmtputc(out, 't'); break;
348
0
    }
349
0
  }
350
0
  fmtputc(out, eq);
351
0
}
352
353
int
354
fz_is_valid_xml_char(int c)
355
0
{
356
0
  if (c == 9 || c == 10 || c == 13)
357
0
    return 1;
358
0
  if (c < 32)
359
0
    return 0;
360
0
  if (c < 0xd800)
361
0
    return 1;
362
0
  if (c < 0xe000)
363
0
    return 0;
364
0
  if (c <= 0xfffd)
365
0
    return 1;
366
0
  if (c < 0x10000)
367
0
    return 0;
368
0
  if (c <= 0x10FFFF)
369
0
    return 1;
370
0
  return 0;
371
0
}
372
373
int
374
fz_is_valid_xml_string(const char *s)
375
0
{
376
0
  int c, n;
377
0
  while (*s != 0) {
378
0
    n = fz_chartorune(&c, s);
379
0
    if (!fz_is_valid_xml_char(c))
380
0
      return 0;
381
0
    s += n;
382
0
  }
383
0
  return 1;
384
0
}
385
386
int
387
fz_range_limit_xml_char(int c)
388
0
{
389
0
  if (fz_is_valid_xml_char(c))
390
0
    return c;
391
0
  return 0xFFFD;
392
0
}
393
394
static void fmtquote_xml(struct fmtbuf *out, const char *s)
395
0
{
396
0
  int c, n;
397
0
  fmtputc(out, '"');
398
0
  while (*s != 0) {
399
0
    n = fz_chartorune(&c, s);
400
0
    switch (c) {
401
0
    case '"':
402
0
      fmtputc(out, '&');
403
0
      fmtputc(out, 'q');
404
0
      fmtputc(out, 'u');
405
0
      fmtputc(out, 'o');
406
0
      fmtputc(out, 't');
407
0
      fmtputc(out, ';');
408
0
      break;
409
0
    case '&':
410
0
      fmtputc(out, '&');
411
0
      fmtputc(out, 'a');
412
0
      fmtputc(out, 'm');
413
0
      fmtputc(out, 'p');
414
0
      fmtputc(out, ';');
415
0
      break;
416
0
    case '<':
417
0
      fmtputc(out, '&');
418
0
      fmtputc(out, 'l');
419
0
      fmtputc(out, 't');
420
0
      fmtputc(out, ';');
421
0
      break;
422
0
    case '>':
423
0
      fmtputc(out, '&');
424
0
      fmtputc(out, 'g');
425
0
      fmtputc(out, 't');
426
0
      fmtputc(out, ';');
427
0
      break;
428
0
    default:
429
0
      c = fz_range_limit_xml_char(c);
430
0
      if (c < 32 || c >= 127)
431
0
      {
432
0
        fmtputc(out, '&');
433
0
        fmtputc(out, '#');
434
0
        fmtputc(out, 'x');
435
0
        if (c > 65535)
436
0
        {
437
0
          fmtputc(out, "0123456789ABCDEF"[(c>>20)&15]);
438
0
          fmtputc(out, "0123456789ABCDEF"[(c>>16)&15]);
439
0
        }
440
0
        if (c > 255)
441
0
        {
442
0
          fmtputc(out, "0123456789ABCDEF"[(c>>12)&15]);
443
0
          fmtputc(out, "0123456789ABCDEF"[(c>>8)&15]);
444
0
        }
445
0
        fmtputc(out, "0123456789ABCDEF"[(c>>4)&15]);
446
0
        fmtputc(out, "0123456789ABCDEF"[(c)&15]);
447
0
        fmtputc(out, ';');
448
0
      }
449
0
      else
450
0
        fmtputc(out, c);
451
0
      break;
452
0
    }
453
0
    s += n;
454
0
  }
455
0
  fmtputc(out, '"');
456
0
}
457
458
static void fmtquote_hex(struct fmtbuf *out, const char *s)
459
0
{
460
0
  int c;
461
0
  fmtputc(out, '"');
462
0
  while ((c = *s++) != 0)
463
0
  {
464
0
    fmtputc(out, "0123456789ABCDEF"[(c>>4)&15]);
465
0
    fmtputc(out, "0123456789ABCDEF"[(c)&15]);
466
0
  }
467
0
  fmtputc(out, '"');
468
0
}
469
470
static void fmtname(struct fmtbuf *out, const char *s)
471
0
{
472
0
  int c;
473
0
  fmtputc(out, '/');
474
0
  while ((c = *s++) != 0) {
475
0
    if (c <= 32 || c == '/' || c == '#') {
476
0
      fmtputc(out, '#');
477
0
      fmtputc(out, "0123456789ABCDEF"[(c>>4)&15]);
478
0
      fmtputc(out, "0123456789ABCDEF"[(c)&15]);
479
0
    } else {
480
0
      fmtputc(out, c);
481
0
    }
482
0
  }
483
0
}
484
485
void
486
fz_format_string(fz_context *ctx, void *user, void (*emit)(fz_context *ctx, void *user, int c), const char *fmt, va_list args)
487
209k
{
488
209k
  struct fmtbuf out;
489
209k
  int c, s, z, p, ps, w, q, i;
490
209k
  int32_t i32;
491
209k
  int64_t i64;
492
209k
  const char *str;
493
209k
  const wchar_t *wstr;
494
209k
  size_t bits;
495
496
209k
  out.ctx = ctx;
497
209k
  out.user = user;
498
209k
  out.emit = emit;
499
500
5.27M
  while ((c = *fmt++) != 0)
501
5.06M
  {
502
5.06M
    if (c == '%')
503
183k
    {
504
183k
      q = 0;
505
183k
      s = 0;
506
183k
      z = ' ';
507
508
      /* flags */
509
183k
      while ((c = *fmt++) != 0)
510
183k
      {
511
        /* plus sign */
512
183k
        if (c == '+')
513
0
          s = 1;
514
        /* space sign */
515
183k
        else if (c == ' ')
516
0
          s = ' ';
517
        /* zero padding */
518
183k
        else if (c == '0')
519
0
          z = '0';
520
        /* comma separators */
521
183k
        else if (c == '\'')
522
0
          q = '\'';
523
183k
        else if (c == ',')
524
0
          q = ',';
525
183k
        else if (c == '_')
526
0
          q = '_';
527
        /* TODO: '-' to left justify */
528
183k
        else
529
183k
          break;
530
183k
      }
531
183k
      if (c == 0)
532
0
        break;
533
534
      /* width */
535
183k
      w = 0;
536
183k
      if (c == '*') {
537
0
        c = *fmt++;
538
0
        w = va_arg(args, int);
539
183k
      } else {
540
183k
        while (c >= '0' && c <= '9') {
541
0
          w = w * 10 + c - '0';
542
0
          c = *fmt++;
543
0
        }
544
183k
      }
545
183k
      if (c == 0)
546
0
        break;
547
548
      /* precision */
549
183k
      p = 6;
550
183k
      ps = -1;
551
183k
      if (c == '.') {
552
14
        c = *fmt++;
553
14
        if (c == 0)
554
0
          break;
555
14
        if (c == '*') {
556
14
          c = *fmt++;
557
14
          p = va_arg(args, int);
558
14
        } else {
559
0
          if (c >= '0' && c <= '9')
560
0
            p = 0;
561
0
          while (c >= '0' && c <= '9') {
562
0
            p = p * 10 + c - '0';
563
0
            c = *fmt++;
564
0
          }
565
0
        }
566
14
        ps = p;
567
14
      }
568
183k
      if (c == 0)
569
0
        break;
570
571
      /* lengths */
572
183k
      bits = 0;
573
183k
      if (c == 'l') {
574
3
        c = *fmt++;
575
3
        bits = sizeof(int64_t) * 8;
576
3
        if (c == 0)
577
0
          break;
578
3
      }
579
183k
      if (c == 't') {
580
0
        c = *fmt++;
581
0
        bits = sizeof(ptrdiff_t) * 8;
582
0
        if (c == 0)
583
0
          break;
584
0
      }
585
183k
      if (c == 'z') {
586
0
        c = *fmt++;
587
0
        bits = sizeof(size_t) * 8;
588
0
        if (c == 0)
589
0
          break;
590
0
      }
591
592
183k
      switch (c) {
593
0
      default:
594
0
        fmtputc(&out, '%');
595
0
        fmtputc(&out, c);
596
0
        break;
597
0
      case '%':
598
0
        fmtputc(&out, '%');
599
0
        break;
600
601
0
      case 'M':
602
0
        {
603
0
          fz_matrix *matrix = va_arg(args, fz_matrix*);
604
0
          fmtfloat(&out, matrix->a); fmtputc(&out, ' ');
605
0
          fmtfloat(&out, matrix->b); fmtputc(&out, ' ');
606
0
          fmtfloat(&out, matrix->c); fmtputc(&out, ' ');
607
0
          fmtfloat(&out, matrix->d); fmtputc(&out, ' ');
608
0
          fmtfloat(&out, matrix->e); fmtputc(&out, ' ');
609
0
          fmtfloat(&out, matrix->f);
610
0
        }
611
0
        break;
612
0
      case 'R':
613
0
        {
614
0
          fz_rect *rect = va_arg(args, fz_rect*);
615
0
          fmtfloat(&out, rect->x0); fmtputc(&out, ' ');
616
0
          fmtfloat(&out, rect->y0); fmtputc(&out, ' ');
617
0
          fmtfloat(&out, rect->x1); fmtputc(&out, ' ');
618
0
          fmtfloat(&out, rect->y1);
619
0
        }
620
0
        break;
621
0
      case 'P':
622
0
        {
623
0
          fz_point *point = va_arg(args, fz_point*);
624
0
          fmtfloat(&out, point->x); fmtputc(&out, ' ');
625
0
          fmtfloat(&out, point->y);
626
0
        }
627
0
        break;
628
629
0
      case 'C': /* unicode char */
630
0
        c = va_arg(args, int);
631
0
        fmtputrune(&out, c);
632
0
        break;
633
452
      case 'c':
634
452
        c = va_arg(args, int);
635
452
        fmtputc(&out, c);
636
452
        break;
637
0
      case 'e':
638
0
        fmtfloat_e(&out, va_arg(args, double), w, p);
639
0
        break;
640
0
      case 'f':
641
0
        fmtfloat_f(&out, va_arg(args, double), w, p);
642
0
        break;
643
3.30k
      case 'g':
644
3.30k
        fmtfloat(&out, va_arg(args, double));
645
3.30k
        break;
646
647
0
      case 'p':
648
0
        bits = 8 * sizeof(void *);
649
0
        z = '0';
650
0
        fmtputc(&out, '0');
651
0
        fmtputc(&out, 'x');
652
0
        q = 0;
653
        /* fallthrough */
654
0
      case 'x':
655
0
        if (bits == 64)
656
0
        {
657
0
          i64 = va_arg(args, int64_t);
658
0
          fmtuint64(&out, i64, 0, z, w, 16, q);
659
0
        }
660
0
        else
661
0
        {
662
0
          i32 = va_arg(args, int);
663
0
          fmtuint32(&out, i32, 0, z, w, 16, q);
664
0
        }
665
0
        break;
666
0
      case 'X':
667
0
        if (bits == 64)
668
0
        {
669
0
          i64 = va_arg(args, int64_t);
670
0
          fmtuint64(&out, i64, 0, z, w, -16, q);
671
0
        }
672
0
        else
673
0
        {
674
0
          i32 = va_arg(args, int);
675
0
          fmtuint32(&out, i32, 0, z, w, -16, q);
676
0
        }
677
0
        break;
678
85.3k
      case 'd':
679
85.3k
      case 'i':
680
85.3k
        if (bits == 64)
681
3
        {
682
3
          i64 = va_arg(args, int64_t);
683
3
          fmtint64(&out, i64, s, z, w, 10, q);
684
3
        }
685
85.3k
        else
686
85.3k
        {
687
85.3k
          i32 = va_arg(args, int);
688
85.3k
          fmtint32(&out, i32, s, z, w, 10, q);
689
85.3k
        }
690
85.3k
        break;
691
0
      case 'u':
692
0
        if (bits == 64)
693
0
        {
694
0
          i64 = va_arg(args, int64_t);
695
0
          fmtuint64(&out, i64, 0, z, w, 10, q);
696
0
        }
697
0
        else
698
0
        {
699
0
          i32 = va_arg(args, int);
700
0
          fmtuint32(&out, i32, 0, z, w, 10, q);
701
0
        }
702
0
        break;
703
704
94.1k
      case 's':
705
94.1k
        if (bits > 0)
706
0
        {
707
0
          wstr = va_arg(args, const wchar_t*);
708
0
          if (!wstr)
709
0
            wstr = L"(null)";
710
0
          if (ps >= 0)
711
0
          {
712
0
            for (i=0; i < ps && ((c = *wstr++) != 0); ++i)
713
0
              fmtputrune(&out, c);
714
0
          }
715
0
          else
716
0
          {
717
0
            while ((c = *wstr++) != 0)
718
0
              fmtputrune(&out, c);
719
0
          }
720
0
        }
721
94.1k
        else
722
94.1k
        {
723
94.1k
          str = va_arg(args, const char*);
724
94.1k
          if (!str)
725
0
            str = "(null)";
726
94.1k
          if (ps >= 0)
727
14
          {
728
468
            for (i=0; i < ps && ((c = *str++) != 0); ++i)
729
454
              fmtputc(&out, c);
730
14
          }
731
94.0k
          else
732
94.0k
          {
733
1.65M
            while ((c = *str++) != 0)
734
1.55M
              fmtputc(&out, c);
735
94.0k
          }
736
94.1k
        }
737
94.1k
        break;
738
0
      case 'Q': /* quoted string (with verbatim unicode) */
739
0
        str = va_arg(args, const char*);
740
0
        if (!str) str = "";
741
0
        fmtquote(&out, str, '"', '"', 1);
742
0
        break;
743
0
      case 'q': /* quoted string */
744
0
        str = va_arg(args, const char*);
745
0
        if (!str) str = "";
746
0
        fmtquote(&out, str, '"', '"', 0);
747
0
        break;
748
0
      case '<': /* quoted string for xml */
749
0
        str = va_arg(args, const char*);
750
0
        if (!str) str = "";
751
0
        fmtquote_xml(&out, str);
752
0
        break;
753
0
      case '>': /* hex string */
754
0
        str = va_arg(args, const char*);
755
0
        if (!str) str = "";
756
0
        fmtquote_hex(&out, str);
757
0
        break;
758
0
      case '(': /* pdf string */
759
0
        str = va_arg(args, const char*);
760
0
        if (!str) str = "";
761
0
        fmtquote_pdf(&out, str, '(', ')');
762
0
        break;
763
0
      case 'n': /* pdf name */
764
0
        str = va_arg(args, const char*);
765
0
        if (!str) str = "";
766
0
        fmtname(&out, str);
767
0
        break;
768
183k
      }
769
183k
    }
770
4.88M
    else
771
4.88M
    {
772
4.88M
      fmtputc(&out, c);
773
4.88M
    }
774
5.06M
  }
775
209k
}
776
777
struct snprintf_buffer
778
{
779
  char *p;
780
  size_t s, n;
781
};
782
783
static void snprintf_emit(fz_context *ctx, void *out_, int c)
784
6.80M
{
785
6.80M
  struct snprintf_buffer *out = out_;
786
6.80M
  if (out->n < out->s)
787
6.80M
    out->p[out->n] = c;
788
6.80M
  ++(out->n);
789
6.80M
}
790
791
size_t
792
fz_vsnprintf(char *buffer, size_t space, const char *fmt, va_list args)
793
199k
{
794
199k
  struct snprintf_buffer out;
795
199k
  out.p = buffer;
796
199k
  out.s = space > 0 ? space - 1 : 0;
797
199k
  out.n = 0;
798
799
  /* Note: using a NULL context is safe here */
800
199k
  fz_format_string(NULL, &out, snprintf_emit, fmt, args);
801
199k
  if (space > 0)
802
199k
    out.p[out.n < space ? out.n : space - 1] = '\0';
803
804
199k
  return out.n;
805
199k
}
806
807
size_t
808
fz_snprintf(char *buffer, size_t space, const char *fmt, ...)
809
8.81k
{
810
8.81k
  va_list ap;
811
8.81k
  struct snprintf_buffer out;
812
8.81k
  out.p = buffer;
813
8.81k
  out.s = space > 0 ? space - 1 : 0;
814
8.81k
  out.n = 0;
815
816
8.81k
  va_start(ap, fmt);
817
  /* Note: using a NULL context is safe here */
818
8.81k
  fz_format_string(NULL, &out, snprintf_emit, fmt, ap);
819
8.81k
  if (space > 0)
820
8.81k
    out.p[out.n < space ? out.n : space - 1] = '\0';
821
8.81k
  va_end(ap);
822
823
8.81k
  return out.n;
824
8.81k
}
825
826
char *
827
fz_asprintf(fz_context *ctx, const char *fmt, ...)
828
0
{
829
0
  size_t len;
830
0
  char *mem;
831
0
  va_list ap;
832
0
  va_start(ap, fmt);
833
0
  len = fz_vsnprintf(NULL, 0, fmt, ap);
834
0
  va_end(ap);
835
0
  mem = Memento_label(fz_malloc(ctx, len+1), "asprintf");
836
0
  va_start(ap, fmt);
837
0
  fz_vsnprintf(mem, len+1, fmt, ap);
838
  va_end(ap);
839
0
  return mem;
840
0
}