PageRenderTime 78ms CodeModel.GetById 44ms app.highlight 29ms RepoModel.GetById 0ms app.codeStats 0ms

/TeXmacs-1.0.7.11-src/src/Plugins/Pdf/dvipdfmx/pst_obj.c

#
C | 894 lines | 717 code | 119 blank | 58 comment | 113 complexity | 9d31d0a017f203e577c40597ef682328 MD5 | raw file
Possible License(s): GPL-3.0, GPL-2.0, MPL-2.0-no-copyleft-exception
  1/*  $Header: /home/cvsroot/dvipdfmx/src/pst_obj.c,v 1.9 2008/11/30 21:12:27 matthias Exp $
  2
  3    This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks.
  4
  5    Copyright (C) 2002 by Jin-Hwan Cho and Shunsaku Hirata,
  6    the dvipdfmx project team <dvipdfmx@project.ktug.or.kr>
  7
  8    Copyright (C) 1998, 1999 by Mark A. Wicks <mwicks@kettering.edu>
  9
 10    This program is free software; you can redistribute it and/or modify
 11    it under the terms of the GNU General Public License as published by
 12    the Free Software Foundation; either version 2 of the License, or
 13    (at your option) any later version.
 14
 15    This program is distributed in the hope that it will be useful,
 16    but WITHOUT ANY WARRANTY; without even the implied warranty of
 17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 18    GNU General Public License for more details.
 19
 20    You should have received a copy of the GNU General Public License
 21    along with this program; if not, write to the Free Software
 22    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
 23*/
 24
 25#include <string.h>
 26#include <stdlib.h>
 27#include <errno.h>
 28
 29#include "system.h"
 30#include "mem.h"
 31#include "error.h"
 32#include "dpxutil.h"
 33#include "pst.h"
 34#include "pst_obj.h"
 35
 36struct pst_obj
 37{
 38  pst_type type;
 39  void    *data;
 40};
 41
 42static const char *pst_const_null  = "null";
 43static const char *pst_const_mark  = "mark";
 44/*
 45static const char *pst_const_true  = "true";
 46static const char *pst_const_false = "false";
 47*/
 48
 49typedef char *                     pst_null;
 50typedef struct { char    value; }  pst_boolean;
 51typedef struct { long    value; }  pst_integer;
 52typedef struct { double  value; }  pst_real;
 53typedef struct { char   *value; }  pst_name;
 54typedef struct
 55{
 56  long    length;
 57  unsigned char *value;
 58} pst_string;
 59
 60
 61/* BOOLEAN */
 62static pst_boolean *pst_boolean_new     (char value)      ;
 63static void         pst_boolean_release (pst_boolean *obj);
 64static long         pst_boolean_IV      (pst_boolean *obj);
 65static double       pst_boolean_RV      (pst_boolean *obj);
 66static unsigned char *pst_boolean_SV      (pst_boolean *obj);
 67static long         pst_boolean_length  (pst_boolean *obj);
 68static void        *pst_boolean_data_ptr(pst_boolean *obj);
 69
 70/* NUMBERS */
 71static pst_integer *pst_integer_new     (long value)      ;
 72static void         pst_integer_release (pst_integer *obj);
 73static long         pst_integer_IV      (pst_integer *obj);
 74static double       pst_integer_RV      (pst_integer *obj);
 75static unsigned char      *pst_integer_SV      (pst_integer *obj);
 76static unsigned int        pst_integer_length  (pst_integer *obj);
 77static void        *pst_integer_data_ptr(pst_integer *obj);
 78
 79static pst_real *pst_real_new      (double value) ;
 80static void      pst_real_release  (pst_real *obj);
 81static long      pst_real_IV       (pst_real *obj);
 82static double    pst_real_RV       (pst_real *obj);
 83static unsigned char   *pst_real_SV       (pst_real *obj);
 84static void     *pst_real_data_ptr (pst_real *obj);
 85static unsigned int     pst_real_length   (pst_real *obj);
 86
 87/* NAME */
 88static pst_name *pst_name_new      (const char *name) ;
 89static void      pst_name_release  (pst_name *obj);
 90static long      pst_name_IV       (pst_name *obj);
 91static double    pst_name_RV       (pst_name *obj);
 92static unsigned char   *pst_name_SV       (pst_name *obj);
 93static void     *pst_name_data_ptr (pst_name *obj);
 94static unsigned int     pst_name_length   (pst_name *obj);
 95
 96/* STRING */
 97static pst_string *pst_string_parse_literal (unsigned char **inbuf, unsigned char *inbufend);
 98static pst_string *pst_string_parse_hex     (unsigned char **inbuf, unsigned char *inbufend);
 99
100static pst_string *pst_string_new      (unsigned char *str, unsigned int len);
101static void        pst_string_release  (pst_string *obj)       ;
102static long        pst_string_IV       (pst_string *obj)       ;
103static double      pst_string_RV       (pst_string *obj)       ;
104static unsigned char     *pst_string_SV       (pst_string *obj)       ;
105static void       *pst_string_data_ptr (pst_string *obj)       ;
106static unsigned int       pst_string_length   (pst_string *obj)       ;
107
108
109#define TYPE_ERROR() ERROR("Operation not defined for this type of object.")
110
111pst_obj *
112pst_new_obj (pst_type type, void *data)
113{
114  pst_obj *obj;
115
116  obj = NEW(1, struct pst_obj);
117  obj->type = type;
118  obj->data = data;
119
120  return obj;
121}
122
123pst_obj *
124pst_new_mark (void)
125{
126  return pst_new_obj(PST_TYPE_MARK, (void *)pst_const_mark);
127}
128
129void
130pst_release_obj (pst_obj *obj)
131{
132  ASSERT(obj);
133  switch (obj->type) {
134  case PST_TYPE_BOOLEAN: pst_boolean_release(obj->data); break;
135  case PST_TYPE_INTEGER: pst_integer_release(obj->data); break;
136  case PST_TYPE_REAL:    pst_real_release(obj->data);    break;
137  case PST_TYPE_NAME:    pst_name_release(obj->data);    break;
138  case PST_TYPE_STRING:  pst_string_release(obj->data);  break;
139  case PST_TYPE_NULL:
140  case PST_TYPE_MARK:
141    break;
142  case PST_TYPE_UNKNOWN:
143    if (obj->data)
144      RELEASE(obj->data);
145    break;
146  default:
147    ERROR("Unrecognized object type: %d", obj->type);
148  }
149  RELEASE(obj);
150}
151
152pst_type
153pst_type_of (pst_obj *obj)
154{
155  ASSERT(obj);
156  return obj->type;
157}
158
159long
160pst_length_of (pst_obj *obj)
161{
162  long len = 0;
163
164  ASSERT(obj);
165  switch (obj->type) {
166  case PST_TYPE_BOOLEAN: len = pst_boolean_length(obj->data); break;
167  case PST_TYPE_INTEGER: len = pst_integer_length(obj->data); break;
168  case PST_TYPE_REAL:    len = pst_real_length(obj->data);    break;
169  case PST_TYPE_NAME:    len = pst_name_length(obj->data);    break;
170  case PST_TYPE_STRING:  len = pst_string_length(obj->data);  break;
171  case PST_TYPE_NULL:
172  case PST_TYPE_MARK:
173    TYPE_ERROR();                     
174    break;
175  case PST_TYPE_UNKNOWN:
176    len = strlen(obj->data);
177    break;
178  default:
179    ERROR("Unrecognized object type: %d", obj->type);
180  }
181
182  return len;
183}
184
185long
186pst_getIV (pst_obj *obj)
187{
188  long iv = 0;
189
190  ASSERT(obj);
191  switch (obj->type) {
192  case PST_TYPE_BOOLEAN: iv = pst_boolean_IV(obj->data); break;
193  case PST_TYPE_INTEGER: iv = pst_integer_IV(obj->data); break;
194  case PST_TYPE_REAL:    iv = pst_real_IV(obj->data);    break;
195  case PST_TYPE_NAME:    iv = pst_name_IV(obj->data);    break;
196  case PST_TYPE_STRING:  iv = pst_string_IV(obj->data);  break;
197  case PST_TYPE_NULL:
198  case PST_TYPE_MARK: 
199    TYPE_ERROR(); 
200    break;
201  case PST_TYPE_UNKNOWN:
202    ERROR("Cannot convert object of type UNKNOWN to integer value.");
203    break;
204  default:
205    ERROR("Unrecognized object type: %d", obj->type);
206  }
207
208  return iv;
209}
210
211double
212pst_getRV (pst_obj *obj)
213{
214  double rv = 0.0;
215
216  ASSERT(obj);
217  switch (obj->type) {
218  case PST_TYPE_BOOLEAN: rv = pst_boolean_RV(obj->data); break;
219  case PST_TYPE_INTEGER: rv = pst_integer_RV(obj->data); break;
220  case PST_TYPE_REAL:    rv = pst_real_RV(obj->data);    break;
221  case PST_TYPE_NAME:    rv = pst_name_RV(obj->data);    break;
222  case PST_TYPE_STRING:  rv = pst_string_RV(obj->data);  break;
223  case PST_TYPE_NULL:
224  case PST_TYPE_MARK:
225    TYPE_ERROR();                  
226    break;
227  case PST_TYPE_UNKNOWN:
228    ERROR("Cannot convert object of type UNKNOWN to real value.");
229    break;
230  default:
231    ERROR("Unrecognized object type: %d", obj->type);
232  }
233
234  return rv;
235}
236
237/* Length can be obtained by pst_length_of(). */
238unsigned char *
239pst_getSV (pst_obj *obj)
240{
241  unsigned char *sv = NULL;
242
243  ASSERT(obj);
244  switch (obj->type) {
245  case PST_TYPE_BOOLEAN: sv = pst_boolean_SV(obj->data); break;
246  case PST_TYPE_INTEGER: sv = pst_integer_SV(obj->data); break;
247  case PST_TYPE_REAL:    sv = pst_real_SV(obj->data);    break;
248  case PST_TYPE_NAME:    sv = pst_name_SV(obj->data);    break;
249  case PST_TYPE_STRING:  sv = pst_string_SV(obj->data);  break;
250  case PST_TYPE_NULL:
251  case PST_TYPE_MARK:
252    TYPE_ERROR(); 
253    break;
254  case PST_TYPE_UNKNOWN:
255    {
256      long len;
257
258      len = strlen((char *) obj->data);
259      if (len > 0) {
260	sv = NEW(len+1, unsigned char);
261	memcpy(sv, obj->data, len);
262	sv[len] = '\0';
263      } else {
264	sv = NULL;
265      }
266      break;
267    }
268  default:
269    ERROR("Unrecognized object type: %d", obj->type);
270  }
271
272  return sv;
273}
274
275void *
276pst_data_ptr (pst_obj *obj)
277{
278  char *p = NULL;
279
280  ASSERT(obj);
281  switch (obj->type) {
282  case PST_TYPE_BOOLEAN: p = pst_boolean_data_ptr(obj->data); break;
283  case PST_TYPE_INTEGER: p = pst_integer_data_ptr(obj->data); break;
284  case PST_TYPE_REAL:    p = pst_real_data_ptr(obj->data);    break;
285  case PST_TYPE_NAME:    p = pst_name_data_ptr(obj->data);    break;
286  case PST_TYPE_STRING:  p = pst_string_data_ptr(obj->data);  break;
287  case PST_TYPE_NULL:
288  case PST_TYPE_MARK: 
289    TYPE_ERROR();
290    break;
291  case PST_TYPE_UNKNOWN:
292    p = obj->data;
293    break;
294  default:
295    ERROR("Unrecognized object type: %d", obj->type);
296  }
297
298  return (void *)p;
299}
300
301/* BOOLEAN */
302static pst_boolean *
303pst_boolean_new (char value)
304{
305  pst_boolean *obj;
306  obj = NEW(1, pst_boolean);
307  obj->value = value;
308  return obj;
309}
310
311static void
312pst_boolean_release (pst_boolean *obj)
313{
314  ASSERT(obj);
315  RELEASE(obj);
316}
317
318static long
319pst_boolean_IV (pst_boolean *obj)
320{
321  ASSERT(obj);
322  return (long) obj->value;
323}
324
325static double
326pst_boolean_RV (pst_boolean *obj)
327{
328  ASSERT(obj);
329  return (double) obj->value;
330}
331
332static unsigned char *
333pst_boolean_SV (pst_boolean *obj)
334{
335  unsigned char *str;
336
337  ASSERT(obj);
338
339  if (obj->value) {
340    str = NEW(5, unsigned char);
341    memcpy(str, "true", 4);
342    str[4] = '\0';
343  } else {
344    str = NEW(6, unsigned char);
345    memcpy(str, "false", 5);
346    str[5] = '\0';
347  }
348
349  return str;
350}
351
352static long
353pst_boolean_length (pst_boolean *obj)
354{
355  TYPE_ERROR();
356  return 0;
357}
358
359static void *
360pst_boolean_data_ptr (pst_boolean *obj)
361{
362  ASSERT(obj);
363  return (void*) &(obj->value);
364}
365
366pst_obj *
367pst_parse_boolean (unsigned char **inbuf, unsigned char *inbufend)
368{
369  if (*inbuf + 4 <= inbufend &&
370      memcmp(*inbuf, "true", 4) == 0 &&
371      PST_TOKEN_END(*inbuf + 4, inbufend)) {
372    *inbuf += 4;
373    return pst_new_obj(PST_TYPE_BOOLEAN, pst_boolean_new(1));
374  } else if (*inbuf + 5 <= inbufend &&
375	     memcmp(*inbuf, "false", 5) == 0 &&
376	     PST_TOKEN_END(*inbuf + 5, inbufend)) {
377    *inbuf += 5;
378    return pst_new_obj(PST_TYPE_BOOLEAN, pst_boolean_new(0));
379  } else
380    return NULL;
381}
382
383
384/* NULL */
385pst_obj *
386pst_parse_null (unsigned char **inbuf, unsigned char *inbufend)
387{
388  if (*inbuf + 4 <= inbufend &&
389      memcmp(*inbuf, "null", 4) == 0 &&
390      PST_TOKEN_END(*inbuf+4, inbufend)) {
391    *inbuf += 4;
392    return pst_new_obj(PST_TYPE_NULL, (void*)pst_const_null);
393  } else
394    return NULL;
395}
396
397/* INTEGER */
398static pst_integer *
399pst_integer_new (long value)
400{
401  pst_integer *obj;
402  obj = NEW(1, pst_integer);
403  obj->value = value;
404  return obj;
405}
406
407static void
408pst_integer_release (pst_integer *obj)
409{
410  ASSERT(obj);
411  RELEASE(obj);
412}
413
414static long
415pst_integer_IV (pst_integer *obj)
416{
417  ASSERT(obj);
418  return (long) obj->value;
419}
420
421static double
422pst_integer_RV (pst_integer *obj)
423{
424  ASSERT(obj);
425  return (double) obj->value;
426}
427
428static unsigned char *
429pst_integer_SV (pst_integer *obj)
430{
431  char *value;
432  int   len;
433  char  fmt_buf[PST_MAX_DIGITS+5];
434
435  ASSERT(obj);
436
437  len = sprintf(fmt_buf, "%ld", obj->value);
438
439  value = NEW(len, char);
440  strcpy(value, fmt_buf);
441
442  return (unsigned char *) value;
443}
444
445static void *
446pst_integer_data_ptr (pst_integer *obj)
447{
448  ASSERT(obj);
449  return (void*) &(obj->value);
450}
451
452static unsigned int
453pst_integer_length (pst_integer *obj)
454{
455  TYPE_ERROR();
456  return 0;
457}
458
459/* REAL */
460static pst_real *
461pst_real_new (double value)
462{
463  pst_real *obj;
464
465  obj = NEW(1, pst_real);
466  obj->value = value;
467
468  return obj;
469}
470
471static void
472pst_real_release (pst_real *obj)
473{
474  ASSERT(obj);
475  RELEASE(obj);
476}
477
478static long
479pst_real_IV (pst_real *obj)
480{
481  ASSERT(obj);
482  return (long) obj->value;
483}
484
485static double
486pst_real_RV (pst_real *obj)
487{
488  ASSERT(obj);
489  return (double) obj->value;
490}
491
492static unsigned char *
493pst_real_SV (pst_real *obj)
494{
495  char *value;
496  int   len;
497  char  fmt_buf[PST_MAX_DIGITS+5];
498
499  ASSERT(obj);
500
501  len = sprintf(fmt_buf, "%.5g", obj->value);
502
503  value = NEW(len, char);
504  strcpy(value, fmt_buf);
505
506  return (unsigned char *) value;
507}
508
509static void *
510pst_real_data_ptr (pst_real *obj)
511{
512  ASSERT(obj);
513
514  return (void*) &(obj->value);
515}
516
517static unsigned int
518pst_real_length (pst_real *obj)
519{
520  TYPE_ERROR();
521  return 0;
522}
523
524/* NOTE: the input buffer must be null-terminated, i.e., *inbufend == 0 */
525/* leading white-space is ignored */
526pst_obj *
527pst_parse_number (unsigned char **inbuf, unsigned char *inbufend)
528{
529  unsigned char  *cur;
530  long    lval;
531  double  dval;
532
533  errno = 0;
534  lval = strtol((char *) *inbuf, (char **) (void *) &cur, 10);
535  if (errno || *cur == '.' || *cur == 'e' || *cur == 'E') {
536    /* real */
537    errno = 0;
538    dval = strtod((char *) *inbuf, (char **) (void *) &cur);
539    if (!errno && PST_TOKEN_END(cur, inbufend)) {
540      *inbuf = cur;
541      return pst_new_obj(PST_TYPE_REAL, pst_real_new(dval));
542    }
543  } else if (cur != *inbuf && PST_TOKEN_END(cur, inbufend)) {
544    /* integer */
545    *inbuf = cur;
546    return pst_new_obj(PST_TYPE_INTEGER, pst_integer_new(lval));
547  } else if (lval >= 2 && lval <= 36 && *cur == '#' && isalnum(*++cur) &&
548	     /* strtod allows leading "0x" for hex numbers, but we don't */
549	     (lval != 16 || (cur[1] != 'x' && cur[1] != 'X'))) {
550    /* integer with radix */
551    /* Can the base have a (plus) sign? I think yes. */
552    errno = 0;
553    lval = strtol((char *) cur, (char **) (void *) &cur, lval);
554    if (!errno && PST_TOKEN_END(cur, inbufend)) {
555      *inbuf = cur;
556      return pst_new_obj(PST_TYPE_INTEGER, pst_integer_new(lval));
557    }
558  }
559  /* error */
560  return NULL;
561}
562
563/* NAME */
564
565/*
566 * \0 is not allowed for name object.
567 */
568
569static pst_name *
570pst_name_new (const char *name)
571{
572  pst_name *obj;
573
574  obj = NEW(1, pst_name);
575  obj->value = NEW(strlen(name)+1, char);
576  strcpy(obj->value, name);
577
578  return obj;
579}
580
581static void
582pst_name_release (pst_name *obj)
583{
584  ASSERT(obj);
585  if (obj->value)
586    RELEASE(obj->value);
587  RELEASE(obj);
588}
589
590#if 0
591int
592pst_name_is_valid (const char *name)
593{
594  static const char *valid_chars =
595    "!\"#$&'*+,-.0123456789:;=?@ABCDEFGHIJKLMNOPQRSTUVWXYZ\\^_`abcdefghijklmnopqrstuvwxyz|~";
596  if (strspn(name, valid_chars) == strlen(name))
597    return 1;
598  else
599    return 0;
600}
601
602char *
603pst_name_encode (const char *name)
604{
605  char *encoded_name, *p;
606  int   i, len;
607  char  c;
608
609  len = strlen(name);
610  if (len > PST_NAME_LEN_MAX) {
611    WARN("Input string too long for name object. String will be truncated.");
612    len = PST_NAME_LEN_MAX;
613  }
614
615  p = encoded_name = NEW(3*len+1, char);
616  for (i = 0; i < len; i++) {
617    c = name[i];
618    if (c < '!'  || c > '~' ||
619	c == '#' || is_delim(c) || is_space(c)) {
620      *p++ = '#';
621      putxpair(c, &p);
622    } else {
623      *p++ = c;
624    }
625  }
626  *p = '\0';
627
628  return encoded_name;
629}
630#endif
631
632pst_obj *
633pst_parse_name (unsigned char **inbuf, unsigned char *inbufend) /* / is required */
634{
635  unsigned char  wbuf[PST_NAME_LEN_MAX+1];
636  unsigned char  c, *p = wbuf, *cur = *inbuf;
637  int     len = 0;
638
639  if (*cur != '/')
640    return NULL;
641  cur++;
642
643  while (!PST_TOKEN_END(cur, inbufend)) {
644    c = *cur++;
645    if (c == '#') {
646      int val;
647      if (cur + 2 >= inbufend) {
648	WARN("Premature end of input name string.");
649	break;
650      }
651      val = getxpair(&cur);
652      if (val <= 0) {
653	WARN("Invalid char for name object. (ignored)");
654	continue;
655      } else
656	c = (unsigned char) val;
657    }
658    if (len < PST_NAME_LEN_MAX)
659      *p++ = c;
660    len++;
661  }
662  *p = '\0';
663
664  if (len > PST_NAME_LEN_MAX)
665    WARN("String too long for name object. Output will be truncated.");
666
667  *inbuf = cur;
668  return pst_new_obj(PST_TYPE_NAME, pst_name_new((char *)wbuf));
669}
670
671static long
672pst_name_IV (pst_name *obj)
673{
674  TYPE_ERROR();
675  return 0;
676}
677
678static double
679pst_name_RV (pst_name *obj)
680{
681  TYPE_ERROR();
682  return 0;
683}
684
685static unsigned char *
686pst_name_SV (pst_name *obj)
687{
688  char *value;
689
690  value = NEW(strlen(obj->value)+1, char);
691  strcpy(value, obj->value);
692
693  return (unsigned char *) value;
694}
695
696static void *
697pst_name_data_ptr (pst_name *obj)
698{
699  ASSERT(obj);
700  return obj->value;
701}
702
703static unsigned int
704pst_name_length (pst_name *obj)
705{
706  ASSERT(obj);
707  return strlen(obj->value);
708}
709
710
711/* STRING */
712
713/*
714 * TODO: ascii85 string <~ .... ~>
715 */
716static pst_string *
717pst_string_new (unsigned char *str, unsigned int len)
718{
719  pst_string *obj;
720  obj = NEW(1, pst_string);
721  obj->length  = len;
722  obj->value = NULL;
723  if (len > 0) {
724    obj->value = NEW(len, unsigned char);
725    if (str)
726      memcpy(obj->value, str, len);
727  }
728  return obj;
729}
730
731static void
732pst_string_release (pst_string *obj)
733{
734  ASSERT(obj);
735  if (obj->value)
736    RELEASE(obj->value);
737  RELEASE(obj);
738}
739
740pst_obj *
741pst_parse_string (unsigned char **inbuf, unsigned char *inbufend)
742{
743  if (*inbuf + 2 >= inbufend) {
744    return NULL;
745  } else if (**inbuf == '(')
746    return pst_new_obj(PST_TYPE_STRING, pst_string_parse_literal(inbuf, inbufend));
747  else if (**inbuf == '<' && *(*inbuf+1) == '~')
748    ERROR("ASCII85 string not supported yet.");
749  else if (**inbuf == '<')
750    return pst_new_obj(PST_TYPE_STRING, pst_string_parse_hex(inbuf, inbufend));
751  return NULL;
752}
753
754static pst_string *
755pst_string_parse_literal (unsigned char **inbuf, unsigned char *inbufend)
756{
757  unsigned char  wbuf[PST_STRING_LEN_MAX];
758  unsigned char *cur = *inbuf, c = 0;
759  long    len = 0, balance = 1;
760
761  if (cur + 2 > inbufend || *cur != '(')
762    return NULL;
763
764  cur++;
765  while (cur < inbufend && len < PST_STRING_LEN_MAX && balance > 0) {
766    c = *(cur++);
767    switch (c) {
768    case '\\':
769      {
770	unsigned char unescaped, valid;
771	unescaped = esctouc(&cur, inbufend, &valid);
772	if (valid)
773	  wbuf[len++] = unescaped;
774      }
775      break;
776    case '(':
777      balance++;
778      wbuf[len++] = '(';
779      break;
780    case ')':
781      balance--;
782      if (balance > 0)
783	wbuf[len++] = ')';
784      break;
785      /*
786       * An end-of-line marker (\n, \r or \r\n), not preceeded by a backslash,
787       * must be converted to single \n.
788       */
789    case '\r':
790      if (cur < inbufend && *cur == '\n')
791	cur++;
792      wbuf[len++] = '\n';
793      break;
794    default:
795      wbuf[len++] = c;
796    }
797  }
798  if (c != ')')
799    return NULL;
800
801  *inbuf  = cur;
802  return pst_string_new(wbuf, len);
803}
804
805static pst_string *
806pst_string_parse_hex (unsigned char **inbuf, unsigned char *inbufend)
807{
808  unsigned char  wbuf[PST_STRING_LEN_MAX];
809  unsigned char *cur = *inbuf;
810  unsigned long  len = 0;
811
812  if (cur + 2 > inbufend || *cur != '<' ||
813      (*cur == '<' && *(cur+1) == '<'))
814    return NULL;
815
816  cur++;
817  /* PDF Reference does not specify how to treat invalid char */  
818  while (cur < inbufend && len < PST_STRING_LEN_MAX) {
819    int    hi, lo;
820    skip_white_spaces(&cur, inbufend);
821    if (*cur == '>')
822      break;
823    hi = xtoi(*(cur++));
824    if (hi < 0) {
825      WARN("Invalid char for hex string <%x> treated as <0>.", *(cur-1));
826      hi = 0;
827    }
828    skip_white_spaces(&cur, inbufend);
829    if (*cur == '>')
830      break;
831    /* 0 is appended if final hex digit is missing */
832    lo = (cur < inbufend) ? xtoi(*(cur++)) : 0;
833    if (lo < 0) {
834      WARN("Invalid char for hex string <%x> treated as <0>.", *(cur-1));
835      lo = 0;
836    }
837    wbuf[len++] = (hi << 4) | lo;
838  }
839  if (*cur++ != '>')
840    return NULL;
841
842  *inbuf = cur;
843  return pst_string_new(wbuf, len);
844}
845
846static long
847pst_string_IV (pst_string *obj)
848{
849  return (long) pst_string_RV(obj);
850}
851
852static double
853pst_string_RV (pst_string *obj)
854{
855  pst_obj *nobj;
856  unsigned char  *p, *end;
857  double   rv;
858
859  ASSERT(obj);
860  p   = obj->value;
861  end = p + obj->length;
862  nobj = pst_parse_number(&p, end);
863  if (nobj == NULL || p != end)
864    ERROR("Cound not convert string to real value.");
865  rv = pst_getRV(nobj);
866  pst_release_obj(nobj);
867
868  return rv;
869}
870
871static unsigned char *
872pst_string_SV (pst_string *obj)
873{
874  unsigned char *str = NULL;
875  ASSERT(obj);
876  str = NEW(obj->length + 1, unsigned char);
877  memcpy(str, obj->value, obj->length);
878  str[obj->length] = '\0';
879  return str;
880}
881
882static void *
883pst_string_data_ptr (pst_string *obj)
884{
885  ASSERT(obj);
886  return obj->value;
887}
888
889static unsigned int
890pst_string_length (pst_string *obj)
891{
892  ASSERT(obj);
893  return obj->length;
894}