Back to index

texmacs  1.0.7.15
Classes | Defines | Functions
pdfnames.c File Reference
#include <ctype.h>
#include <math.h>
#include <string.h>
#include "system.h"
#include "mem.h"
#include "error.h"
#include "numbers.h"
#include "dpxutil.h"
#include "pdfobj.h"
#include "pdfnames.h"

Go to the source code of this file.

Classes

struct  obj_data
struct  named_object

Defines

#define MAX_KEY   32
#define NAME_CLUSTER   4

Functions

char * printable_key (const char *key, int keylen)
static void CDECL hval_free (void *hval)
struct ht_tablepdf_new_name_tree (void)
static void check_objects_defined (struct ht_table *ht_tab)
void pdf_delete_name_tree (struct ht_table **names)
int pdf_names_add_object (struct ht_table *names, const void *key, int keylen, pdf_obj *object)
pdf_objpdf_names_lookup_reference (struct ht_table *names, const void *key, int keylen)
pdf_objpdf_names_lookup_object (struct ht_table *names, const void *key, int keylen)
int pdf_names_close_object (struct ht_table *names, const void *key, int keylen)
static int CDECL cmp_key (const void *d1, const void *d2)
static pdf_objbuild_name_tree (struct named_object *first, long num_leaves, int is_root)
static struct named_objectflat_table (struct ht_table *ht_tab, long *num_entries, struct ht_table *filter)
pdf_objpdf_names_create_tree (struct ht_table *names, long *count, struct ht_table *filter)

Class Documentation

struct obj_data

Definition at line 45 of file pdfnames.c.

Collaboration diagram for obj_data:
Class Members
int closed
pdf_obj * object
struct named_object

Definition at line 244 of file pdfnames.c.

Collaboration diagram for named_object:
Class Members
char * key
int keylen
pdf_obj * value

Define Documentation

#define MAX_KEY   32
#define NAME_CLUSTER   4

Definition at line 275 of file pdfnames.c.


Function Documentation

static pdf_obj* build_name_tree ( struct named_object first,
long  num_leaves,
int  is_root 
) [static]

Definition at line 277 of file pdfnames.c.

