1
//========================================================================
5
// Simple variable-length string type.
7
// Copyright 1996-2003 Glyph & Cog, LLC
9
//========================================================================
11
//========================================================================
13
// Modified under the Poppler project - http://poppler.freedesktop.org
15
// All changes made under the Poppler project to this file are licensed
16
// under GPL version 2 or later
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 Albert Astals Cid <aacid@kde.org>
23
// To see a description of the changes please see the Changelog file that
24
// came with your tarball or type make ChangeLog if you are building from git
26
//========================================================================
30
#ifdef USE_GCC_PRAGMAS
31
#pragma implementation
41
#include "GooString.h"
43
static const int MAXIMUM_DOUBLE_PREC = 16;
45
//------------------------------------------------------------------------
47
union GooStringFormatArg {
58
enum GooStringFormatType {
76
fmtDoubleTrimSmallAware,
84
static char *formatStrings[] = {
85
"d", "x", "o", "b", "ud", "ux", "uo", "ub",
86
"ld", "lx", "lo", "lb", "uld", "ulx", "ulo", "ulb",
95
//------------------------------------------------------------------------
97
int inline GooString::roundedSize(int len) {
99
if (len <= STR_STATIC_SIZE-1)
100
return STR_STATIC_SIZE;
101
delta = len < 256 ? 7 : 255;
102
return ((len + 1) + delta) & ~delta;
105
// Make sure that the buffer is big enough to contain <newLength> characters
106
// plus terminating 0.
107
// We assume that if this is being called from the constructor, <s> was set
108
// to NULL and <length> was set to 0 to indicate unused string before calling us.
109
void inline GooString::resize(int newLength) {
112
if (!s || (roundedSize(length) != roundedSize(newLength))) {
113
// requires re-allocating data for string
114
if (newLength < STR_STATIC_SIZE) {
117
// allocate a rounded amount
119
s1 = (char*)gmalloc(roundedSize(newLength));
121
s1 = (char*)grealloc(s, roundedSize(newLength));
123
if (s == sStatic || s1 == sStatic) {
124
// copy the minimum, we only need to if are moving to or
126
// assert(s != s1) the roundedSize condition ensures this
127
if (newLength < length) {
128
memcpy(s1, s, newLength);
130
memcpy(s1, s, length);
141
GooString* GooString::Set(const char *s1, int s1Len, const char *s2, int s2Len)
147
if (CALC_STRING_LEN == s1Len) {
155
if (CALC_STRING_LEN == s2Len) {
165
memcpy(p, s1, s1Len);
169
memcpy(p, s2, s2Len);
175
GooString::GooString() {
181
GooString::GooString(const char *sA) {
184
Set(sA, CALC_STRING_LEN);
187
GooString::GooString(const char *sA, int lengthA) {
193
GooString::GooString(GooString *str, int idx, int lengthA) {
196
assert(idx + lengthA <= str->length);
197
Set(str->getCString() + idx, lengthA);
200
GooString::GooString(const GooString *str) {
203
Set(str->getCString(), str->length);
206
GooString::GooString(GooString *str1, GooString *str2) {
209
Set(str1->getCString(), str1->length, str2->getCString(), str2->length);
212
GooString *GooString::fromInt(int x) {
213
char buf[24]; // enough space for 64-bit ints plus a little extra
216
formatInt(x, buf, sizeof(buf), gFalse, 0, 10, &p, &len);
217
return new GooString(p, len);
220
GooString *GooString::format(char *fmt, ...) {
225
va_start(argList, fmt);
226
s->appendfv(fmt, argList);
231
GooString *GooString::formatv(char *fmt, va_list argList) {
235
s->appendfv(fmt, argList);
239
GooString::~GooString() {
244
GooString *GooString::clear() {
249
GooString *GooString::append(char c) {
250
return append((const char*)&c, 1);
253
GooString *GooString::append(GooString *str) {
254
return append(str->getCString(), str->getLength());
257
GooString *GooString::append(const char *str, int lengthA) {
258
int prevLen = length;
259
if (CALC_STRING_LEN == lengthA)
260
lengthA = strlen(str);
261
resize(length + lengthA);
262
memcpy(s + prevLen, str, lengthA);
266
GooString *GooString::appendf(char *fmt, ...) {
269
va_start(argList, fmt);
270
appendfv(fmt, argList);
275
GooString *GooString::appendfv(char *fmt, va_list argList) {
276
GooStringFormatArg *args;
277
int argsLen, argsSize;
278
GooStringFormatArg arg;
279
int idx, width, prec;
280
GBool reverseAlign, zeroFill;
281
GooStringFormatType ft;
288
args = (GooStringFormatArg *)gmallocn(argsSize, sizeof(GooStringFormatArg));
299
// parse the format string
300
if (!(*p0 >= '0' && *p0 <= '9')) {
304
for (++p0; *p0 >= '0' && *p0 <= '9'; ++p0) {
305
idx = 10 * idx + (*p0 - '0');
312
reverseAlign = gTrue;
315
reverseAlign = gFalse;
318
zeroFill = *p0 == '0';
319
for (; *p0 >= '0' && *p0 <= '9'; ++p0) {
320
width = 10 * width + (*p0 - '0');
325
for (; *p0 >= '0' && *p0 <= '9'; ++p0) {
326
prec = 10 * prec + (*p0 - '0');
331
for (ft = (GooStringFormatType)0;
333
ft = (GooStringFormatType)(ft + 1)) {
334
if (!strncmp(p0, formatStrings[ft], strlen(formatStrings[ft]))) {
338
if (!formatStrings[ft]) {
341
p0 += strlen(formatStrings[ft]);
347
// fetch the argument
351
if (idx == argsLen) {
352
if (argsLen == argsSize) {
354
args = (GooStringFormatArg *)greallocn(args, argsSize,
355
sizeof(GooStringFormatArg));
363
args[argsLen].i = va_arg(argList, int);
369
args[argsLen].ui = va_arg(argList, Guint);
375
args[argsLen].l = va_arg(argList, long);
377
case fmtULongDecimal:
381
args[argsLen].ul = va_arg(argList, Gulong);
385
case fmtDoubleTrimSmallAware:
386
args[argsLen].f = va_arg(argList, double);
389
args[argsLen].c = (char)va_arg(argList, int);
392
args[argsLen].s = va_arg(argList, char *);
395
args[argsLen].gs = va_arg(argList, GooString *);
401
// format the argument
405
formatInt(arg.i, buf, sizeof(buf), zeroFill, width, 10, &str, &len);
408
formatInt(arg.i, buf, sizeof(buf), zeroFill, width, 16, &str, &len);
411
formatInt(arg.i, buf, sizeof(buf), zeroFill, width, 8, &str, &len);
414
formatInt(arg.i, buf, sizeof(buf), zeroFill, width, 2, &str, &len);
417
formatUInt(arg.ui, buf, sizeof(buf), zeroFill, width, 10,
421
formatUInt(arg.ui, buf, sizeof(buf), zeroFill, width, 16,
425
formatUInt(arg.ui, buf, sizeof(buf), zeroFill, width, 8, &str, &len);
428
formatUInt(arg.ui, buf, sizeof(buf), zeroFill, width, 2, &str, &len);
431
formatInt(arg.l, buf, sizeof(buf), zeroFill, width, 10, &str, &len);
434
formatInt(arg.l, buf, sizeof(buf), zeroFill, width, 16, &str, &len);
437
formatInt(arg.l, buf, sizeof(buf), zeroFill, width, 8, &str, &len);
440
formatInt(arg.l, buf, sizeof(buf), zeroFill, width, 2, &str, &len);
442
case fmtULongDecimal:
443
formatUInt(arg.ul, buf, sizeof(buf), zeroFill, width, 10,
447
formatUInt(arg.ul, buf, sizeof(buf), zeroFill, width, 16,
451
formatUInt(arg.ul, buf, sizeof(buf), zeroFill, width, 8, &str, &len);
454
formatUInt(arg.ul, buf, sizeof(buf), zeroFill, width, 2, &str, &len);
457
formatDouble(arg.f, buf, sizeof(buf), prec, gFalse, &str, &len);
460
formatDouble(arg.f, buf, sizeof(buf), prec, gTrue, &str, &len);
462
case fmtDoubleTrimSmallAware:
463
formatDoubleSmallAware(arg.f, buf, sizeof(buf), prec, gTrue, &str, &len);
469
reverseAlign = !reverseAlign;
474
reverseAlign = !reverseAlign;
477
str = arg.gs->getCString();
478
len = arg.gs->getLength();
479
reverseAlign = !reverseAlign;
488
// append the formatted arg, handling width and alignment
489
if (!reverseAlign && len < width) {
490
for (i = len; i < width; ++i) {
495
if (reverseAlign && len < width) {
496
for (i = len; i < width; ++i) {
502
} else if (*p0 == '}') {
510
for (p1 = p0 + 1; *p1 && *p1 != '{' && *p1 != '}'; ++p1) ;
520
void GooString::formatInt(long x, char *buf, int bufSize,
521
GBool zeroFill, int width, int base,
522
char **p, int *len) {
523
static char vals[17] = "0123456789abcdef";
535
while (i > start && x) {
536
buf[--i] = vals[x % base];
541
for (j = bufSize - i; i > start && j < width - start; ++j) {
552
void GooString::formatUInt(Gulong x, char *buf, int bufSize,
553
GBool zeroFill, int width, int base,
554
char **p, int *len) {
555
static char vals[17] = "0123456789abcdef";
563
buf[--i] = vals[x % base];
568
for (j = bufSize - i; i > 0 && j < width; ++j) {
576
void GooString::formatDouble(double x, char *buf, int bufSize, int prec,
577
GBool trim, char **p, int *len) {
585
x = floor(x * pow((double)10, prec) + 0.5);
588
for (j = 0; j < prec && i > 1; ++j) {
589
x2 = floor(0.1 * (x + 0.5));
590
d = (int)floor(x - 10 * x2 + 0.5);
591
if (started || d != 0) {
597
if (i > 1 && started) {
602
x2 = floor(0.1 * (x + 0.5));
603
d = (int)floor(x - 10 * x2 + 0.5);
606
} while (i > 1 && x);
615
void GooString::formatDoubleSmallAware(double x, char *buf, int bufSize, int prec,
616
GBool trim, char **p, int *len)
618
double absX = fabs(x);
620
formatDouble(x, buf, bufSize, prec, trim, p, len);
622
while (absX < 0.1 && prec < MAXIMUM_DOUBLE_PREC)
627
formatDouble(x, buf, bufSize, prec, trim, p, len);
631
GooString *GooString::insert(int i, char c) {
632
return insert(i, (const char*)&c, 1);
635
GooString *GooString::insert(int i, GooString *str) {
636
return insert(i, str->getCString(), str->getLength());
639
GooString *GooString::insert(int i, const char *str, int lengthA) {
641
int prevLen = length;
642
if (CALC_STRING_LEN == lengthA)
643
lengthA = strlen(str);
645
resize(length + lengthA);
646
for (j = prevLen; j >= i; --j)
648
memcpy(s+i, str, lengthA);
652
GooString *GooString::del(int i, int n) {
656
if (i + n > length) {
659
for (j = i; j <= length - n; ++j) {
667
GooString *GooString::upperCase() {
670
for (i = 0; i < length; ++i) {
672
s[i] = toupper(s[i]);
677
GooString *GooString::lowerCase() {
680
for (i = 0; i < length; ++i) {
682
s[i] = tolower(s[i]);
687
int GooString::cmp(GooString *str) const {
693
for (i = 0, p1 = s, p2 = str->s; i < n1 && i < n2; ++i, ++p1, ++p2) {
702
int GooString::cmpN(GooString *str, int n) const {
708
for (i = 0, p1 = s, p2 = str->s;
709
i < n1 && i < n2 && i < n;
722
int GooString::cmp(const char *sA) const {
727
for (i = 0, p1 = s, p2 = sA; i < n1 && *p2; ++i, ++p1, ++p2) {
742
int GooString::cmpN(const char *sA, int n) const {
747
for (i = 0, p1 = s, p2 = sA; i < n1 && *p2 && i < n; ++i, ++p1, ++p2) {
765
GBool GooString::hasUnicodeMarker(void)
767
return (s[0] & 0xff) == 0xfe && (s[1] & 0xff) == 0xff;
770
GooString *GooString::sanitizedName(GBool psmode)
777
name = new GooString();
781
// ghostscript chokes on names that begin with out-of-limits
782
// numbers, e.g., 1e4foo is handled correctly (as a name), but
783
// 1e999foo generates a limitcheck error
785
if (c >= '0' && c <= '9') {
790
for (i = 0; i < getLength(); ++i) {
792
if (c <= (char)0x20 || c >= (char)0x7f ||
794
c == '(' || c == ')' || c == '<' || c == '>' ||
795
c == '[' || c == ']' || c == '{' || c == '}' ||
796
c == '/' || c == '%' || c == '#') {
797
sprintf(buf, "#%02x", c & 0xff);