summaryrefslogtreecommitdiff
path: root/src/pdflib/pdcore/pc_core.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/pdflib/pdcore/pc_core.c')
-rw-r--r--src/pdflib/pdcore/pc_core.c1190
1 files changed, 1190 insertions, 0 deletions
diff --git a/src/pdflib/pdcore/pc_core.c b/src/pdflib/pdcore/pc_core.c
new file mode 100644
index 0000000..4617aec
--- /dev/null
+++ b/src/pdflib/pdcore/pc_core.c
@@ -0,0 +1,1190 @@
+/*---------------------------------------------------------------------------*
+ | PDFlib - A library for generating PDF on the fly |
+ +---------------------------------------------------------------------------+
+ | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. |
+ +---------------------------------------------------------------------------+
+ | |
+ | This software is subject to the PDFlib license. It is NOT in the |
+ | public domain. Extended versions and commercial licenses are |
+ | available, please check http://www.pdflib.com. |
+ | |
+ *---------------------------------------------------------------------------*/
+
+/* $Id: pc_core.c,v 1.1 2008/10/17 06:10:43 scuri Exp $
+ *
+ * PDFlib core services
+ *
+ */
+
+#include "pc_util.h"
+#include "pc_string.h"
+#include "pc_ctype.h"
+
+#define PDF_UnknownError 12
+
+#if defined(__ia64__) && defined (__linux__)
+#define PDC_ALIGN16
+#endif
+
+/* TODO: how to make this dynamic?
+** exception during pdc_core_init():
+** - out of memory in pdc_bs_new()
+*/
+#define PDC_ERRPARM_SIZE 2048
+#define PDC_ERRBUF_SIZE (5 * PDC_ERRPARM_SIZE)
+#define PDC_XSTACK_INISIZE 10
+
+#define PDC_CLASSLIST_SIZE 32
+
+#define N_ERRTABS (PDC_ET_LAST / 1000)
+
+/* temporary free store.
+*/
+typedef struct
+{
+ void * mem;
+ pdc_destructor destr;
+ void * opaque;
+} pdc_tmpmem;
+
+typedef struct
+{
+ pdc_tmpmem * tmpmem;
+ int capacity;
+ int size;
+} pdc_tmpmem_list;
+
+
+/* exception handling frame.
+*/
+typedef struct
+{
+ pdc_jmpbuf jbuf;
+} pdc_xframe;
+
+typedef struct
+{
+ const pdc_error_info * ei;
+ int n_entries;
+} error_table;
+
+
+/* ------------------------ the core private structure ---------------------- */
+
+struct pdc_core_priv_s
+{
+ /* ------------ try/catch ------------ */
+ pdc_xframe * x_stack;
+#ifdef PDC_ALIGN16
+ char * x_alias;
+#endif
+ int x_ssize;
+ int x_sp; /* exception stack pointer */
+ int x_sp0; /* exception stack pointer at */
+ /* the time of pdc_enter_api() */
+
+ /* ------------ error handling ------------ */
+ pdc_bool in_error;
+ char * premsg;
+ char errbuf[PDC_ERRBUF_SIZE];
+ char errparms[4][PDC_ERRPARM_SIZE];
+ int epcount;
+ int errnum;
+ pdc_bool x_thrown; /* exception thrown and not caught */
+ char apiname[32];
+ pdc_error_fp errorhandler; /* client error handler */
+ void * opaque; /* client specific, opaque data */
+
+ error_table err_tables[N_ERRTABS];
+
+#ifdef PDC_DEBUG
+ pdc_bool hexdump; /* hexdump feature enabled? */
+#endif /* PDC_DEBUG */
+
+ /* ------------ memory management ------------ */
+ pdc_alloc_fp allocproc;
+ pdc_realloc_fp reallocproc;
+ pdc_free_fp freeproc;
+ pdc_tmpmem_list tm_list;
+};
+
+
+/* ----------- default memory management & error handling ----------- */
+
+static void *
+default_malloc(void *opaque, size_t size, const char *caller)
+{
+ (void) opaque;
+ (void) caller;
+
+ return malloc(size);
+}
+
+static void *
+default_realloc(void *opaque, void *mem, size_t size, const char *caller)
+{
+ (void) opaque;
+ (void) caller;
+
+ return realloc(mem, size);
+}
+
+static void
+default_free(void *opaque, void *mem)
+{
+ (void) opaque;
+
+ free(mem);
+}
+
+static void
+default_errorhandler(void *opaque, int errnum, const char *msg)
+{
+ (void) opaque;
+ (void) errnum;
+
+ fprintf(stderr, "fatal exception: %s\n", msg);
+ exit(99);
+}
+
+pdc_bool
+pdc_enter_api(pdc_core *pdc, const char *apiname)
+{
+ char *name = NULL;
+
+ if (pdc->pr->in_error)
+ return pdc_false;
+
+ if (pdc->objorient)
+ name = (char *) strchr(apiname, '_');
+ if (name)
+ name++;
+ else
+ name = (char *) apiname;
+ if (name[0] == '\n')
+ name++;
+
+ strcpy(pdc->pr->apiname, name);
+
+ if (pdc->binding != NULL)
+ {
+ size_t len = strlen(pdc->pr->apiname);
+ len--;
+ if (len && pdc->pr->apiname[len] == '2')
+ pdc->pr->apiname[len] = 0;
+ }
+
+ pdc->pr->errnum = 0;
+ pdc->pr->x_sp0 = pdc->pr->x_sp;
+ return pdc_true;
+}
+
+pdc_bool
+pdc_in_error(pdc_core *pdc)
+{
+ return pdc->pr->in_error;
+}
+
+
+/* --------------------- error table management --------------------- */
+
+static pdc_error_info core_errors[] =
+{
+#define pdc_genInfo 1
+#include "pc_generr.h"
+};
+
+#define N_CORE_ERRORS (sizeof core_errors / sizeof (pdc_error_info))
+
+
+static void
+pdc_panic(pdc_core *pdc, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ pdc_vsnprintf(pdc->pr->errbuf, PDC_ERRPARM_SIZE, fmt, ap);
+ va_end(ap);
+
+ (*pdc->pr->errorhandler)(pdc->pr->opaque, PDF_UnknownError,
+ pdc->pr->errbuf);
+} /* pdc_panic */
+
+
+static void
+check_parms(pdc_core *pdc, const pdc_error_info *ei)
+{
+ const char *msg = ei->errmsg;
+ const char *dollar;
+
+ while ((dollar = strchr(msg, '$')) != (char *) 0)
+ {
+ if (pdc_isdigit(dollar[1]))
+ {
+ int n = dollar[1] - '0';
+
+ if (ei->nparms < n || n < 1)
+ pdc_panic(pdc, "illegal parameter '$%d' in error message %d",
+ n, ei->errnum);
+ }
+ else if (dollar[1] != '$')
+ {
+ pdc_panic(pdc,
+ "illegal '$' in error message %d", ei->errnum);
+ }
+
+ msg = dollar + 1;
+ }
+} /* check_parms */
+
+
+void
+pdc_register_errtab(
+ pdc_core *pdc,
+ int et,
+ const pdc_error_info *ei,
+ int n_entries)
+{
+ int i;
+ int n = (et / 1000) - 1;
+
+ if (n < 0 || N_ERRTABS <= n || et % 1000 != 0)
+ pdc_panic(pdc, "tried to register unknown error table %d", et);
+
+ /* ignore multiple registrations of the same table.
+ */
+ if (pdc->pr->err_tables[n].ei != (pdc_error_info *) 0)
+ return;
+
+ pdc->pr->err_tables[n].ei = ei;
+ pdc->pr->err_tables[n].n_entries = n_entries;
+
+ check_parms(pdc, &ei[0]);
+
+ for (i = 1; i < n_entries; ++i)
+ {
+ if (ei[i].errnum <= ei[i-1].errnum)
+ {
+ pdc_panic(pdc,
+ "duplicate or misplaced error number %d", ei[i].errnum);
+ }
+
+ /* an error table may span several blocks.
+ */
+ if ((ei[i].errnum / 1000) - 1 > n)
+ {
+ pdc->pr->err_tables[n].n_entries = i; /* correct old block size */
+
+ n = (ei[i].errnum / 1000) - 1; /* new block number */
+
+ if (N_ERRTABS <= n)
+ pdc_panic(pdc, "invalid error number %d", ei[i].errnum);
+
+ ei += i; /* start of new block */
+ n_entries -= i; /* size of new block */
+ i = 0;
+ pdc->pr->err_tables[n].ei = ei;
+ pdc->pr->err_tables[n].n_entries = n_entries;
+ }
+
+ check_parms(pdc, &ei[i]);
+ }
+} /* pdc_register_errtab */
+
+
+/* pdc_new_core() never throws exceptions.
+** it returns NULL if there's not enough memory.
+*/
+pdc_core *
+pdc_new_core(
+ pdc_error_fp errorhandler,
+ pdc_alloc_fp allocproc,
+ pdc_realloc_fp reallocproc,
+ pdc_free_fp freeproc,
+ void *opaque,
+ const char *prodname,
+ const char *version)
+{
+ static const char fn[] = "pdc_new_core";
+
+ pdc_core_priv *pdc_pr;
+ pdc_core *pdc;
+ int i;
+
+ /* if allocproc is NULL, we use pdc's default memory handling.
+ */
+ if (allocproc == (pdc_alloc_fp) 0)
+ {
+ allocproc = default_malloc;
+ reallocproc = default_realloc;
+ freeproc = default_free;
+ }
+
+ if (errorhandler == (pdc_error_fp) 0)
+ errorhandler = default_errorhandler;
+
+ pdc_pr = (pdc_core_priv *)
+ (*allocproc)(opaque, sizeof (pdc_core_priv), fn);
+
+ if (pdc_pr == (pdc_core_priv *) 0)
+ return (pdc_core *) 0;
+
+ pdc = (pdc_core *)
+ (*allocproc)(opaque, sizeof (pdc_core), fn);
+
+ if (pdc == (pdc_core *) 0)
+ return (pdc_core *) 0;
+
+ pdc->pr = pdc_pr;
+
+ /* initialize client members
+ */
+ pdc->reslist = NULL;
+ pdc->filesystem = NULL;
+ pdc->logg = NULL;
+ pdc->loggenv = pdc_false;
+ pdc->encstack = NULL;
+ pdc->pglyphtab = NULL;
+ pdc->bstr_pool = NULL;
+ pdc->ustr_pool = NULL;
+ pdc->last_rand = 1;
+ pdc->prodname = prodname;
+ pdc->version = version;
+ pdc->binding = NULL;
+ pdc->unicaplang = pdc_false;
+ pdc->objorient = pdc_false;
+ pdc->hastobepos = pdc_false;
+ pdc->ptfrun = pdc_false;
+ pdc->smokerun = pdc_false;
+ pdc->charref = pdc_false;
+ pdc->escapesequ = pdc_false;
+ pdc->honorlang = pdc_false;
+ pdc->compatibility = PDC_X_X_LAST;
+ pdc->floatdigits = 4;
+ pdc->uniqueno = 0;
+
+
+#ifdef PDC_DEBUG
+ pdc->pr->hexdump = pdc_true;
+#endif
+
+ /* set diverse handlers
+ */
+ pdc->pr->errorhandler = errorhandler;
+ pdc->pr->allocproc = allocproc;
+ pdc->pr->reallocproc = reallocproc;
+ pdc->pr->freeproc = freeproc;
+ pdc->pr->opaque = opaque;
+
+ /* initialize error & exception handling.
+ */
+ pdc->pr->in_error = pdc_false;
+ pdc->pr->x_thrown = pdc_false;
+ pdc->pr->epcount = 0;
+ pdc->pr->errnum = 0;
+ pdc->pr->premsg = NULL;
+ pdc->pr->apiname[0] = 0;
+ pdc->pr->x_sp = -1;
+ pdc->pr->x_ssize = PDC_XSTACK_INISIZE;
+
+#ifdef PDC_ALIGN16
+ pdc->pr->x_alias = (char *)
+ (*allocproc)(opaque, 16 + pdc->pr->x_ssize * sizeof (pdc_xframe), fn);
+
+ if (pdc->pr->x_alias == (char *) 0)
+ pdc->pr->x_stack = (pdc_xframe *) 0;
+ else
+ pdc->pr->x_stack = (pdc_xframe *)
+ (((unsigned long) pdc->pr->x_alias + 16) & 0xFFFFFFFFFFFFFFF0);
+#else
+ pdc->pr->x_stack = (pdc_xframe *)
+ (*allocproc)(opaque, pdc->pr->x_ssize * sizeof (pdc_xframe), fn);
+#endif
+
+ if (pdc->pr->x_stack == (pdc_xframe *) 0)
+ {
+ (*freeproc)(opaque, pdc);
+ return (pdc_core *) 0;
+ }
+
+ pdc_tmlist_init(pdc);
+
+ /* initialize error tables.
+ */
+ for (i = 0; i < N_ERRTABS; ++i)
+ pdc->pr->err_tables[i].ei = (pdc_error_info *) 0;
+
+ pdc_register_errtab(pdc, PDC_ET_CORE, core_errors, N_CORE_ERRORS);
+ pdc_init_strings(pdc);
+
+ return pdc;
+}
+
+void
+pdc_delete_core(pdc_core *pdc)
+{
+ pdc_free_fp freeproc = pdc->pr->freeproc;
+ void *opaque = pdc->pr->opaque;
+ pdc_time ltime;
+
+ pdc_localtime(&ltime);
+ pdc_logg(pdc, "[%04d-%02d-%02d %02d:%02d:%02d]\n",
+ ltime.year + 1900, ltime.month + 1, ltime.mday,
+ ltime.hour, ltime.minute, ltime.second);
+
+ pdc_delete_reslist(pdc);
+ pdc_delete_filesystem(pdc);
+ pdc_delete_encodingstack(pdc);
+ pdc_delete_pglyphtab(pdc);
+
+ pdc_cleanup_strings(pdc);
+
+ if (pdc->binding)
+ pdc_free(pdc, pdc->binding);
+
+ pdc_pop_errmsg(pdc);
+
+ pdc_tmlist_cleanup(pdc);
+
+ if (pdc->pr->tm_list.capacity != 0)
+ pdc_free(pdc, pdc->pr->tm_list.tmpmem);
+
+#ifdef PDC_ALIGN16
+ pdc_free(pdc, pdc->pr->x_alias);
+#else
+ pdc_free(pdc, pdc->pr->x_stack);
+#endif
+
+ pdc_delete_logg(pdc);
+
+ (*freeproc)(opaque, pdc->pr);
+ (*freeproc)(opaque, pdc);
+}
+
+/* --------------------------- memory management --------------------------- */
+
+void *
+pdc_malloc(pdc_core *pdc, size_t size, const char *caller)
+{
+ void *ret;
+ pdc_bool logg1 = pdc_logg_is_enabled(pdc, 1, trc_memory);
+
+ if (logg1)
+ pdc_logg(pdc, "\ttry to malloc %ld bytes\n", size);
+
+
+ /* the behavior of malloc(0) is undefined in ANSI C, and may
+ * result in a NULL pointer return value which makes PDFlib bail out.
+ */
+ if (size == (size_t) 0 || (long) size < 0L) {
+ size = (size_t) 1;
+ pdc_error(pdc, PDC_E_INT_ALLOC0, caller, 0, 0, 0);
+ }
+
+ if ((ret = (*pdc->pr->allocproc)(pdc->pr->opaque, size, caller)) ==
+ (void *) 0)
+ {
+ pdc_error(pdc, PDC_E_MEM_OUT, caller, 0, 0, 0);
+ }
+
+ if (logg1)
+ pdc_logg(pdc, "\t%p malloced, size=%ld, called from \"%s\"\n",
+ ret, size, caller);
+
+ return ret;
+}
+
+/* We cook up our own calloc routine, using the caller-supplied
+ * malloc and memset.
+ */
+void *
+pdc_calloc(pdc_core *pdc, size_t size, const char *caller)
+{
+ void *ret;
+ pdc_bool logg1 = pdc_logg_is_enabled(pdc, 1, trc_memory);
+
+ if (logg1)
+ pdc_logg(pdc, "\ttry to calloc %ld bytes\n", size);
+
+ if (size == (size_t) 0 || (long) size < 0L) {
+ size = (size_t) 1;
+ pdc_error(pdc, PDC_E_INT_ALLOC0, caller, 0, 0, 0);
+ }
+
+ if ((ret = (*pdc->pr->allocproc)(pdc->pr->opaque, size, caller)) ==
+ (void *) 0)
+ {
+ pdc_error(pdc, PDC_E_MEM_OUT, caller, 0, 0, 0);
+ }
+
+ if (logg1)
+ pdc_logg(pdc, "\t%p calloced, size=%ld, called from \"%s\"\n",
+ ret, size, caller);
+
+ memset(ret, 0, size);
+ return ret;
+}
+
+void *
+pdc_realloc(pdc_core *pdc, void *mem, size_t size, const char *caller)
+{
+ void *ret;
+ pdc_bool logg1 = pdc_logg_is_enabled(pdc, 1, trc_memory);
+
+ if (logg1)
+ pdc_logg(pdc, "\ttry to realloc %p to %ld bytes\n", mem, size);
+
+ if (size == (size_t) 0 || (long) size < 0L) {
+ size = (size_t) 1;
+ pdc_error(pdc, PDC_E_INT_ALLOC0, caller, 0, 0, 0);
+ }
+
+ ret = (mem == (void *) 0) ?
+ (*pdc->pr->allocproc)(pdc->pr->opaque, size, caller) :
+ (*pdc->pr->reallocproc)(pdc->pr->opaque, mem, size, caller);
+
+ if (ret == (void *) 0)
+ pdc_error(pdc, PDC_E_MEM_OUT, caller, 0, 0, 0);
+
+ pdc_logg_cond(pdc, 1, trc_memory,
+ "\t%p realloced to\n"
+ "\t%p new, size=%ld, called from \"%s\"\n",
+ mem, ret, size, caller);
+
+ return ret;
+}
+
+void
+pdc_free(pdc_core *pdc, void *mem)
+{
+ pdc_logg_cond(pdc, 1, trc_memory, "\t%p freed\n", mem);
+
+ /* just in case the freeproc() isn't that ANSI compatible...
+ */
+ if (mem != NULL)
+ (*pdc->pr->freeproc)(pdc->pr->opaque, mem);
+}
+
+/* -------------------- temporary free store management -------------------- */
+
+void
+pdc_tmlist_init(pdc_core *pdc)
+{
+ pdc->pr->tm_list.size = pdc->pr->tm_list.capacity = 0;
+}
+
+static void
+pdc_tmlist_grow(pdc_core *pdc)
+{
+ static const char fn[] = "pdc_tmlist_grow";
+ pdc_tmpmem_list *tm_list = &pdc->pr->tm_list;
+ static const int chunksize = 20;
+
+ if (tm_list->capacity == 0)
+ {
+ tm_list->capacity = chunksize;
+ tm_list->tmpmem = (pdc_tmpmem *) pdc_malloc(pdc,
+ (size_t) (tm_list->capacity * sizeof (pdc_tmpmem)), fn);
+ }
+ else
+ {
+ tm_list->capacity += chunksize;
+ tm_list->tmpmem = (pdc_tmpmem *) pdc_realloc(pdc, tm_list->tmpmem,
+ (size_t) (tm_list->capacity * sizeof (pdc_tmpmem)), fn);
+ }
+}
+
+void
+pdc_tmlist_cleanup(pdc_core *pdc)
+{
+ pdc_tmpmem_list *tm_list = &pdc->pr->tm_list;
+ int i;
+
+ for (i = 0; i < tm_list->size; ++i)
+ {
+ if (tm_list->tmpmem[i].destr)
+ tm_list->tmpmem[i].destr(tm_list->tmpmem[i].opaque,
+ tm_list->tmpmem[i].mem);
+
+ pdc_free(pdc, tm_list->tmpmem[i].mem);
+ }
+
+ tm_list->size = 0;
+}
+
+void
+pdc_insert_mem_tmp(
+ pdc_core * pdc,
+ void * memory,
+ void * opaque,
+ pdc_destructor destr)
+{
+ pdc_tmpmem_list *tm_list = &pdc->pr->tm_list;
+
+ if (tm_list->size == tm_list->capacity)
+ pdc_tmlist_grow(pdc);
+
+ pdc_logg_cond(pdc, 2, trc_memory,
+ "\tTemporary memory %p was created\n", memory);
+
+ tm_list->tmpmem[tm_list->size].mem = memory;
+ tm_list->tmpmem[tm_list->size].destr = destr;
+ tm_list->tmpmem[tm_list->size].opaque = opaque;
+ ++tm_list->size;
+}
+
+void *
+pdc_malloc_tmp(
+ pdc_core * pdc,
+ size_t size,
+ const char * caller,
+ void * opaque,
+ pdc_destructor destr)
+{
+ void *memory = pdc_malloc(pdc, size, caller);
+
+ pdc_insert_mem_tmp(pdc, memory, opaque, destr);
+
+ return memory;
+}
+
+void *
+pdc_calloc_tmp(
+ pdc_core * pdc,
+ size_t size,
+ const char * caller,
+ void * opaque,
+ pdc_destructor destr)
+{
+ void *memory = pdc_calloc(pdc, size, caller);
+
+ pdc_insert_mem_tmp(pdc, memory, opaque, destr);
+
+ return memory;
+}
+
+void *
+pdc_realloc_tmp(pdc_core *pdc, void *mem, size_t size, const char *caller)
+{
+ pdc_tmpmem_list *tm_list = &pdc->pr->tm_list;
+ int i;
+
+ for (i = tm_list->size - 1; 0 <= i; --i)
+ if (tm_list->tmpmem[i].mem == mem)
+ return tm_list->tmpmem[i].mem = pdc_realloc(pdc, mem, size, caller);
+
+ pdc_error(pdc, PDC_E_INT_REALLOC_TMP, caller, 0, 0, 0);
+ return (void *) 0;
+}
+
+void
+pdc_free_tmp(pdc_core *pdc, void *mem)
+{
+ pdc_tmpmem_list *tm_list = &pdc->pr->tm_list;
+ int i, j;
+
+ pdc_logg_cond(pdc, 2, trc_memory,
+ "\tTemporary memory %p to be freed\n", mem);
+
+ /* we search the list backwards since chances are good
+ ** that the most recently allocated items are freed first.
+ */
+ for (i = tm_list->size - 1; 0 <= i; --i)
+ {
+ if (tm_list->tmpmem[i].mem == mem)
+ {
+ if (tm_list->tmpmem[i].destr)
+ tm_list->tmpmem[i].destr(
+ tm_list->tmpmem[i].opaque, tm_list->tmpmem[i].mem);
+
+ pdc_free(pdc, tm_list->tmpmem[i].mem);
+ tm_list->tmpmem[i].mem = (void *) 0;
+
+ --tm_list->size;
+ for (j = i; j < tm_list->size; j++)
+ tm_list->tmpmem[j] = tm_list->tmpmem[j + 1];
+
+ return;
+ }
+ }
+
+ pdc_error(pdc, PDC_E_INT_FREE_TMP, 0, 0, 0, 0);
+}
+
+
+/* --------------------------- exception handling --------------------------- */
+
+const char *pdc_errprintf(pdc_core *pdc, const char *fmt, ...)
+{
+ va_list ap;
+
+ if (pdc->pr->epcount < 0 || pdc->pr->epcount > 3)
+ pdc->pr->epcount = 0;
+
+ va_start(ap, fmt);
+ pdc_vsnprintf(pdc->pr->errparms[pdc->pr->epcount], PDC_ERRPARM_SIZE,
+ fmt, ap);
+ va_end(ap);
+
+ return pdc->pr->errparms[pdc->pr->epcount++];
+}
+
+static const pdc_error_info *
+get_error_info(pdc_core *pdc, int errnum)
+{
+ int n = (errnum / 1000) - 1;
+
+ if (0 <= n && n < N_ERRTABS && pdc->pr->err_tables[n].ei != 0)
+ {
+ error_table *etab = &pdc->pr->err_tables[n];
+ int i;
+
+ /* LATER: binary search. */
+ for (i = 0; i < etab->n_entries; ++i)
+ {
+ if (etab->ei[i].errnum == errnum)
+ return &etab->ei[i];
+ }
+ }
+
+ pdc_panic(pdc, "Internal error: unknown error number %d", errnum);
+
+ return (pdc_error_info *) 0; /* for the compiler */
+} /* get_error_info */
+
+
+static void
+make_errmsg(
+ pdc_core * pdc,
+ const pdc_error_info *ei,
+ const char * parm1,
+ const char * parm2,
+ const char * parm3,
+ const char * parm4,
+ pdc_bool popmsg)
+{
+ const char *src = ei->ce_msg ? ei->ce_msg : ei->errmsg;
+ char * dst = pdc->pr->errbuf;
+ const char *dollar;
+
+ if (pdc->pr->premsg != NULL)
+ {
+ strcpy(dst, pdc->pr->premsg);
+ dst += strlen(pdc->pr->premsg);
+ if (popmsg)
+ pdc_pop_errmsg(pdc);
+ }
+
+ pdc->pr->epcount = 0;
+
+ /* copy *src to *dst, replacing "$N" with *parmN.
+ */
+ while ((dollar = strchr(src, '$')) != (char *) 0)
+ {
+ const char *parm = (const char *) 0;
+
+ memcpy(dst, src, (size_t) (dollar - src));
+ dst += dollar - src;
+ src = dollar + 1;
+
+ switch (*src)
+ {
+ case '1': parm = (parm1 ? parm1 : "?"); break;
+ case '2': parm = (parm2 ? parm2 : "?"); break;
+ case '3': parm = (parm3 ? parm3 : "?"); break;
+ case '4': parm = (parm4 ? parm4 : "?"); break;
+
+ case 0: break;
+
+ default: *(dst++) = *(src++);
+ break;
+ }
+
+ if (parm != (const char *) 0)
+ {
+ ++src;
+ strcpy(dst, parm);
+ dst += strlen(parm);
+ }
+ }
+
+ strcpy(dst, src);
+
+} /* make_errmsg */
+
+void
+pdc_pop_errmsg(pdc_core *pdc)
+{
+ if (pdc->pr->premsg)
+ {
+ pdc_free(pdc, pdc->pr->premsg);
+ pdc->pr->premsg = NULL;
+ }
+} /* pdc_pop_errmsg */
+
+void
+pdc_push_errmsg(
+ pdc_core * pdc,
+ int errnum,
+ const char *parm1,
+ const char *parm2,
+ const char *parm3,
+ const char *parm4)
+{
+ static const char fn[] = "pdc_push_errmsg";
+ const pdc_error_info *ei = get_error_info(pdc, errnum);
+
+ pdc_pop_errmsg(pdc);
+
+ make_errmsg(pdc, ei, parm1, parm2, parm3, parm4, pdc_false);
+
+ pdc->pr->premsg = pdc_strdup_ext(pdc, pdc->pr->errbuf, 0, fn);
+
+} /* pdc_push_errmsg */
+
+void
+pdc_set_errmsg(
+ pdc_core * pdc,
+ int errnum,
+ const char *parm1,
+ const char *parm2,
+ const char *parm3,
+ const char *parm4)
+{
+ const pdc_error_info *ei = get_error_info(pdc, errnum);
+
+ make_errmsg(pdc, ei, parm1, parm2, parm3, parm4, pdc_false);
+
+ pdc->pr->errnum = errnum;
+
+ pdc_logg_cond(pdc, 2, trc_warning,
+ "[Reason for error message %d: \"%s\"]\n",
+ pdc->pr->errnum, pdc->pr->errbuf);
+
+} /* pdc_set_errmsg */
+
+void
+pdc_set_warnmsg(
+ pdc_core * pdc,
+ int errnum,
+ const char *parm1,
+ const char *parm2,
+ const char *parm3,
+ const char *parm4)
+{
+ char errbuf[PDC_ERRBUF_SIZE];
+
+ strcpy(errbuf, pdc->pr->errbuf);
+
+ if (errnum != -1)
+ {
+ const pdc_error_info *ei = get_error_info(pdc, errnum);
+
+ make_errmsg(pdc, ei, parm1, parm2, parm3, parm4, pdc_false);
+ }
+
+ pdc_logg_cond(pdc, 1, trc_warning,
+ "\n[Warning message %d: \"%s\"]\n",
+ errnum, pdc->pr->errbuf);
+
+ strcpy(pdc->pr->errbuf, errbuf);
+
+} /* pdc_set_warnmsg */
+
+
+void
+pdc_error(
+ pdc_core * pdc,
+ int errnum,
+ const char *parm1,
+ const char *parm2,
+ const char *parm3,
+ const char *parm4)
+{
+ const char *logmsg;
+
+ /* avoid recursive errors, but allow rethrow.
+ */
+ if (errnum != -1 && pdc->pr->in_error)
+ return;
+
+ pdc->pr->in_error = pdc_true;
+ pdc->pr->x_thrown = pdc_true;
+
+ if (errnum != -1)
+ {
+ const pdc_error_info *ei = get_error_info(pdc, errnum);
+
+ make_errmsg(pdc, ei, parm1, parm2, parm3, parm4, pdc_true);
+ pdc->pr->errnum = errnum;
+ }
+
+ if (pdc->pr->x_sp > pdc->pr->x_sp0)
+ {
+ logmsg = "\n[/// Exception %d in %s ]";
+ }
+ else
+ {
+ logmsg = "\n[+++ Exception %d in %s ]";
+ }
+
+ pdc_logg(pdc, logmsg, pdc->pr->errnum,
+ (pdc->pr->errnum == 0 || !pdc->pr->apiname) ? "" : pdc->pr->apiname,
+ pdc->pr->x_sp0 + 1, pdc->pr->x_sp - pdc->pr->x_sp0);
+
+ pdc_logg(pdc, "[\"%s\"]\n\n", pdc->pr->errbuf);
+
+ if (pdc->pr->x_sp == -1)
+ {
+ char errbuf[PDC_ERRBUF_SIZE];
+ const char *apiname = pdc_get_apiname(pdc);
+ const char *errmsg = pdc->pr->errbuf;
+
+ if (strlen(apiname))
+ {
+ sprintf(errbuf, "[%d] %s: %s", pdc->pr->errnum, apiname, errmsg);
+ errmsg = errbuf;
+ }
+
+ (*pdc->pr->errorhandler)(pdc->pr->opaque, PDF_UnknownError, errmsg);
+
+ /*
+ * The error handler must never return. If it does, it is severely
+ * broken. We cannot remedy this, so we exit.
+ */
+ exit(99);
+
+ }
+ else
+ {
+ longjmp(pdc->pr->x_stack[pdc->pr->x_sp].jbuf.jbuf, 1);
+ }
+
+} /* pdc_error */
+
+pdc_jmpbuf *
+pdc_jbuf(pdc_core *pdc)
+{
+ static const char fn[] = "pdc_jbuf";
+
+ if (++pdc->pr->x_sp == pdc->pr->x_ssize)
+ {
+ pdc_xframe *aux;
+
+#ifdef PDC_ALIGN16
+ char *cp = (char *) (*pdc->pr->allocproc)(pdc->pr->opaque,
+ 16 + 2 * pdc->pr->x_ssize * sizeof (pdc_xframe), fn);
+
+ if (cp == (char *) 0)
+ {
+ aux = (pdc_xframe *) 0;
+ }
+ else
+ {
+ /* remember the pointer in order to free it only after the memcpy
+ * below, as pdc->pr->x_stack points into the memory allocated
+ * to pdc->pr->x_alias
+ */
+ char *free_me_later = pdc->pr->x_alias;
+ pdc->pr->x_alias = cp;
+ aux = (pdc_xframe *)
+ (((unsigned long) cp + 16) & 0xFFFFFFFFFFFFFFF0);
+
+ memcpy(aux, pdc->pr->x_stack,
+ pdc->pr->x_ssize * sizeof (pdc_xframe));
+ pdc_free(pdc, free_me_later);
+ }
+#else
+ aux = (pdc_xframe *) (*pdc->pr->reallocproc)(
+ pdc->pr->opaque, pdc->pr->x_stack,
+ 2 * pdc->pr->x_ssize * sizeof (pdc_xframe), fn);
+#endif
+
+ if (aux == (pdc_xframe *) 0)
+ {
+ --pdc->pr->x_sp;
+ pdc->pr->x_thrown = pdc_true;
+ pdc->pr->in_error = pdc_true;
+
+ pdc->pr->errnum = PDC_E_MEM_OUT;
+ pdc->pr->apiname[0] = 0;
+ sprintf(pdc->pr->errbuf,
+ "Out of memory in TRY function (nesting level: %d)",
+ pdc->pr->x_sp + 1);
+
+ longjmp(pdc->pr->x_stack[pdc->pr->x_sp].jbuf.jbuf, 1);
+ }
+
+ pdc->pr->x_stack = aux;
+ pdc->pr->x_ssize *= 2;
+ }
+
+ pdc->pr->x_thrown = pdc_false;
+ return &pdc->pr->x_stack[pdc->pr->x_sp].jbuf;
+} /* pdc_jbuf */
+
+void
+pdc_exit_try(pdc_core *pdc)
+{
+ if (pdc->pr->x_sp == -1)
+ {
+ strcpy(pdc->pr->errbuf, "exception stack underflow");
+ pdc->pr->errnum = PDC_E_INT_XSTACK;
+ (*pdc->pr->errorhandler)(pdc->pr->opaque, PDF_UnknownError,
+ pdc->pr->errbuf);
+ }
+ else
+ --pdc->pr->x_sp;
+} /* pdc_exit_try */
+
+int
+pdc_catch_intern(pdc_core *pdc)
+{
+ pdc_bool result;
+
+ if (pdc->pr->x_sp == -1)
+ {
+ strcpy(pdc->pr->errbuf, "exception stack underflow");
+ pdc->pr->errnum = PDC_E_INT_XSTACK;
+ (*pdc->pr->errorhandler)(pdc->pr->opaque, PDF_UnknownError,
+ pdc->pr->errbuf);
+ }
+ else
+ --pdc->pr->x_sp;
+
+ result = pdc->pr->x_thrown;
+ pdc->pr->in_error = pdc_false;
+ pdc->pr->x_thrown = pdc_false;
+
+ return result;
+} /* pdc_catch_intern */
+
+int
+pdc_catch_extern(pdc_core *pdc)
+{
+ pdc_bool result;
+
+ if (pdc->pr->x_sp == -1)
+ {
+ strcpy(pdc->pr->errbuf, "exception stack underflow");
+ pdc->pr->errnum = PDC_E_INT_XSTACK;
+ (*pdc->pr->errorhandler)(pdc->pr->opaque, PDF_UnknownError,
+ pdc->pr->errbuf);
+ }
+ else
+ --pdc->pr->x_sp;
+
+ result = pdc->pr->x_thrown;
+ pdc->pr->x_thrown = pdc_false;
+
+ return result;
+} /* pdc_catch_extern */
+
+void
+pdc_rethrow(pdc_core *pdc)
+{
+ pdc_error(pdc, -1, 0, 0, 0, 0);
+} /* pdc_rethrow */
+
+
+/* this function should be called in the PDC_CATCH branch of
+** a function before it returns -1.
+*/
+void
+pdc_check_rethrow(pdc_core *pdc)
+{
+ if (pdc->pr->errnum == PDC_E_MEM_OUT)
+ pdc_error(pdc, -1, 0, 0, 0, 0);
+} /* pdc_check_rethrow */
+
+
+int
+pdc_get_errnum(pdc_core *pdc)
+{
+ return pdc->pr->errnum;
+}
+
+const char *
+pdc_get_errmsg(pdc_core *pdc)
+{
+ return (pdc->pr->errnum == 0) ? "" : pdc->pr->errbuf;
+}
+
+const char *
+pdc_get_apiname(pdc_core *pdc)
+{
+ return pdc->pr->apiname;
+}
+
+const char *
+pdc_get_errpref(pdc_core *pdc)
+{
+ return pdc->pr->premsg;
+}
+
+/* ----------- service function to get PDF version string -------------- */
+
+const char *
+pdc_get_pdfversion(pdc_core *pdc, int compatibility)
+{
+ return pdc_errprintf(pdc, "%d.%d", compatibility / 10, compatibility % 10);
+}
+
+
+#ifdef PDC_DEBUG
+
+/* --------------------------- debug hexdump --------------------------- */
+void
+pdc_enable_hexdump(pdc_core *pdc)
+{
+ pdc->pr->hexdump = pdc_true;
+}
+
+void
+pdc_disable_hexdump(pdc_core *pdc)
+{
+ pdc->pr->hexdump = pdc_false;
+}
+
+void
+pdc_hexdump(pdc_core *pdc, const char *msg, const char *text, int tlen)
+{
+ if (pdc->pr->hexdump)
+ {
+ int i, k;
+
+ if (tlen == 1)
+ {
+ printf("%s: %02X '%c'\n", msg,
+ (unsigned char) text[0],
+ pdc_isprint(text[0]) ? text[0] : '.');
+ }
+ else
+ {
+ printf("%s:\n", msg);
+
+ for (i = 0; i < tlen; i += 16)
+ {
+ for (k = 0; k < 16; ++k)
+ if (i + k < tlen)
+ printf("%02X ", (unsigned char) text[i + k]);
+ else
+ printf(" ");
+
+ printf(" ");
+ for (k = 0; k < 16; ++k)
+ if (i + k < tlen)
+ {
+ printf("%c",
+ pdc_isprint(text[i + k]) ? text[i + k] : '.');
+ }
+ else
+ printf(" ");
+
+ printf("\n");
+ }
+ }
+ }
+}
+
+#endif /* PDC_DEBUG */