{
  pdf_obj *result;
  int      i;

  result = pdf_new_dict();
  /*
   * According to PDF Refrence, Third Edition (p.101-102), a name tree
   * always has exactly one root node, which contains a SINGLE entry:
   * either Kids or Names but not both. If the root node has a Names
   * entry, it is the only node in the tree. If it has a Kids entry,
   * then each of the remaining nodes is either an intermediate node,
   * containing a Limits entry and a Kids entry, or a leaf node,
   * containing a Limits entry and a Names entry.
   */
  if (!is_root) {
    struct named_object *last;
    pdf_obj *limits;

    limits = pdf_new_array();
    last   = &first[num_leaves - 1];
    pdf_add_array(limits, pdf_new_string(first->key, first->keylen));
    pdf_add_array(limits, pdf_new_string(last->key , last->keylen ));
    pdf_add_dict (result, pdf_new_name("Limits"),    limits);
  }

  if (num_leaves > 0 &&
      num_leaves <= 2 * NAME_CLUSTER) {
    pdf_obj *names;

    /* Create leaf nodes. */
    names = pdf_new_array();
    for (i = 0; i < num_leaves; i++) {
      struct named_object *cur;

      cur = &first[i];
      pdf_add_array(names, pdf_new_string(cur->key, cur->keylen));
      switch (PDF_OBJ_TYPEOF(cur->value)) {
      case PDF_ARRAY:
      case PDF_DICT:
      case PDF_STREAM:
      case PDF_STRING:
       pdf_add_array(names, pdf_ref_obj(cur->value));
       break;
      case PDF_OBJ_INVALID:
       ERROR("Invalid object...: %s", printable_key(cur->key, cur->keylen));
       break;
      default:
       pdf_add_array(names, pdf_link_obj(cur->value));
       break;
      }
      pdf_release_obj(cur->value);
      cur->value = NULL;
    }
    pdf_add_dict(result, pdf_new_name("Names"), names);
  } else if (num_leaves > 0) {
    pdf_obj *kids;

    /* Intermediate node */
    kids = pdf_new_array();
    for (i = 0; i < NAME_CLUSTER; i++) {
      pdf_obj *subtree;
      long     start, end;

      start = (i*num_leaves) / NAME_CLUSTER;
      end   = ((i+1)*num_leaves) / NAME_CLUSTER;
      subtree = build_name_tree(&first[start], (end - start), 0);
      pdf_add_array  (kids, pdf_ref_obj(subtree));
      pdf_release_obj(subtree);
    }
    pdf_add_dict(result, pdf_new_name("Kids"), kids);
  }

  return result;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void check_objects_defined ( struct ht_table ht_tab) [static]

Definition at line 105 of file pdfnames.c.

{
  struct ht_iter iter;

  if (ht_set_iter(ht_tab, &iter) >= 0) {
    do {
      char  *key;
      int    keylen;
      struct obj_data *value;

      key   = ht_iter_getkey(&iter, &keylen);
      value = ht_iter_getval(&iter);
      ASSERT(value->object);
      if (PDF_OBJ_UNDEFINED(value->object)) {
       pdf_names_add_object(ht_tab, key, keylen, pdf_new_null());
       WARN("Object @%s used, but not defined. Replaced by null.",
            printable_key(key, keylen));
      }
    } while (ht_iter_next(&iter) >= 0);
    ht_clear_iter(&iter);
  }
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int CDECL cmp_key ( const void *  d1,
const void *  d2 
) [static]

Definition at line 252 of file pdfnames.c.

{
  struct named_object *sd1, *sd2;
  int    keylen, cmp;

  sd1 = (struct named_object *) d1;
  sd2 = (struct named_object *) d2;

  if (!sd1->key)
    cmp = -1;
  else if (!sd2->key)
    cmp =  1;
  else {
    keylen = MIN(sd1->keylen, sd2->keylen);
    cmp    = memcmp(sd1->key, sd2->key, keylen);
    if (!cmp) {
      cmp = sd1->keylen - sd2->keylen;
    }
  }

  return cmp;
}

Here is the caller graph for this function:

static struct named_object* flat_table ( struct ht_table ht_tab,
long *  num_entries,
struct ht_table filter 
) [static, read]

Definition at line 354 of file pdfnames.c.

{
  struct named_object *objects;
  struct ht_iter       iter;
  long   count;

  ASSERT(ht_tab);

  objects = NEW(ht_tab->count, struct named_object);
  count = 0;
  if (ht_set_iter(ht_tab, &iter) >= 0) {
    do {
      char  *key;
      int    keylen;
      struct obj_data *value;

      key   = ht_iter_getkey(&iter, &keylen);

      if (filter) {
       pdf_obj *new_obj = ht_lookup_table(filter, key, keylen);

       if (!new_obj)
         continue;

       key = pdf_string_value(new_obj);
       keylen = pdf_string_length(new_obj);
      }

      value = ht_iter_getval(&iter);
      ASSERT(value->object);
      if (PDF_OBJ_UNDEFINED(value->object)) {
       WARN("Object @%s\" not defined. Replaced by null.",
            printable_key(key, keylen));
       objects[count].key    = (char *) key;
       objects[count].keylen = keylen;
       objects[count].value  = pdf_new_null();
      } else if (value->object) {
       objects[count].key    = (char *) key;
       objects[count].keylen = keylen;
       objects[count].value  = pdf_link_obj(value->object);
      }

      count++;
    } while (ht_iter_next(&iter) >= 0);
    ht_clear_iter(&iter);
  }

  *num_entries = count;
  objects = RENEW(objects, count, struct named_object);

  return objects;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void CDECL hval_free ( void *  hval) [static]

Definition at line 77 of file pdfnames.c.

{
  struct obj_data *value;

  value = (struct obj_data *) hval;

  if (value->object) {
    pdf_release_obj(value->object);
    value->object     = NULL;
  }

  RELEASE(value);

  return;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void pdf_delete_name_tree ( struct ht_table **  names)

Definition at line 129 of file pdfnames.c.

{
  ASSERT(names && *names);

  check_objects_defined(*names);

  ht_clear_table(*names);
  RELEASE(*names);
  *names = NULL;
}

Here is the call graph for this function:

Here is the caller graph for this function:

int pdf_names_add_object ( struct ht_table names,
const void *  key,
int  keylen,
pdf_obj object 
)

Definition at line 141 of file pdfnames.c.

{
  struct obj_data *value;

  ASSERT(names && object);

  if (!key || keylen < 1) {
    WARN("Null string used for name tree key.");
    return -1;
  }

  value = ht_lookup_table(names, key, keylen);
  if (!value) {
    value = NEW(1, struct obj_data);
    value->object = object;
    value->closed = 0;
    ht_append_table(names, key, keylen, value);
  } else {
    ASSERT(value->object);
    if (PDF_OBJ_UNDEFINED(value->object)) {
      pdf_transfer_label(object, value->object);
      pdf_release_obj(value->object);
      value->object = object;
    } else {
      WARN("Object @%s already defined.", printable_key(key, keylen));
      pdf_release_obj(object);
      return -1;
    }
  }

  return 0;
}

Here is the call graph for this function:

Here is the caller graph for this function:

int pdf_names_close_object ( struct ht_table names,
const void *  key,
int  keylen 
)

Definition at line 220 of file pdfnames.c.

{
  struct obj_data *value;

  ASSERT(names);

  value = ht_lookup_table(names, key, keylen);
  if (!value ||PDF_OBJ_UNDEFINED(value->object) ) {
    WARN("Cannot close undefined object @%s.", printable_key(key, keylen));
    return -1;
  }
  ASSERT(value->object);

  if (value->closed) {
    WARN("Object @%s already closed.", printable_key(key, keylen));
    return -1;
  }

  value->closed = 1;

  return 0;
}

Here is the call graph for this function:

pdf_obj* pdf_names_create_tree ( struct ht_table names,
long *  count,
struct ht_table filter 
)

Definition at line 409 of file pdfnames.c.

{
  pdf_obj *name_tree;
  struct   named_object *flat;

  flat = flat_table(names, count, filter);
  if (!flat)
    name_tree = NULL;
  else {
    qsort(flat, *count, sizeof(struct named_object), cmp_key);
    name_tree = build_name_tree(flat, *count, 1);
    RELEASE(flat);
  }

  return name_tree;
}

Here is the call graph for this function:

Here is the caller graph for this function:

pdf_obj* pdf_names_lookup_object ( struct ht_table names,
const void *  key,
int  keylen 
)

Definition at line 204 of file pdfnames.c.

{
  struct obj_data *value;

  ASSERT(names);

  value = ht_lookup_table(names, key, keylen);
  if (!value || PDF_OBJ_UNDEFINED(value->object))
    return NULL;
  ASSERT(value->object);

  return value->object;
}

Here is the call graph for this function:

pdf_obj* pdf_names_lookup_reference ( struct ht_table names,
const void *  key,
int  keylen 
)

Definition at line 179 of file pdfnames.c.

{
  struct obj_data *value;
  pdf_obj *object;

  ASSERT(names);

  value = ht_lookup_table(names, key, keylen);
  if (value) {
    object = value->object;
  } else {
    /* A null object as dummy would create problems because as value
     * of a dictionary entry, a null object is be equivalent to no entry
     * at all. This matters for optimization of PDF destinations.
     */
    object = pdf_new_undefined();
    pdf_names_add_object(names, key, keylen, object);
  }
  ASSERT(object);

  return pdf_ref_obj(object);
}

Here is the call graph for this function:

struct ht_table* pdf_new_name_tree ( void  ) [read]

Definition at line 94 of file pdfnames.c.

{
  struct ht_table *names;

  names = NEW(1, struct ht_table);
  ht_init_table(names, hval_free);

  return names;
}

Here is the call graph for this function:

Here is the caller graph for this function:

char* printable_key ( const char *  key,
int  keylen 
)

Definition at line 52 of file pdfnames.c.

{
#define MAX_KEY 32
  static char pkey[MAX_KEY+4];
  int    i, len;
  unsigned char hi, lo;

  for (i = 0, len = 0;
       i < keylen && len < MAX_KEY; i++) {
    if (isprint(key[i])) {
      pkey[len++] = key[i];
    } else {
      hi = (key[i] >> 4) & 0xff;
      lo =  key[i] & 0xff;
      pkey[len++] = '#';
      pkey[len++] = (hi < 10) ? hi + '0' : (hi - 10) + 'A';
      pkey[len++] = (lo < 10) ? lo + '0' : (lo - 10) + 'A';
    }
  }
  pkey[len] = '\0';

  return (char *) pkey;
}

Here is the caller graph for this function: