Coverage Report

Created: 2026-08-11 07:29

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/poppler/goo/GooString.cc
Line
Count
Source
1
//========================================================================
2
//
3
// GooString.cc
4
//
5
// Simple variable-length string type.
6
//
7
// Copyright 1996-2003 Glyph & Cog, LLC
8
//
9
//========================================================================
10
11
//========================================================================
12
//
13
// Modified under the Poppler project - http://poppler.freedesktop.org
14
//
15
// All changes made under the Poppler project to this file are licensed
16
// under GPL version 2 or later
17
//
18
// Copyright (C) 2006 Kristian Høgsberg <krh@redhat.com>
19
// Copyright (C) 2006 Krzysztof Kowalczyk <kkowalczyk@gmail.com>
20
// Copyright (C) 2007 Jeff Muizelaar <jeff@infidigm.net>
21
// Copyright (C) 2008-2011, 2016-2018, 2022, 2025 Albert Astals Cid <aacid@kde.org>
22
// Copyright (C) 2011 Kenji Uno <ku@digitaldolphins.jp>
23
// Copyright (C) 2012, 2013 Fabio D'Urso <fabiodurso@hotmail.it>
24
// Copyright (C) 2012, 2017 Adrian Johnson <ajohnson@redneon.com>
25
// Copyright (C) 2012 Pino Toscano <pino@kde.org>
26
// Copyright (C) 2013 Jason Crain <jason@aquaticape.us>
27
// Copyright (C) 2015 William Bader <williambader@hotmail.com>
28
// Copyright (C) 2016 Jakub Alba <jakubalba@gmail.com>
29
// Copyright (C) 2018 Klarälvdalens Datakonsult AB, a KDAB Group company, <info@kdab.com>. Work sponsored by the LiMux project of the city of Munich
30
// Copyright (C) 2018 Adam Reichold <adam.reichold@t-online.de>
31
// Copyright (C) 2018 Greg Knight <lyngvi@gmail.com>
32
// Copyright (C) 2019, 2022-2024 Oliver Sander <oliver.sander@tu-dresden.de>
33
// Copyright (C) 2023 Even Rouault <even.rouault@mines-paris.org>
34
// Copyright (C) 2025, 2026 g10 Code GmbH, Author: Sune Stolborg Vuorela <sune@vuorela.dk>
35
// Copyright (C) 2025 Jonathan Hähne <jonathan.haehne@hotmail.com>
36
//
37
// To see a description of the changes please see the Changelog file that
38
// came with your tarball or type make ChangeLog if you are building from git
39
//
40
//========================================================================
41
42
#include <config.h>
43
44
#include <cassert>
45
#include <cctype>
46
#include <cmath>
47
#include <cstddef>
48
#include <cstdlib>
49
#include <cstring>
50
#include <limits>
51
52
#include "gmem.h"
53
#include "Error.h"
54
#include "GooString.h"
55
56
//------------------------------------------------------------------------
57
58
namespace {
59
60
union GooStringFormatArg {
61
    int i;
62
    unsigned int ui;
63
    long l;
64
    unsigned long ul;
65
    long long ll;
66
    unsigned long long ull;
67
    double f;
68
    char c;
69
    char *s;
70
    GooString *gs;
71
    std::string *r;
72
};
73
74
enum GooStringFormatType
75
{
76
    fmtIntDecimal,
77
    fmtIntHex,
78
    fmtIntHexUpper,
79
    fmtIntOctal,
80
    fmtIntBinary,
81
    fmtUIntDecimal,
82
    fmtUIntHex,
83
    fmtUIntHexUpper,
84
    fmtUIntOctal,
85
    fmtUIntBinary,
86
    fmtLongDecimal,
87
    fmtLongHex,
88
    fmtLongHexUpper,
89
    fmtLongOctal,
90
    fmtLongBinary,
91
    fmtULongDecimal,
92
    fmtULongHex,
93
    fmtULongHexUpper,
94
    fmtULongOctal,
95
    fmtULongBinary,
96
    fmtLongLongDecimal,
97
    fmtLongLongHex,
98
    fmtLongLongHexUpper,
99
    fmtLongLongOctal,
100
    fmtLongLongBinary,
101
    fmtULongLongDecimal,
102
    fmtULongLongHex,
103
    fmtULongLongHexUpper,
104
    fmtULongLongOctal,
105
    fmtULongLongBinary,
106
    fmtDouble,
107
    fmtDoubleTrimSmallAware,
108
    fmtDoubleTrim,
109
    fmtChar,
110
    fmtString,
111
    fmtGooString,
112
    fmtStdString,
113
    fmtSpace,
114
    fmtInvalidFormat
115
};
116
117
const char *const formatStrings[] = { "d",   "x",   "X",   "o",   "b",   "ud",   "ux",   "uX",   "uo",   "ub",   "ld", "lx", "lX", "lo", "lb", "uld", "ulx", "ulX", "ulo",  "ulb",
118
                                      "lld", "llx", "llX", "llo", "llb", "ulld", "ullx", "ullX", "ullo", "ullb", "f",  "gs", "g",  "c",  "s",  "t",   "r",   "w",   nullptr };
119
static_assert((fmtInvalidFormat + 1) == (sizeof(formatStrings) / sizeof(char *)));
120
121
void formatInt(long long x, char *buf, int bufSize, bool zeroFill, int width, int base, const char **p, int *len, bool upperCase = false);
122
123
void formatUInt(unsigned long long x, char *buf, int bufSize, bool zeroFill, int width, int base, const char **p, int *len, bool upperCase = false);
124
125
void formatDouble(double x, char *buf, int bufSize, int prec, bool trim, const char **p, int *len);
126
127
void formatDoubleSmallAware(double x, char *buf, int bufSize, int prec, bool trim, const char **p, int *len);
128
129
}
130
131
//------------------------------------------------------------------------
132
133
std::string GooString::format(const char *fmt, ...)
134
0
{
135
0
    std::string s;
136
137
0
    va_list argList;
138
0
    va_start(argList, fmt);
139
0
    appendfv(s, fmt, argList);
140
0
    va_end(argList);
141
142
0
    return s;
143
0
}
144
145
std::string GooString::formatv(const char *fmt, va_list argList)
146
13.5M
{
147
13.5M
    std::string s;
148
149
13.5M
    appendfv(s, fmt, argList);
150
151
13.5M
    return s;
152
13.5M
}
153
154
std::string &GooString::appendf(std::string &that, const char *fmt, ...)
155
2.01M
{
156
2.01M
    va_list argList;
157
2.01M
    va_start(argList, fmt);
158
2.01M
    appendfv(that, fmt, argList);
159
2.01M
    va_end(argList);
160
161
2.01M
    return that;
162
2.01M
}
163
164
std::string &GooString::appendfv(std::string &that, const char *fmt, va_list argList)
165
15.5M
{
166
15.5M
    GooStringFormatArg *args;
167
15.5M
    int argsLen, argsSize;
168
15.5M
    GooStringFormatArg arg;
169
15.5M
    int idx, width, prec;
170
15.5M
    bool reverseAlign, zeroFill;
171
15.5M
    GooStringFormatType ft;
172
15.5M
    char buf[65];
173
15.5M
    int len, i;
174
15.5M
    const char *p0, *p1;
175
15.5M
    const char *str;
176
15.5M
    GooStringFormatArg argsBuf[8];
177
178
15.5M
    argsLen = 0;
179
15.5M
    argsSize = sizeof(argsBuf) / sizeof(argsBuf[0]);
180
15.5M
    args = argsBuf;
181
182
15.5M
    p0 = fmt;
183
53.8M
    while (*p0) {
184
38.3M
        if (*p0 == '{') {
185
11.4M
            ++p0;
186
11.4M
            if (*p0 == '{') {
187
0
                ++p0;
188
0
                that.push_back('{');
189
11.4M
            } else {
190
191
                // parse the format string
192
11.4M
                if (*p0 < '0' || *p0 > '9') {
193
0
                    break;
194
0
                }
195
11.4M
                idx = *p0 - '0';
196
11.4M
                for (++p0; *p0 >= '0' && *p0 <= '9'; ++p0) {
197
0
                    idx = 10 * idx + (*p0 - '0');
198
0
                }
199
11.4M
                if (*p0 != ':') {
200
0
                    break;
201
0
                }
202
11.4M
                ++p0;
203
11.4M
                if (*p0 == '-') {
204
0
                    reverseAlign = true;
205
0
                    ++p0;
206
11.4M
                } else {
207
11.4M
                    reverseAlign = false;
208
11.4M
                }
209
11.4M
                width = 0;
210
11.4M
                zeroFill = *p0 == '0';
211
33.1M
                for (; *p0 >= '0' && *p0 <= '9'; ++p0) {
212
21.7M
                    width = 10 * width + (*p0 - '0');
213
21.7M
                }
214
11.4M
                if (width < 0) {
215
0
                    width = 0;
216
0
                }
217
11.4M
                if (*p0 == '.') {
218
0
                    ++p0;
219
0
                    prec = 0;
220
0
                    for (; *p0 >= '0' && *p0 <= '9'; ++p0) {
221
0
                        prec = 10 * prec + (*p0 - '0');
222
0
                    }
223
11.4M
                } else {
224
11.4M
                    prec = 0;
225
11.4M
                }
226
38.8M
                for (ft = static_cast<GooStringFormatType>(0); formatStrings[ft]; ft = static_cast<GooStringFormatType>(ft + 1)) {
227
38.8M
                    if (!strncmp(p0, formatStrings[ft], strlen(formatStrings[ft]))) {
228
11.4M
                        break;
229
11.4M
                    }
230
38.8M
                }
231
11.4M
                if (!formatStrings[ft]) {
232
0
                    break;
233
0
                }
234
11.4M
                p0 += strlen(formatStrings[ft]);
235
11.4M
                if (*p0 != '}') {
236
0
                    break;
237
0
                }
238
11.4M
                ++p0;
239
240
                // fetch the argument
241
11.4M
                if (idx > argsLen) {
242
0
                    break;
243
0
                }
244
11.4M
                if (idx == argsLen) {
245
11.4M
                    if (argsLen == argsSize) {
246
0
                        argsSize *= 2;
247
0
                        if (args == argsBuf) {
248
0
                            args = static_cast<GooStringFormatArg *>(gmallocn(argsSize, sizeof(GooStringFormatArg)));
249
0
                            memcpy(args, argsBuf, argsLen * sizeof(GooStringFormatArg));
250
0
                        } else {
251
0
                            args = static_cast<GooStringFormatArg *>(greallocn(args, argsSize, sizeof(GooStringFormatArg)));
252
0
                        }
253
0
                    }
254
11.4M
                    switch (ft) {
255
60.2k
                    case fmtIntDecimal:
256
10.9M
                    case fmtIntHex:
257
10.9M
                    case fmtIntHexUpper:
258
10.9M
                    case fmtIntOctal:
259
10.9M
                    case fmtIntBinary:
260
10.9M
                    case fmtSpace:
261
10.9M
                        args[argsLen].i = va_arg(argList, int);
262
10.9M
                        break;
263
0
                    case fmtUIntDecimal:
264
0
                    case fmtUIntHex:
265
0
                    case fmtUIntHexUpper:
266
0
                    case fmtUIntOctal:
267
0
                    case fmtUIntBinary:
268
0
                        args[argsLen].ui = va_arg(argList, unsigned int);
269
0
                        break;
270
0
                    case fmtLongDecimal:
271
0
                    case fmtLongHex:
272
0
                    case fmtLongHexUpper:
273
0
                    case fmtLongOctal:
274
0
                    case fmtLongBinary:
275
0
                        args[argsLen].l = va_arg(argList, long);
276
0
                        break;
277
145
                    case fmtULongDecimal:
278
145
                    case fmtULongHex:
279
145
                    case fmtULongHexUpper:
280
145
                    case fmtULongOctal:
281
145
                    case fmtULongBinary:
282
145
                        args[argsLen].ul = va_arg(argList, unsigned long);
283
145
                        break;
284
0
                    case fmtLongLongDecimal:
285
0
                    case fmtLongLongHex:
286
0
                    case fmtLongLongHexUpper:
287
0
                    case fmtLongLongOctal:
288
0
                    case fmtLongLongBinary:
289
0
                        args[argsLen].ll = va_arg(argList, long long);
290
0
                        break;
291
0
                    case fmtULongLongDecimal:
292
0
                    case fmtULongLongHex:
293
0
                    case fmtULongLongHexUpper:
294
0
                    case fmtULongLongOctal:
295
0
                    case fmtULongLongBinary:
296
0
                        args[argsLen].ull = va_arg(argList, unsigned long long);
297
0
                        break;
298
0
                    case fmtDouble:
299
0
                    case fmtDoubleTrim:
300
0
                    case fmtDoubleTrimSmallAware:
301
0
                        args[argsLen].f = va_arg(argList, double);
302
0
                        break;
303
87.6k
                    case fmtChar:
304
87.6k
                        args[argsLen].c = static_cast<char>(va_arg(argList, int));
305
87.6k
                        break;
306
374k
                    case fmtString:
307
374k
                        args[argsLen].s = va_arg(argList, char *);
308
374k
                        break;
309
0
                    case fmtGooString:
310
0
                        args[argsLen].gs = va_arg(argList, GooString *);
311
0
                        break;
312
26.7k
                    case fmtStdString:
313
26.7k
                        args[argsLen].r = va_arg(argList, std::string *);
314
26.7k
                        break;
315
0
                    case fmtInvalidFormat:
316
0
                        assert(false);
317
11.4M
                    }
318
11.4M
                    ++argsLen;
319
11.4M
                }
320
321
                // format the argument
322
11.4M
                arg = args[idx];
323
11.4M
                switch (ft) {
324
60.2k
                case fmtIntDecimal:
325
60.2k
                    formatInt(arg.i, buf, sizeof(buf), zeroFill, width, 10, &str, &len);
326
60.2k
                    break;
327
10.8M
                case fmtIntHex:
328
10.8M
                    formatInt(arg.i, buf, sizeof(buf), zeroFill, width, 16, &str, &len);
329
10.8M
                    break;
330
0
                case fmtIntHexUpper:
331
0
                    formatInt(arg.i, buf, sizeof(buf), zeroFill, width, 16, &str, &len, true);
332
0
                    break;
333
0
                case fmtIntOctal:
334
0
                    formatInt(arg.i, buf, sizeof(buf), zeroFill, width, 8, &str, &len);
335
0
                    break;
336
0
                case fmtIntBinary:
337
0
                    formatInt(arg.i, buf, sizeof(buf), zeroFill, width, 2, &str, &len);
338
0
                    break;
339
0
                case fmtUIntDecimal:
340
0
                    formatUInt(arg.ui, buf, sizeof(buf), zeroFill, width, 10, &str, &len);
341
0
                    break;
342
0
                case fmtUIntHex:
343
0
                    formatUInt(arg.ui, buf, sizeof(buf), zeroFill, width, 16, &str, &len);
344
0
                    break;
345
0
                case fmtUIntHexUpper:
346
0
                    formatUInt(arg.ui, buf, sizeof(buf), zeroFill, width, 16, &str, &len, true);
347
0
                    break;
348
0
                case fmtUIntOctal:
349
0
                    formatUInt(arg.ui, buf, sizeof(buf), zeroFill, width, 8, &str, &len);
350
0
                    break;
351
0
                case fmtUIntBinary:
352
0
                    formatUInt(arg.ui, buf, sizeof(buf), zeroFill, width, 2, &str, &len);
353
0
                    break;
354
0
                case fmtLongDecimal:
355
0
                    formatInt(arg.l, buf, sizeof(buf), zeroFill, width, 10, &str, &len);
356
0
                    break;
357
0
                case fmtLongHex:
358
0
                    formatInt(arg.l, buf, sizeof(buf), zeroFill, width, 16, &str, &len);
359
0
                    break;
360
0
                case fmtLongHexUpper:
361
0
                    formatInt(arg.l, buf, sizeof(buf), zeroFill, width, 16, &str, &len, true);
362
0
                    break;
363
0
                case fmtLongOctal:
364
0
                    formatInt(arg.l, buf, sizeof(buf), zeroFill, width, 8, &str, &len);
365
0
                    break;
366
0
                case fmtLongBinary:
367
0
                    formatInt(arg.l, buf, sizeof(buf), zeroFill, width, 2, &str, &len);
368
0
                    break;
369
145
                case fmtULongDecimal:
370
145
                    formatUInt(arg.ul, buf, sizeof(buf), zeroFill, width, 10, &str, &len);
371
145
                    break;
372
0
                case fmtULongHex:
373
0
                    formatUInt(arg.ul, buf, sizeof(buf), zeroFill, width, 16, &str, &len);
374
0
                    break;
375
0
                case fmtULongHexUpper:
376
0
                    formatUInt(arg.ul, buf, sizeof(buf), zeroFill, width, 16, &str, &len, true);
377
0
                    break;
378
0
                case fmtULongOctal:
379
0
                    formatUInt(arg.ul, buf, sizeof(buf), zeroFill, width, 8, &str, &len);
380
0
                    break;
381
0
                case fmtULongBinary:
382
0
                    formatUInt(arg.ul, buf, sizeof(buf), zeroFill, width, 2, &str, &len);
383
0
                    break;
384
0
                case fmtLongLongDecimal:
385
0
                    formatInt(arg.ll, buf, sizeof(buf), zeroFill, width, 10, &str, &len);
386
0
                    break;
387
0
                case fmtLongLongHex:
388
0
                    formatInt(arg.ll, buf, sizeof(buf), zeroFill, width, 16, &str, &len);
389
0
                    break;
390
0
                case fmtLongLongHexUpper:
391
0
                    formatInt(arg.ll, buf, sizeof(buf), zeroFill, width, 16, &str, &len, true);
392
0
                    break;
393
0
                case fmtLongLongOctal:
394
0
                    formatInt(arg.ll, buf, sizeof(buf), zeroFill, width, 8, &str, &len);
395
0
                    break;
396
0
                case fmtLongLongBinary:
397
0
                    formatInt(arg.ll, buf, sizeof(buf), zeroFill, width, 2, &str, &len);
398
0
                    break;
399
0
                case fmtULongLongDecimal:
400
0
                    formatUInt(arg.ull, buf, sizeof(buf), zeroFill, width, 10, &str, &len);
401
0
                    break;
402
0
                case fmtULongLongHex:
403
0
                    formatUInt(arg.ull, buf, sizeof(buf), zeroFill, width, 16, &str, &len);
404
0
                    break;
405
0
                case fmtULongLongHexUpper:
406
0
                    formatUInt(arg.ull, buf, sizeof(buf), zeroFill, width, 16, &str, &len, true);
407
0
                    break;
408
0
                case fmtULongLongOctal:
409
0
                    formatUInt(arg.ull, buf, sizeof(buf), zeroFill, width, 8, &str, &len);
410
0
                    break;
411
0
                case fmtULongLongBinary:
412
0
                    formatUInt(arg.ull, buf, sizeof(buf), zeroFill, width, 2, &str, &len);
413
0
                    break;
414
0
                case fmtDouble:
415
0
                    formatDouble(arg.f, buf, sizeof(buf), prec, false, &str, &len);
416
0
                    break;
417
0
                case fmtDoubleTrim:
418
0
                    formatDouble(arg.f, buf, sizeof(buf), prec, true, &str, &len);
419
0
                    break;
420
0
                case fmtDoubleTrimSmallAware:
421
0
                    formatDoubleSmallAware(arg.f, buf, sizeof(buf), prec, true, &str, &len);
422
0
                    break;
423
87.6k
                case fmtChar:
424
87.6k
                    buf[0] = arg.c;
425
87.6k
                    str = buf;
426
87.6k
                    len = 1;
427
87.6k
                    reverseAlign = !reverseAlign;
428
87.6k
                    break;
429
374k
                case fmtString: {
430
374k
                    str = arg.s;
431
374k
                    const size_t strlen_str = strlen(str);
432
374k
                    if (strlen_str > static_cast<size_t>(std::numeric_limits<int>::max())) {
433
0
                        error(errSyntaxWarning, 0, "String truncated to INT_MAX bytes");
434
0
                        len = std::numeric_limits<int>::max();
435
374k
                    } else {
436
374k
                        len = static_cast<int>(strlen_str);
437
374k
                    }
438
374k
                    reverseAlign = !reverseAlign;
439
374k
                    break;
440
0
                }
441
0
                case fmtGooString:
442
0
                    if (arg.gs) {
443
0
                        str = arg.gs->c_str();
444
0
                        len = arg.gs->size();
445
0
                    } else {
446
0
                        str = "(null)";
447
0
                        len = 6;
448
0
                    }
449
0
                    reverseAlign = !reverseAlign;
450
0
                    break;
451
26.7k
                case fmtStdString:
452
26.7k
                    if (arg.r) {
453
26.7k
                        str = arg.r->c_str();
454
26.7k
                        len = arg.r->size();
455
26.7k
                    } else {
456
0
                        str = "(null)";
457
0
                        len = 6;
458
0
                    }
459
26.7k
                    reverseAlign = !reverseAlign;
460
26.7k
                    break;
461
0
                case fmtSpace:
462
0
                    str = buf;
463
0
                    len = 0;
464
0
                    width = arg.i;
465
0
                    break;
466
0
                case fmtInvalidFormat:
467
0
                    assert(false);
468
11.4M
                }
469
470
                // append the formatted arg, handling width and alignment
471
11.4M
                if (!reverseAlign && len < width) {
472
0
                    for (i = len; i < width; ++i) {
473
0
                        that.push_back(' ');
474
0
                    }
475
0
                }
476
11.4M
                that.append(str, len);
477
11.4M
                if (reverseAlign && len < width) {
478
0
                    for (i = len; i < width; ++i) {
479
0
                        that.push_back(' ');
480
0
                    }
481
0
                }
482
11.4M
            }
483
484
26.9M
        } else if (*p0 == '}') {
485
0
            ++p0;
486
0
            if (*p0 == '}') {
487
0
                ++p0;
488
0
            }
489
0
            that.push_back('}');
490
491
26.9M
        } else {
492
461M
            for (p1 = p0 + 1; *p1 && *p1 != '{' && *p1 != '}'; ++p1) {
493
434M
                ;
494
434M
            }
495
26.9M
            that.append(p0, p1 - p0);
496
26.9M
            p0 = p1;
497
26.9M
        }
498
38.3M
    }
499
500
15.5M
    if (args != argsBuf) {
501
0
        gfree(args);
502
0
    }
503
504
15.5M
    return that;
505
15.5M
}
506
507
namespace {
508
509
const char lowerCaseDigits[17] = "0123456789abcdef";
510
const char upperCaseDigits[17] = "0123456789ABCDEF";
511
512
void formatInt(long long x, char *buf, int bufSize, bool zeroFill, int width, int base, const char **p, int *len, bool upperCase)
513
10.9M
{
514
10.9M
    const char *vals = upperCase ? upperCaseDigits : lowerCaseDigits;
515
10.9M
    bool neg;
516
10.9M
    int start, i, j;
517
10.9M
    unsigned long long abs_x;
518
519
10.9M
    i = bufSize;
520
10.9M
    if ((neg = x < 0)) {
521
1.07k
        abs_x = -x;
522
10.9M
    } else {
523
10.9M
        abs_x = x;
524
10.9M
    }
525
10.9M
    start = neg ? 1 : 0;
526
10.9M
    if (abs_x == 0) {
527
36.4k
        buf[--i] = '0';
528
10.8M
    } else {
529
32.1M
        while (i > start && abs_x) {
530
21.2M
            buf[--i] = vals[abs_x % base];
531
21.2M
            abs_x /= base;
532
21.2M
        }
533
10.8M
    }
534
10.9M
    if (zeroFill) {
535
11.3M
        for (j = bufSize - i; i > start && j < width - start; ++j) {
536
483k
            buf[--i] = '0';
537
483k
        }
538
10.8M
    }
539
10.9M
    if (neg) {
540
1.07k
        buf[--i] = '-';
541
1.07k
    }
542
10.9M
    *p = buf + i;
543
10.9M
    *len = bufSize - i;
544
10.9M
}
545
546
void formatUInt(unsigned long long x, char *buf, int bufSize, bool zeroFill, int width, int base, const char **p, int *len, bool upperCase)
547
145
{
548
145
    const char *vals = upperCase ? upperCaseDigits : lowerCaseDigits;
549
145
    int i, j;
550
551
145
    i = bufSize;
552
145
    if (x == 0) {
553
0
        buf[--i] = '0';
554
145
    } else {
555
290
        while (i > 0 && x) {
556
145
            buf[--i] = vals[x % base];
557
145
            x /= base;
558
145
        }
559
145
    }
560
145
    if (zeroFill) {
561
0
        for (j = bufSize - i; i > 0 && j < width; ++j) {
562
0
            buf[--i] = '0';
563
0
        }
564
0
    }
565
145
    *p = buf + i;
566
145
    *len = bufSize - i;
567
145
}
568
569
void formatDouble(double x, char *buf, int bufSize, int prec, bool trim, const char **p, int *len)
570
0
{
571
0
    bool neg, started;
572
0
    double x2;
573
0
    int d, i, j;
574
575
0
    if ((neg = x < 0)) {
576
0
        x = -x;
577
0
    }
578
0
    x = floor(x * pow(10.0, prec) + 0.5);
579
0
    i = bufSize;
580
0
    started = !trim;
581
0
    for (j = 0; j < prec && i > 1; ++j) {
582
0
        x2 = floor(0.1 * (x + 0.5));
583
0
        d = static_cast<int>(floor(x - 10 * x2 + 0.5));
584
0
        if (started || d != 0) {
585
0
            buf[--i] = '0' + d;
586
0
            started = true;
587
0
        }
588
0
        x = x2;
589
0
    }
590
0
    if (i > 1 && started) {
591
0
        buf[--i] = '.';
592
0
    }
593
0
    if (i > 1) {
594
0
        do {
595
0
            x2 = floor(0.1 * (x + 0.5));
596
0
            d = static_cast<int>(floor(x - 10 * x2 + 0.5));
597
0
            buf[--i] = '0' + d;
598
0
            x = x2;
599
0
        } while (i > 1 && x);
600
0
    }
601
0
    if (neg) {
602
0
        buf[--i] = '-';
603
0
    }
604
0
    *p = buf + i;
605
0
    *len = bufSize - i;
606
0
}
607
608
void formatDoubleSmallAware(double x, char *buf, int bufSize, int prec, bool trim, const char **p, int *len)
609
0
{
610
0
    double absX = fabs(x);
611
0
    if (absX >= 0.1) {
612
0
        formatDouble(x, buf, bufSize, prec, trim, p, len);
613
0
    } else {
614
0
        while (absX < 0.1 && prec < 16) {
615
0
            absX = absX * 10;
616
0
            prec++;
617
0
        }
618
0
        formatDouble(x, buf, bufSize, prec, trim, p, len);
619
0
    }
620
0
}
621
622
}
623
624
void GooString::lowerCase(std::string &s)
625
0
{
626
0
    for (auto &c : s) {
627
0
        if (std::isupper(c)) {
628
0
            c = std::tolower(c);
629
0
        }
630
0
    }
631
0
}
632
633
std::string GooString::toLowerCase(std::string_view s)
634
0
{
635
0
    std::string newString(s);
636
0
    lowerCase(newString);
637
0
    return newString;
638
0
}