source: trunk/poppler/mypoppler/goo/GooString.cc @ 461

Last change on this file since 461 was 461, checked in by Silvan Scherrer, 11 years ago

poppler update to 0.14.2

File size: 16.7 KB
Line 
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-2010 Albert Astals Cid <aacid@kde.org>
22//
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
25//
26//========================================================================
27
28#include <config.h>
29
30#ifdef USE_GCC_PRAGMAS
31#pragma implementation
32#endif
33
34#include <stdlib.h>
35#include <stddef.h>
36#include <string.h>
37#include <ctype.h>
38#include <assert.h>
39#include <math.h>
40#include "gmem.h"
41#include "GooString.h"
42
43static const int MAXIMUM_DOUBLE_PREC = 16;
44
45//------------------------------------------------------------------------
46
47union GooStringFormatArg {
48  int i;
49  Guint ui;
50  long l;
51  Gulong ul;
52  double f;
53  char c;
54  char *s;
55  GooString *gs;
56};
57
58enum GooStringFormatType {
59  fmtIntDecimal,
60  fmtIntHex,
61  fmtIntOctal,
62  fmtIntBinary,
63  fmtUIntDecimal,
64  fmtUIntHex,
65  fmtUIntOctal,
66  fmtUIntBinary,
67  fmtLongDecimal,
68  fmtLongHex,
69  fmtLongOctal,
70  fmtLongBinary,
71  fmtULongDecimal,
72  fmtULongHex,
73  fmtULongOctal,
74  fmtULongBinary,
75  fmtDouble,
76  fmtDoubleTrimSmallAware,
77  fmtDoubleTrim,
78  fmtChar,
79  fmtString,
80  fmtGooString,
81  fmtSpace
82};
83
84static char *formatStrings[] = {
85  "d", "x", "o", "b", "ud", "ux", "uo", "ub",
86  "ld", "lx", "lo", "lb", "uld", "ulx", "ulo", "ulb",
87  "f", "gs", "g",
88  "c",
89  "s",
90  "t",
91  "w",
92  NULL
93};
94
95//------------------------------------------------------------------------
96
97int inline GooString::roundedSize(int len) {
98  int delta;
99  if (len <= STR_STATIC_SIZE-1)
100      return STR_STATIC_SIZE;
101  delta = len < 256 ? 7 : 255;
102  return ((len + 1) + delta) & ~delta;
103}
104
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.
109void inline GooString::resize(int newLength) {
110  char *s1 = s;
111
112  if (!s || (roundedSize(length) != roundedSize(newLength))) {
113    // requires re-allocating data for string
114    if (newLength < STR_STATIC_SIZE) {
115      s1 = sStatic;
116    } else {
117      // allocate a rounded amount
118      if (s == sStatic)
119        s1 = (char*)gmalloc(roundedSize(newLength));
120      else
121        s1 = (char*)grealloc(s, roundedSize(newLength));
122    }
123    if (s == sStatic || s1 == sStatic) {
124      // copy the minimum, we only need to if are moving to or
125      // from sStatic.
126      // assert(s != s1) the roundedSize condition ensures this
127      if (newLength < length) {
128        memcpy(s1, s, newLength);
129      } else {
130        memcpy(s1, s, length);
131      }
132    }
133
134  }
135
136  s = s1;
137  length = newLength;
138  s[length] = '\0';
139}
140
141GooString* GooString::Set(const char *s1, int s1Len, const char *s2, int s2Len)
142{
143    int newLen = 0;
144    char *p;
145
146    if (s1) {
147        if (CALC_STRING_LEN == s1Len) {
148            s1Len = strlen(s1);
149        } else
150            assert(s1Len >= 0);
151        newLen += s1Len;
152    }
153
154    if (s2) {
155        if (CALC_STRING_LEN == s2Len) {
156            s2Len = strlen(s2);
157        } else
158            assert(s2Len >= 0);
159        newLen += s2Len;
160    }
161
162    resize(newLen);
163    p = s;
164    if (s1) {
165        memcpy(p, s1, s1Len);
166        p += s1Len;
167    }
168    if (s2) {
169        memcpy(p, s2, s2Len);
170        p += s2Len;
171    }
172    return this;
173}
174
175GooString::GooString() {
176  s = NULL;
177  length = 0;
178  Set(NULL);
179}
180
181GooString::GooString(const char *sA) {
182  s = NULL;
183  length = 0;
184  Set(sA, CALC_STRING_LEN);
185}
186
187GooString::GooString(const char *sA, int lengthA) {
188  s = NULL;
189  length = 0;
190  Set(sA, lengthA);
191}
192
193GooString::GooString(GooString *str, int idx, int lengthA) {
194  s = NULL;
195  length = 0;
196  assert(idx + lengthA <= str->length);
197  Set(str->getCString() + idx, lengthA);
198}
199
200GooString::GooString(const GooString *str) {
201  s = NULL;
202  length = 0;
203  Set(str->getCString(), str->length);
204}
205
206GooString::GooString(GooString *str1, GooString *str2) {
207  s = NULL;
208  length = 0;
209  Set(str1->getCString(), str1->length, str2->getCString(), str2->length);
210}
211
212GooString *GooString::fromInt(int x) {
213  char buf[24]; // enough space for 64-bit ints plus a little extra
214  char *p;
215  int len;
216  formatInt(x, buf, sizeof(buf), gFalse, 0, 10, &p, &len);
217  return new GooString(p, len);
218}
219
220GooString *GooString::format(char *fmt, ...) {
221  va_list argList;
222  GooString *s;
223
224  s = new GooString();
225  va_start(argList, fmt);
226  s->appendfv(fmt, argList);
227  va_end(argList);
228  return s;
229}
230
231GooString *GooString::formatv(char *fmt, va_list argList) {
232  GooString *s;
233
234  s = new GooString();
235  s->appendfv(fmt, argList);
236  return s;
237}
238
239GooString::~GooString() {
240  if (s != sStatic)
241    free(s);
242}
243
244GooString *GooString::clear() {
245  resize(0);
246  return this;
247}
248
249GooString *GooString::append(char c) {
250  return append((const char*)&c, 1);
251}
252
253GooString *GooString::append(GooString *str) {
254  return append(str->getCString(), str->getLength());
255}
256
257GooString *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);
263  return this;
264}
265
266GooString *GooString::appendf(char *fmt, ...) {
267  va_list argList;
268
269  va_start(argList, fmt);
270  appendfv(fmt, argList);
271  va_end(argList);
272  return this;
273}
274
275GooString *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;
282  char buf[65];
283  int len, i;
284  char *p0, *p1, *str;
285
286  argsLen = 0;
287  argsSize = 8;
288  args = (GooStringFormatArg *)gmallocn(argsSize, sizeof(GooStringFormatArg));
289
290  p0 = fmt;
291  while (*p0) {
292    if (*p0 == '{') {
293      ++p0;
294      if (*p0 == '{') {
295        ++p0;
296        append('{');
297      } else {
298
299        // parse the format string
300        if (!(*p0 >= '0' && *p0 <= '9')) {
301          break;
302        }
303        idx = *p0 - '0';
304        for (++p0; *p0 >= '0' && *p0 <= '9'; ++p0) {
305          idx = 10 * idx + (*p0 - '0');
306        }
307        if (*p0 != ':') {
308          break;
309        }
310        ++p0;
311        if (*p0 == '-') {
312          reverseAlign = gTrue;
313          ++p0;
314        } else {
315          reverseAlign = gFalse;
316        }
317        width = 0;
318        zeroFill = *p0 == '0';
319        for (; *p0 >= '0' && *p0 <= '9'; ++p0) {
320          width = 10 * width + (*p0 - '0');
321        }
322        if (*p0 == '.') {
323          ++p0;
324          prec = 0;
325          for (; *p0 >= '0' && *p0 <= '9'; ++p0) {
326            prec = 10 * prec + (*p0 - '0');
327          }
328        } else {
329          prec = 0;
330        }
331        for (ft = (GooStringFormatType)0;
332             formatStrings[ft];
333             ft = (GooStringFormatType)(ft + 1)) {
334          if (!strncmp(p0, formatStrings[ft], strlen(formatStrings[ft]))) {
335            break;
336          }
337        }
338        if (!formatStrings[ft]) {
339          break;
340        }
341        p0 += strlen(formatStrings[ft]);
342        if (*p0 != '}') {
343          break;
344        }
345        ++p0;
346
347        // fetch the argument
348        if (idx > argsLen) {
349          break;
350        }
351        if (idx == argsLen) {
352          if (argsLen == argsSize) {
353            argsSize *= 2;
354            args = (GooStringFormatArg *)greallocn(args, argsSize,
355                                                 sizeof(GooStringFormatArg));
356          }
357          switch (ft) {
358          case fmtIntDecimal:
359          case fmtIntHex:
360          case fmtIntOctal:
361          case fmtIntBinary:
362          case fmtSpace:
363            args[argsLen].i = va_arg(argList, int);
364            break;
365          case fmtUIntDecimal:
366          case fmtUIntHex:
367          case fmtUIntOctal:
368          case fmtUIntBinary:
369            args[argsLen].ui = va_arg(argList, Guint);
370            break;
371          case fmtLongDecimal:
372          case fmtLongHex:
373          case fmtLongOctal:
374          case fmtLongBinary:
375            args[argsLen].l = va_arg(argList, long);
376            break;
377          case fmtULongDecimal:
378          case fmtULongHex:
379          case fmtULongOctal:
380          case fmtULongBinary:
381            args[argsLen].ul = va_arg(argList, Gulong);
382            break;
383          case fmtDouble:
384          case fmtDoubleTrim:
385          case fmtDoubleTrimSmallAware:
386            args[argsLen].f = va_arg(argList, double);
387            break;
388          case fmtChar:
389            args[argsLen].c = (char)va_arg(argList, int);
390            break;
391          case fmtString:
392            args[argsLen].s = va_arg(argList, char *);
393            break;
394          case fmtGooString:
395            args[argsLen].gs = va_arg(argList, GooString *);
396            break;
397          }
398          ++argsLen;
399        }
400
401        // format the argument
402        arg = args[idx];
403        switch (ft) {
404        case fmtIntDecimal:
405          formatInt(arg.i, buf, sizeof(buf), zeroFill, width, 10, &str, &len);
406          break;
407        case fmtIntHex:
408          formatInt(arg.i, buf, sizeof(buf), zeroFill, width, 16, &str, &len);
409          break;
410        case fmtIntOctal:
411          formatInt(arg.i, buf, sizeof(buf), zeroFill, width, 8, &str, &len);
412          break;
413        case fmtIntBinary:
414          formatInt(arg.i, buf, sizeof(buf), zeroFill, width, 2, &str, &len);
415          break;
416        case fmtUIntDecimal:
417          formatUInt(arg.ui, buf, sizeof(buf), zeroFill, width, 10,
418                     &str, &len);
419          break;
420        case fmtUIntHex:
421          formatUInt(arg.ui, buf, sizeof(buf), zeroFill, width, 16,
422                     &str, &len);
423          break;
424        case fmtUIntOctal:
425          formatUInt(arg.ui, buf, sizeof(buf), zeroFill, width, 8, &str, &len);
426          break;
427        case fmtUIntBinary:
428          formatUInt(arg.ui, buf, sizeof(buf), zeroFill, width, 2, &str, &len);
429          break;
430        case fmtLongDecimal:
431          formatInt(arg.l, buf, sizeof(buf), zeroFill, width, 10, &str, &len);
432          break;
433        case fmtLongHex:
434          formatInt(arg.l, buf, sizeof(buf), zeroFill, width, 16, &str, &len);
435          break;
436        case fmtLongOctal:
437          formatInt(arg.l, buf, sizeof(buf), zeroFill, width, 8, &str, &len);
438          break;
439        case fmtLongBinary:
440          formatInt(arg.l, buf, sizeof(buf), zeroFill, width, 2, &str, &len);
441          break;
442        case fmtULongDecimal:
443          formatUInt(arg.ul, buf, sizeof(buf), zeroFill, width, 10,
444                     &str, &len);
445          break;
446        case fmtULongHex:
447          formatUInt(arg.ul, buf, sizeof(buf), zeroFill, width, 16,
448                     &str, &len);
449          break;
450        case fmtULongOctal:
451          formatUInt(arg.ul, buf, sizeof(buf), zeroFill, width, 8, &str, &len);
452          break;
453        case fmtULongBinary:
454          formatUInt(arg.ul, buf, sizeof(buf), zeroFill, width, 2, &str, &len);
455          break;
456        case fmtDouble:
457          formatDouble(arg.f, buf, sizeof(buf), prec, gFalse, &str, &len);
458          break;
459        case fmtDoubleTrim:
460          formatDouble(arg.f, buf, sizeof(buf), prec, gTrue, &str, &len);
461          break;
462        case fmtDoubleTrimSmallAware:
463          formatDoubleSmallAware(arg.f, buf, sizeof(buf), prec, gTrue, &str, &len);
464          break;
465        case fmtChar:
466          buf[0] = arg.c;
467          str = buf;
468          len = 1;
469          reverseAlign = !reverseAlign;
470          break;
471        case fmtString:
472          str = arg.s;
473          len = strlen(str);
474          reverseAlign = !reverseAlign;
475          break;
476        case fmtGooString:
477          str = arg.gs->getCString();
478          len = arg.gs->getLength();
479          reverseAlign = !reverseAlign;
480          break;
481        case fmtSpace:
482          str = buf;
483          len = 0;
484          width = arg.i;
485          break;
486        }
487
488        // append the formatted arg, handling width and alignment
489        if (!reverseAlign && len < width) {
490          for (i = len; i < width; ++i) {
491            append(' ');
492          }
493        }
494        append(str, len);
495        if (reverseAlign && len < width) {
496          for (i = len; i < width; ++i) {
497            append(' ');
498          }
499        }
500      }
501
502    } else if (*p0 == '}') {
503      ++p0;
504      if (*p0 == '}') {
505        ++p0;
506      }
507      append('}');
508     
509    } else {
510      for (p1 = p0 + 1; *p1 && *p1 != '{' && *p1 != '}'; ++p1) ;
511      append(p0, p1 - p0);
512      p0 = p1;
513    }
514  }
515
516  gfree(args);
517  return this;
518}
519
520void 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";
524  GBool neg;
525  int start, i, j;
526
527  i = bufSize;
528  if ((neg = x < 0)) {
529    x = -x;
530  }
531  start = neg ? 1 : 0;
532  if (x == 0) {
533    buf[--i] = '0';
534  } else {
535    while (i > start && x) {
536      buf[--i] = vals[x % base];
537      x /= base;
538    }
539  }
540  if (zeroFill) {
541    for (j = bufSize - i; i > start && j < width - start; ++j) {
542      buf[--i] = '0';
543    }
544  }
545  if (neg) {
546    buf[--i] = '-';
547  }
548  *p = buf + i;
549  *len = bufSize - i;
550}
551
552void 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";
556  int i, j;
557
558  i = bufSize;
559  if (x == 0) {
560    buf[--i] = '0';
561  } else {
562    while (i > 0 && x) {
563      buf[--i] = vals[x % base];
564      x /= base;
565    }
566  }
567  if (zeroFill) {
568    for (j = bufSize - i; i > 0 && j < width; ++j) {
569      buf[--i] = '0';
570    }
571  }
572  *p = buf + i;
573  *len = bufSize - i;
574}
575
576void GooString::formatDouble(double x, char *buf, int bufSize, int prec,
577                           GBool trim, char **p, int *len) {
578  GBool neg, started;
579  double x2;
580  int d, i, j;
581
582  if ((neg = x < 0)) {
583    x = -x;
584  }
585  x = floor(x * pow((double)10, prec) + 0.5);
586  i = bufSize;
587  started = !trim;
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) {
592      buf[--i] = '0' + d;
593      started = gTrue;
594    }
595    x = x2;
596  }
597  if (i > 1 && started) {
598    buf[--i] = '.';
599  }
600  if (i > 1) {
601    do {
602      x2 = floor(0.1 * (x + 0.5));
603      d = (int)floor(x - 10 * x2 + 0.5);
604      buf[--i] = '0' + d;
605      x = x2;
606    } while (i > 1 && x);
607  }
608  if (neg) {
609    buf[--i] = '-';
610  }
611  *p = buf + i;
612  *len = bufSize - i;
613}
614
615void GooString::formatDoubleSmallAware(double x, char *buf, int bufSize, int prec,
616                                      GBool trim, char **p, int *len)
617{
618  double absX = fabs(x);
619  if (absX >= 0.1) {
620    formatDouble(x, buf, bufSize, prec, trim, p, len);
621  } else {
622    while (absX < 0.1 && prec < MAXIMUM_DOUBLE_PREC)
623    {
624      absX = absX * 10;
625      prec++;
626    }
627    formatDouble(x, buf, bufSize, prec, trim, p, len);
628  }
629}
630
631GooString *GooString::insert(int i, char c) {
632  return insert(i, (const char*)&c, 1);
633}
634
635GooString *GooString::insert(int i, GooString *str) {
636  return insert(i, str->getCString(), str->getLength());
637}
638
639GooString *GooString::insert(int i, const char *str, int lengthA) {
640  int j;
641  int prevLen = length;
642  if (CALC_STRING_LEN == lengthA)
643    lengthA = strlen(str);
644
645  resize(length + lengthA);
646  for (j = prevLen; j >= i; --j)
647    s[j+lengthA] = s[j];
648  memcpy(s+i, str, lengthA);
649  return this;
650}
651
652GooString *GooString::del(int i, int n) {
653  int j;
654
655  if (n > 0) {
656    if (i + n > length) {
657      n = length - i;
658    }
659    for (j = i; j <= length - n; ++j) {
660      s[j] = s[j + n];
661    }
662    resize(length - n);
663  }
664  return this;
665}
666
667GooString *GooString::upperCase() {
668  int i;
669
670  for (i = 0; i < length; ++i) {
671    if (islower(s[i]))
672      s[i] = toupper(s[i]);
673  }
674  return this;
675}
676
677GooString *GooString::lowerCase() {
678  int i;
679
680  for (i = 0; i < length; ++i) {
681    if (isupper(s[i]))
682      s[i] = tolower(s[i]);
683  }
684  return this;
685}
686
687int GooString::cmp(GooString *str) const {
688  int n1, n2, i, x;
689  char *p1, *p2;
690
691  n1 = length;
692  n2 = str->length;
693  for (i = 0, p1 = s, p2 = str->s; i < n1 && i < n2; ++i, ++p1, ++p2) {
694    x = *p1 - *p2;
695    if (x != 0) {
696      return x;
697    }
698  }
699  return n1 - n2;
700}
701
702int GooString::cmpN(GooString *str, int n) const {
703  int n1, n2, i, x;
704  char *p1, *p2;
705
706  n1 = length;
707  n2 = str->length;
708  for (i = 0, p1 = s, p2 = str->s;
709       i < n1 && i < n2 && i < n;
710       ++i, ++p1, ++p2) {
711    x = *p1 - *p2;
712    if (x != 0) {
713      return x;
714    }
715  }
716  if (i == n) {
717    return 0;
718  }
719  return n1 - n2;
720}
721
722int GooString::cmp(const char *sA) const {
723  int n1, i, x;
724  const char *p1, *p2;
725
726  n1 = length;
727  for (i = 0, p1 = s, p2 = sA; i < n1 && *p2; ++i, ++p1, ++p2) {
728    x = *p1 - *p2;
729    if (x != 0) {
730      return x;
731    }
732  }
733  if (i < n1) {
734    return 1;
735  }
736  if (*p2) {
737    return -1;
738  }
739  return 0;
740}
741
742int GooString::cmpN(const char *sA, int n) const {
743  int n1, i, x;
744  const char *p1, *p2;
745
746  n1 = length;
747  for (i = 0, p1 = s, p2 = sA; i < n1 && *p2 && i < n; ++i, ++p1, ++p2) {
748    x = *p1 - *p2;
749    if (x != 0) {
750      return x;
751    }
752  }
753  if (i == n) {
754    return 0;
755  }
756  if (i < n1) {
757    return 1;
758  }
759  if (*p2) {
760    return -1;
761  }
762  return 0;
763}
764
765GBool GooString::hasUnicodeMarker(void)
766{
767    return (s[0] & 0xff) == 0xfe && (s[1] & 0xff) == 0xff;
768}
769
770GooString *GooString::sanitizedName(GBool psmode)
771{
772  GooString *name;
773  char buf[8];
774  int i;
775  char c;
776
777  name = new GooString();
778
779  if (psmode)
780  {
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
784    c = getChar(0);
785    if (c >= '0' && c <= '9') {
786      name->append('f');
787    }
788  }
789
790  for (i = 0; i < getLength(); ++i) {
791    c = getChar(i);
792    if (c <= (char)0x20 || c >= (char)0x7f ||
793        c == ' ' ||
794        c == '(' || c == ')' || c == '<' || c == '>' ||
795        c == '[' || c == ']' || c == '{' || c == '}' ||
796        c == '/' || c == '%' || c == '#') {
797      sprintf(buf, "#%02x", c & 0xff);
798      name->append(buf);
799    } else {
800      name->append(c);
801    }
802  }
803  return name;
804}
Note: See TracBrowser for help on using the repository browser.