Coverage Report

Created: 2026-07-30 07:17

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
8.05M
{
147
8.05M
    std::string s;
148
149
8.05M
    appendfv(s, fmt, argList);
150
151
8.05M
    return s;
152
8.05M
}
153
154
std::string &GooString::appendf(std::string &that, const char *fmt, ...)
155
1.77M
{
156
1.77M
    va_list argList;
157
1.77M
    va_start(argList, fmt);
158
1.77M
    appendfv(that, fmt, argList);
159
1.77M
    va_end(argList);
160
161
1.77M
    return that;
162
1.77M
}
163
164
std::string &GooString::appendfv(std::string &that, const char *fmt, va_list argList)
165
9.83M
{
166
9.83M
    GooStringFormatArg *args;
167
9.83M
    int argsLen, argsSize;
168
9.83M
    GooStringFormatArg arg;
169
9.83M
    int idx, width, prec;
170
9.83M
    bool reverseAlign, zeroFill;
171
9.83M
    GooStringFormatType ft;
172
9.83M
    char buf[65];
173
9.83M
    int len, i;
174
9.83M
    const char *p0, *p1;
175
9.83M
    const char *str;
176
9.83M
    GooStringFormatArg argsBuf[8];
177
178
9.83M
    argsLen = 0;
179
9.83M
    argsSize = sizeof(argsBuf) / sizeof(argsBuf[0]);
180
9.83M
    args = argsBuf;
181
182
9.83M
    p0 = fmt;
183
34.5M
    while (*p0) {
184
24.7M
        if (*p0 == '{') {
185
7.46M
            ++p0;
186
7.46M
            if (*p0 == '{') {
187
0
                ++p0;
188
0
                that.push_back('{');
189
7.46M
            } else {
190
191
                // parse the format string
192
7.46M
                if (*p0 < '0' || *p0 > '9') {
193
0
                    break;
194
0
                }
195
7.46M
                idx = *p0 - '0';
196
7.46M
                for (++p0; *p0 >= '0' && *p0 <= '9'; ++p0) {
197
0
                    idx = 10 * idx + (*p0 - '0');
198
0
                }
199
7.46M
                if (*p0 != ':') {
200
0
                    break;
201
0
                }
202
7.46M
                ++p0;
203
7.46M
                if (*p0 == '-') {
204
0
                    reverseAlign = true;
205
0
                    ++p0;
206
7.46M
                } else {
207
7.46M
                    reverseAlign = false;
208
7.46M
                }
209
7.46M
                width = 0;
210
7.46M
                zeroFill = *p0 == '0';
211
21.6M
                for (; *p0 >= '0' && *p0 <= '9'; ++p0) {
212
14.1M
                    width = 10 * width + (*p0 - '0');
213
14.1M
                }
214
7.46M
                if (width < 0) {
215
0
                    width = 0;
216
0
                }
217
7.46M
                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
7.46M
                } else {
224
7.46M
                    prec = 0;
225
7.46M
                }
226
25.7M
                for (ft = static_cast<GooStringFormatType>(0); formatStrings[ft]; ft = static_cast<GooStringFormatType>(ft + 1)) {
227
25.7M
                    if (!strncmp(p0, formatStrings[ft], strlen(formatStrings[ft]))) {
228
7.46M
                        break;
229
7.46M
                    }
230
25.7M
                }
231
7.46M
                if (!formatStrings[ft]) {
232
0
                    break;
233
0
                }
234
7.46M
                p0 += strlen(formatStrings[ft]);
235
7.46M
                if (*p0 != '}') {
236
0
                    break;
237
0
                }
238
7.46M
                ++p0;
239
240
                // fetch the argument
241
7.46M
                if (idx > argsLen) {
242
0
                    break;
243
0
                }
244
7.46M
                if (idx == argsLen) {
245
7.46M
                    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
7.46M
                    switch (ft) {
255
48.4k
                    case fmtIntDecimal:
256
7.13M
                    case fmtIntHex:
257
7.13M
                    case fmtIntHexUpper:
258
7.13M
                    case fmtIntOctal:
259
7.13M
                    case fmtIntBinary:
260
7.13M
                    case fmtSpace:
261
7.13M
                        args[argsLen].i = va_arg(argList, int);
262
7.13M
                        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
119
                    case fmtULongDecimal:
278
119
                    case fmtULongHex:
279
119
                    case fmtULongHexUpper:
280
119
                    case fmtULongOctal:
281
119
                    case fmtULongBinary:
282
119
                        args[argsLen].ul = va_arg(argList, unsigned long);
283
119
                        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
50.0k
                    case fmtChar:
304
50.0k
                        args[argsLen].c = static_cast<char>(va_arg(argList, int));
305
50.0k
                        break;
306
257k
                    case fmtString:
307
257k
                        args[argsLen].s = va_arg(argList, char *);
308
257k
                        break;
309
0
                    case fmtGooString:
310
0
                        args[argsLen].gs = va_arg(argList, GooString *);
311
0
                        break;
312
22.0k
                    case fmtStdString:
313
22.0k
                        args[argsLen].r = va_arg(argList, std::string *);
314
22.0k
                        break;
315
0
                    case fmtInvalidFormat:
316
0
                        assert(false);
317
7.46M
                    }
318
7.46M
                    ++argsLen;
319
7.46M
                }
320
321
                // format the argument
322
7.46M
                arg = args[idx];
323
7.46M
                switch (ft) {
324
48.4k
                case fmtIntDecimal:
325
48.4k
                    formatInt(arg.i, buf, sizeof(buf), zeroFill, width, 10, &str, &len);
326
48.4k
                    break;
327
7.08M
                case fmtIntHex:
328
7.08M
                    formatInt(arg.i, buf, sizeof(buf), zeroFill, width, 16, &str, &len);
329
7.08M
                    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
119
                case fmtULongDecimal:
370
119
                    formatUInt(arg.ul, buf, sizeof(buf), zeroFill, width, 10, &str, &len);
371
119
                    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
50.0k
                case fmtChar:
424
50.0k
                    buf[0] = arg.c;
425
50.0k
                    str = buf;
426
50.0k
                    len = 1;
427
50.0k
                    reverseAlign = !reverseAlign;
428
50.0k
                    break;
429
257k
                case fmtString: {
430
257k
                    str = arg.s;
431
257k
                    const size_t strlen_str = strlen(str);
432
257k
                    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
257k
                    } else {
436
257k
                        len = static_cast<int>(strlen_str);
437
257k
                    }
438
257k
                    reverseAlign = !reverseAlign;
439
257k
                    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
22.0k
                case fmtStdString:
452
22.0k
                    if (arg.r) {
453
22.0k
                        str = arg.r->c_str();
454
22.0k
                        len = arg.r->size();
455
22.0k
                    } else {
456
0
                        str = "(null)";
457
0
                        len = 6;
458
0
                    }
459
22.0k
                    reverseAlign = !reverseAlign;
460
22.0k
                    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
7.46M
                }
469
470
                // append the formatted arg, handling width and alignment
471
7.46M
                if (!reverseAlign && len < width) {
472
0
                    for (i = len; i < width; ++i) {
473
0
                        that.push_back(' ');
474
0
                    }
475
0
                }
476
7.46M
                that.append(str, len);
477
7.46M
                if (reverseAlign && len < width) {
478
0
                    for (i = len; i < width; ++i) {
479
0
                        that.push_back(' ');
480
0
                    }
481
0
                }
482
7.46M
            }
483
484
17.2M
        } else if (*p0 == '}') {
485
0
            ++p0;
486
0
            if (*p0 == '}') {
487
0
                ++p0;
488
0
            }
489
0
            that.push_back('}');
490
491
17.2M
        } else {
492
275M
            for (p1 = p0 + 1; *p1 && *p1 != '{' && *p1 != '}'; ++p1) {
493
258M
                ;
494
258M
            }
495
17.2M
            that.append(p0, p1 - p0);
496
17.2M
            p0 = p1;
497
17.2M
        }
498
24.7M
    }
499
500
9.83M
    if (args != argsBuf) {
501
0
        gfree(args);
502
0
    }
503
504
9.83M
    return that;
505
9.83M
}
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
7.13M
{
514
7.13M
    const char *vals = upperCase ? upperCaseDigits : lowerCaseDigits;
515
7.13M
    bool neg;
516
7.13M
    int start, i, j;
517
7.13M
    unsigned long long abs_x;
518
519
7.13M
    i = bufSize;
520
7.13M
    if ((neg = x < 0)) {
521
917
        abs_x = -x;
522
7.13M
    } else {
523
7.13M
        abs_x = x;
524
7.13M
    }
525
7.13M
    start = neg ? 1 : 0;
526
7.13M
    if (abs_x == 0) {
527
30.7k
        buf[--i] = '0';
528
7.10M
    } else {
529
21.1M
        while (i > start && abs_x) {
530
13.9M
            buf[--i] = vals[abs_x % base];
531
13.9M
            abs_x /= base;
532
13.9M
        }
533
7.10M
    }
534
7.13M
    if (zeroFill) {
535
7.28M
        for (j = bufSize - i; i > start && j < width - start; ++j) {
536
199k
            buf[--i] = '0';
537
199k
        }
538
7.08M
    }
539
7.13M
    if (neg) {
540
917
        buf[--i] = '-';
541
917
    }
542
7.13M
    *p = buf + i;
543
7.13M
    *len = bufSize - i;
544
7.13M
}
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
119
{
548
119
    const char *vals = upperCase ? upperCaseDigits : lowerCaseDigits;
549
119
    int i, j;
550
551
119
    i = bufSize;
552
119
    if (x == 0) {
553
0
        buf[--i] = '0';
554
119
    } else {
555
238
        while (i > 0 && x) {
556
119
            buf[--i] = vals[x % base];
557
119
            x /= base;
558
119
        }
559
119
    }
560
119
    if (zeroFill) {
561
0
        for (j = bufSize - i; i > 0 && j < width; ++j) {
562
0
            buf[--i] = '0';
563
0
        }
564
0
    }
565
119
    *p = buf + i;
566
119
    *len = bufSize - i;
567
119
}
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
}