Back to index

texmacs  1.0.7.15
pdfnames.c
Go to the documentation of this file.
00001 /*  $Header: /home/cvsroot/dvipdfmx/src/pdfnames.c,v 1.7 2009/09/18 23:56:02 matthias Exp $
00002 
00003     This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks.
00004 
00005     Copyright (C) 2002 by Jin-Hwan Cho and Shunsaku Hirata,
00006     the dvipdfmx project team <dvipdfmx@project.ktug.or.kr>
00007     
00008     Copyright (C) 1998, 1999 by Mark A. Wicks <mwicks@kettering.edu>
00009 
00010     This program is free software; you can redistribute it and/or modify
00011     it under the terms of the GNU General Public License as published by
00012     the Free Software Foundation; either version 2 of the License, or
00013     (at your option) any later version.
00014     
00015     This program is distributed in the hope that it will be useful,
00016     but WITHOUT ANY WARRANTY; without even the implied warranty of
00017     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018     GNU General Public License for more details.
00019     
00020     You should have received a copy of the GNU General Public License
00021     along with this program; if not, write to the Free Software
00022     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
00023 */
00024 
00025 #if HAVE_CONFIG_H
00026 #include "config.h"
00027 #endif
00028 
00029 #include <ctype.h>
00030 #include <math.h>
00031 #include <string.h>
00032 
00033 #include "system.h"
00034 #include "mem.h"
00035 #include "error.h"
00036 #include "numbers.h"
00037 
00038 /* Hash */
00039 #include "dpxutil.h"
00040 
00041 #include "pdfobj.h"
00042 
00043 #include "pdfnames.h"
00044 
00045 struct obj_data
00046 {
00047   pdf_obj *object;
00048   int closed;            /* 1 if object is closed */
00049 };
00050 
00051 char *
00052 printable_key (const char *key, int keylen)
00053 {
00054 #define MAX_KEY 32
00055   static char pkey[MAX_KEY+4];
00056   int    i, len;
00057   unsigned char hi, lo;
00058 
00059   for (i = 0, len = 0;
00060        i < keylen && len < MAX_KEY; i++) {
00061     if (isprint(key[i])) {
00062       pkey[len++] = key[i];
00063     } else {
00064       hi = (key[i] >> 4) & 0xff;
00065       lo =  key[i] & 0xff;
00066       pkey[len++] = '#';
00067       pkey[len++] = (hi < 10) ? hi + '0' : (hi - 10) + 'A';
00068       pkey[len++] = (lo < 10) ? lo + '0' : (lo - 10) + 'A';
00069     }
00070   }
00071   pkey[len] = '\0';
00072 
00073   return (char *) pkey;
00074 }
00075 
00076 static void CDECL
00077 hval_free (void *hval)
00078 {
00079   struct obj_data *value;
00080 
00081   value = (struct obj_data *) hval;
00082 
00083   if (value->object) {
00084     pdf_release_obj(value->object);
00085     value->object     = NULL;
00086   }
00087 
00088   RELEASE(value);
00089 
00090   return;
00091 }
00092 
00093 struct ht_table *
00094 pdf_new_name_tree (void)
00095 {
00096   struct ht_table *names;
00097 
00098   names = NEW(1, struct ht_table);
00099   ht_init_table(names, hval_free);
00100 
00101   return names;
00102 }
00103 
00104 static void
00105 check_objects_defined (struct ht_table *ht_tab)
00106 {
00107   struct ht_iter iter;
00108 
00109   if (ht_set_iter(ht_tab, &iter) >= 0) {
00110     do {
00111       char  *key;
00112       int    keylen;
00113       struct obj_data *value;
00114 
00115       key   = ht_iter_getkey(&iter, &keylen);
00116       value = ht_iter_getval(&iter);
00117       ASSERT(value->object);
00118       if (PDF_OBJ_UNDEFINED(value->object)) {
00119        pdf_names_add_object(ht_tab, key, keylen, pdf_new_null());
00120        WARN("Object @%s used, but not defined. Replaced by null.",
00121             printable_key(key, keylen));
00122       }
00123     } while (ht_iter_next(&iter) >= 0);
00124     ht_clear_iter(&iter);
00125   }
00126 }
00127 
00128 void
00129 pdf_delete_name_tree (struct ht_table **names)
00130 {
00131   ASSERT(names && *names);
00132 
00133   check_objects_defined(*names);
00134 
00135   ht_clear_table(*names);
00136   RELEASE(*names);
00137   *names = NULL;
00138 }
00139 
00140 int
00141 pdf_names_add_object (struct ht_table *names,
00142                     const void *key, int keylen, pdf_obj *object)
00143 {
00144   struct obj_data *value;
00145 
00146   ASSERT(names && object);
00147 
00148   if (!key || keylen < 1) {
00149     WARN("Null string used for name tree key.");
00150     return -1;
00151   }
00152 
00153   value = ht_lookup_table(names, key, keylen);
00154   if (!value) {
00155     value = NEW(1, struct obj_data);
00156     value->object = object;
00157     value->closed = 0;
00158     ht_append_table(names, key, keylen, value);
00159   } else {
00160     ASSERT(value->object);
00161     if (PDF_OBJ_UNDEFINED(value->object)) {
00162       pdf_transfer_label(object, value->object);
00163       pdf_release_obj(value->object);
00164       value->object = object;
00165     } else {
00166       WARN("Object @%s already defined.", printable_key(key, keylen));
00167       pdf_release_obj(object);
00168       return -1;
00169     }
00170   }
00171 
00172   return 0;
00173 }
00174 
00175 /*
00176  * The following routine returns copies, not the original object.
00177  */
00178 pdf_obj *
00179 pdf_names_lookup_reference (struct ht_table *names,
00180                          const void *key, int keylen)
00181 {
00182   struct obj_data *value;
00183   pdf_obj *object;
00184 
00185   ASSERT(names);
00186 
00187   value = ht_lookup_table(names, key, keylen);
00188   if (value) {
00189     object = value->object;
00190   } else {
00191     /* A null object as dummy would create problems because as value
00192      * of a dictionary entry, a null object is be equivalent to no entry
00193      * at all. This matters for optimization of PDF destinations.
00194      */
00195     object = pdf_new_undefined();
00196     pdf_names_add_object(names, key, keylen, object);
00197   }
00198   ASSERT(object);
00199 
00200   return pdf_ref_obj(object);
00201 }
00202 
00203 pdf_obj *
00204 pdf_names_lookup_object (struct ht_table *names,
00205                       const void *key, int keylen)
00206 {
00207   struct obj_data *value;
00208 
00209   ASSERT(names);
00210 
00211   value = ht_lookup_table(names, key, keylen);
00212   if (!value || PDF_OBJ_UNDEFINED(value->object))
00213     return NULL;
00214   ASSERT(value->object);
00215 
00216   return value->object;
00217 }
00218 
00219 int
00220 pdf_names_close_object (struct ht_table *names,
00221                      const void *key, int keylen)
00222 {
00223   struct obj_data *value;
00224 
00225   ASSERT(names);
00226 
00227   value = ht_lookup_table(names, key, keylen);
00228   if (!value ||PDF_OBJ_UNDEFINED(value->object) ) {
00229     WARN("Cannot close undefined object @%s.", printable_key(key, keylen));
00230     return -1;
00231   }
00232   ASSERT(value->object);
00233 
00234   if (value->closed) {
00235     WARN("Object @%s already closed.", printable_key(key, keylen));
00236     return -1;
00237   }
00238 
00239   value->closed = 1;
00240 
00241   return 0;
00242 }
00243 
00244 struct named_object
00245 {
00246   char    *key;
00247   int      keylen;
00248   pdf_obj *value;
00249 };
00250 
00251 static int CDECL
00252 cmp_key (const void *d1, const void *d2)
00253 {
00254   struct named_object *sd1, *sd2;
00255   int    keylen, cmp;
00256 
00257   sd1 = (struct named_object *) d1;
00258   sd2 = (struct named_object *) d2;
00259 
00260   if (!sd1->key)
00261     cmp = -1;
00262   else if (!sd2->key)
00263     cmp =  1;
00264   else {
00265     keylen = MIN(sd1->keylen, sd2->keylen);
00266     cmp    = memcmp(sd1->key, sd2->key, keylen);
00267     if (!cmp) {
00268       cmp = sd1->keylen - sd2->keylen;
00269     }
00270   }
00271 
00272   return cmp;
00273 }
00274 
00275 #define NAME_CLUSTER 4
00276 static pdf_obj *
00277 build_name_tree (struct named_object *first, long num_leaves, int is_root)
00278 {
00279   pdf_obj *result;
00280   int      i;
00281 
00282   result = pdf_new_dict();
00283   /*
00284    * According to PDF Refrence, Third Edition (p.101-102), a name tree
00285    * always has exactly one root node, which contains a SINGLE entry:
00286    * either Kids or Names but not both. If the root node has a Names
00287    * entry, it is the only node in the tree. If it has a Kids entry,
00288    * then each of the remaining nodes is either an intermediate node,
00289    * containing a Limits entry and a Kids entry, or a leaf node,
00290    * containing a Limits entry and a Names entry.
00291    */
00292   if (!is_root) {
00293     struct named_object *last;
00294     pdf_obj *limits;
00295 
00296     limits = pdf_new_array();
00297     last   = &first[num_leaves - 1];
00298     pdf_add_array(limits, pdf_new_string(first->key, first->keylen));
00299     pdf_add_array(limits, pdf_new_string(last->key , last->keylen ));
00300     pdf_add_dict (result, pdf_new_name("Limits"),    limits);
00301   }
00302 
00303   if (num_leaves > 0 &&
00304       num_leaves <= 2 * NAME_CLUSTER) {
00305     pdf_obj *names;
00306 
00307     /* Create leaf nodes. */
00308     names = pdf_new_array();
00309     for (i = 0; i < num_leaves; i++) {
00310       struct named_object *cur;
00311 
00312       cur = &first[i];
00313       pdf_add_array(names, pdf_new_string(cur->key, cur->keylen));
00314       switch (PDF_OBJ_TYPEOF(cur->value)) {
00315       case PDF_ARRAY:
00316       case PDF_DICT:
00317       case PDF_STREAM:
00318       case PDF_STRING:
00319        pdf_add_array(names, pdf_ref_obj(cur->value));
00320        break;
00321       case PDF_OBJ_INVALID:
00322        ERROR("Invalid object...: %s", printable_key(cur->key, cur->keylen));
00323        break;
00324       default:
00325        pdf_add_array(names, pdf_link_obj(cur->value));
00326        break;
00327       }
00328       pdf_release_obj(cur->value);
00329       cur->value = NULL;
00330     }
00331     pdf_add_dict(result, pdf_new_name("Names"), names);
00332   } else if (num_leaves > 0) {
00333     pdf_obj *kids;
00334 
00335     /* Intermediate node */
00336     kids = pdf_new_array();
00337     for (i = 0; i < NAME_CLUSTER; i++) {
00338       pdf_obj *subtree;
00339       long     start, end;
00340 
00341       start = (i*num_leaves) / NAME_CLUSTER;
00342       end   = ((i+1)*num_leaves) / NAME_CLUSTER;
00343       subtree = build_name_tree(&first[start], (end - start), 0);
00344       pdf_add_array  (kids, pdf_ref_obj(subtree));
00345       pdf_release_obj(subtree);
00346     }
00347     pdf_add_dict(result, pdf_new_name("Kids"), kids);
00348   }
00349 
00350   return result;
00351 }
00352 
00353 static struct named_object *
00354 flat_table (struct ht_table *ht_tab, long *num_entries,
00355            struct ht_table *filter)
00356 {
00357   struct named_object *objects;
00358   struct ht_iter       iter;
00359   long   count;
00360 
00361   ASSERT(ht_tab);
00362 
00363   objects = NEW(ht_tab->count, struct named_object);
00364   count = 0;
00365   if (ht_set_iter(ht_tab, &iter) >= 0) {
00366     do {
00367       char  *key;
00368       int    keylen;
00369       struct obj_data *value;
00370 
00371       key   = ht_iter_getkey(&iter, &keylen);
00372 
00373       if (filter) {
00374        pdf_obj *new_obj = ht_lookup_table(filter, key, keylen);
00375 
00376        if (!new_obj)
00377          continue;
00378 
00379        key = pdf_string_value(new_obj);
00380        keylen = pdf_string_length(new_obj);
00381       }
00382 
00383       value = ht_iter_getval(&iter);
00384       ASSERT(value->object);
00385       if (PDF_OBJ_UNDEFINED(value->object)) {
00386        WARN("Object @%s\" not defined. Replaced by null.",
00387             printable_key(key, keylen));
00388        objects[count].key    = (char *) key;
00389        objects[count].keylen = keylen;
00390        objects[count].value  = pdf_new_null();
00391       } else if (value->object) {
00392        objects[count].key    = (char *) key;
00393        objects[count].keylen = keylen;
00394        objects[count].value  = pdf_link_obj(value->object);
00395       }
00396 
00397       count++;
00398     } while (ht_iter_next(&iter) >= 0);
00399     ht_clear_iter(&iter);
00400   }
00401 
00402   *num_entries = count;
00403   objects = RENEW(objects, count, struct named_object);
00404 
00405   return objects;
00406 }
00407 
00408 pdf_obj *
00409 pdf_names_create_tree (struct ht_table *names, long *count,
00410                      struct ht_table *filter)
00411 {
00412   pdf_obj *name_tree;
00413   struct   named_object *flat;
00414 
00415   flat = flat_table(names, count, filter);
00416   if (!flat)
00417     name_tree = NULL;
00418   else {
00419     qsort(flat, *count, sizeof(struct named_object), cmp_key);
00420     name_tree = build_name_tree(flat, *count, 1);
00421     RELEASE(flat);
00422   }
00423 
00424   return name_tree;
00425 }