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

Last change on this file since 257 was 257, checked in by Eugene Romanenko, 13 years ago

PDF plugin: Poppler library updated to version 0.10.0

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