1% pdftables.w 2% 3% Copyright 2009-2010 Taco Hoekwater <taco@@luatex.org> 4% 5% This file is part of LuaTeX. 6% 7% LuaTeX is free software; you can redistribute it and/or modify it under 8% the terms of the GNU General Public License as published by the Free 9% Software Foundation; either version 2 of the License, or (at your 10% option) any later version. 11% 12% LuaTeX is distributed in the hope that it will be useful, but WITHOUT 13% ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14% FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 15% License for more details. 16% 17% You should have received a copy of the GNU General Public License along 18% with LuaTeX; if not, see <http://www.gnu.org/licenses/>. 19 20@ @c 21 22 23#include "ptexlib.h" 24 25@ @c 26const char *pdf_obj_typenames[PDF_OBJ_TYPE_MAX + 1] = 27 { "font", "outline", "dest", "obj", "xform", "ximage", "thread", 28 "pagestream", "page", "pages", "catalog", "info", "link", "annot", "annots", 29 "bead", "beads", "objstm", "others" 30}; 31 32@ AVL sort oentry into |avl_table[]| 33@c 34static int compare_info(const void *pa, const void *pb, void *param) 35{ 36 const oentry *a, *b; 37 (void) param; 38 a = (const oentry *) pa; 39 b = (const oentry *) pb; 40 if (a->u_type == b->u_type) { 41 if (a->u_type == union_type_int) 42 return ((a->u.int0 < 43 b->u.int0 ? -1 : (a->u.int0 > b->u.int0 ? 1 : 0))); 44 else /* string type */ 45 return strcmp(a->u.str0, b->u.str0); 46 } else if (a->u_type == union_type_int) 47 return -1; 48 else 49 return 1; 50} 51 52static void avl_put_obj(PDF pdf, int t, oentry * oe) 53{ 54 void **pp; 55 assert(t >= 0 && t <= PDF_OBJ_TYPE_MAX); 56 if (pdf->obj_tree[t] == NULL) { 57 pdf->obj_tree[t] = avl_create(compare_info, NULL, &avl_xallocator); 58 if (pdf->obj_tree[t] == NULL) 59 luatex_fail("avlstuff.c: avl_create() pdf->obj_tree failed"); 60 } 61 pp = avl_probe(pdf->obj_tree[t], oe); 62 if (pp == NULL) 63 luatex_fail("avlstuff.c: avl_probe() out of memory in insertion"); 64} 65 66static void avl_put_int_obj(PDF pdf, int int0, int objptr, int t) 67{ 68 oentry *oe; 69 oe = xtalloc(1, oentry); 70 oe->u.int0 = int0; 71 oe->u_type = union_type_int; 72 oe->objptr = objptr; 73 avl_put_obj(pdf, t, oe); 74} 75 76static void avl_put_str_obj(PDF pdf, char *str0, int objptr, int t) 77{ 78 oentry *oe; 79 oe = xtalloc(1, oentry); 80 oe->u.str0 = str0; /* no xstrdup() here */ 81 oe->u_type = union_type_cstring; 82 oe->objptr = objptr; 83 avl_put_obj(pdf, t, oe); 84} 85 86static int avl_find_int_obj(PDF pdf, int t, int i) 87{ 88 oentry *p; 89 oentry tmp; 90 assert(t >= 0 && t <= PDF_OBJ_TYPE_MAX); 91 tmp.u.int0 = i; 92 tmp.u_type = union_type_int; 93 if (pdf->obj_tree[t] == NULL) 94 return 0; 95 p = (oentry *) avl_find(pdf->obj_tree[t], &tmp); 96 if (p == NULL) 97 return 0; 98 return p->objptr; 99} 100 101static int avl_find_str_obj(PDF pdf, int t, char *s) 102{ 103 oentry *p; 104 oentry tmp; 105 assert(t >= 0 && t <= PDF_OBJ_TYPE_MAX); 106 tmp.u.str0 = s; 107 tmp.u_type = union_type_cstring; 108 if (pdf->obj_tree[t] == NULL) 109 return 0; 110 p = (oentry *) avl_find(pdf->obj_tree[t], &tmp); 111 if (p == NULL) 112 return 0; 113 return p->objptr; 114} 115 116@ Create an object with type |t| and identifier |i| 117 118@c 119int pdf_create_obj(PDF pdf, int t, int i) 120{ 121 int a; 122 char *ss = NULL; 123 if (pdf->obj_ptr == sup_obj_tab_size) 124 overflow("indirect objects table size", (unsigned) pdf->obj_tab_size); 125 if (pdf->obj_ptr == pdf->obj_tab_size) { 126 a = pdf->obj_tab_size / 5; 127 if (pdf->obj_tab_size < sup_obj_tab_size - a) 128 pdf->obj_tab_size = pdf->obj_tab_size + a; 129 else 130 pdf->obj_tab_size = sup_obj_tab_size; 131 pdf->obj_tab = 132 xreallocarray(pdf->obj_tab, obj_entry, 133 (unsigned) pdf->obj_tab_size); 134 } 135 pdf->obj_ptr++; 136 obj_info(pdf, pdf->obj_ptr) = i; 137 obj_type(pdf, pdf->obj_ptr) = t; 138 set_obj_fresh(pdf, pdf->obj_ptr); 139 obj_aux(pdf, pdf->obj_ptr) = 0; 140 if (i < 0) { 141 ss = makecstring(-i); 142 avl_put_str_obj(pdf, ss, pdf->obj_ptr, t); 143 } else if (i > 0) 144 avl_put_int_obj(pdf, i, pdf->obj_ptr, t); 145 if (t <= HEAD_TAB_MAX) { 146 obj_link(pdf, pdf->obj_ptr) = pdf->head_tab[t]; 147 pdf->head_tab[t] = pdf->obj_ptr; 148 if ((t == obj_type_dest) && (i < 0)) 149 append_dest_name(pdf, makecstring(-obj_info(pdf, pdf->obj_ptr)), 150 pdf->obj_ptr); 151 } 152 return pdf->obj_ptr; 153} 154 155@ @c 156int find_obj(PDF pdf, int t, int i, boolean byname) 157{ 158 char *ss = NULL; 159 int ret; 160 assert(i >= 0); /* no tricks */ 161 if (byname) { 162 ss = makecstring(i); 163 ret = avl_find_str_obj(pdf, t, ss); 164 free(ss); 165 } else { 166 ret = avl_find_int_obj(pdf, t, i); 167 } 168 return ret; 169} 170 171@ The following function finds an object with identifier |i| and type |t|. 172 Identifier |i| is either an integer or a token list index. If no 173 such object exists then it will be created. This function is used mainly to 174 find destination for link annotations and outlines; however it is also used 175 in |ship_out| (to check whether a Page object already exists) so we need 176 to declare it together with subroutines needed in |hlist_out| and 177 |vlist_out|. 178 179@c 180int pdf_get_obj(PDF pdf, int t, int i, boolean byname) 181{ 182 int r; 183 str_number s; 184 assert(i >= 0); 185 if (byname > 0) { 186 s = tokens_to_string(i); 187 r = find_obj(pdf, t, s, true); 188 } else { 189 s = 0; 190 r = find_obj(pdf, t, i, false); 191 } 192 if (r == 0) { 193 if (byname > 0) { 194 r = pdf_create_obj(pdf, t, -s); 195 s = 0; 196 } else { 197 r = pdf_create_obj(pdf, t, i); 198 } 199 if (t == obj_type_dest) 200 set_obj_dest_ptr(pdf, r, null); 201 } 202 if (s != 0) 203 flush_str(s); 204 return r; 205} 206 207@ object checking 208@c 209void check_obj_exists(PDF pdf, int objnum) 210{ 211 if (objnum < 0 || objnum > pdf->obj_ptr) 212 pdf_error("ext1", "cannot find referenced object"); 213} 214 215void check_obj_type(PDF pdf, int t, int objnum) 216{ 217 int u; 218 char *s; 219 check_obj_exists(pdf, objnum); 220 u = obj_type(pdf, objnum); 221 if (t != u) { 222 assert(t >= 0 && t <= PDF_OBJ_TYPE_MAX); 223 assert(u >= 0 && u <= PDF_OBJ_TYPE_MAX); 224 s = (char *) xtalloc(128, char); 225 snprintf(s, 127, "referenced object has wrong type %s; should be %s", 226 pdf_obj_typenames[u], pdf_obj_typenames[t]); 227 pdf_error("ext1", s); 228 } 229} 230 231@ @c 232void set_rect_dimens(PDF pdf, halfword p, halfword parent_box, scaledpos cur, 233 scaled_whd alt_rule, scaled margin) 234{ 235 scaledpos ll, ur; /* positions relative to cur */ 236 scaledpos pos_ll, pos_ur, tmp; 237 posstructure localpos; 238 localpos.dir = pdf->posstruct->dir; 239 ll.h = 0; /* pdf contains current point on page */ 240 if (is_running(alt_rule.dp)) 241 ll.v = depth(parent_box) - cur.v; 242 else 243 ll.v = alt_rule.dp; 244 if (is_running(alt_rule.wd)) 245 ur.h = width(parent_box) - cur.h; 246 else 247 ur.h = alt_rule.wd; 248 if (is_running(alt_rule.ht)) 249 ur.v = -height(parent_box) - cur.v; 250 else 251 ur.v = -alt_rule.ht; 252 253 synch_pos_with_cur(&localpos, pdf->posstruct, ll); 254 pos_ll = localpos.pos; 255 synch_pos_with_cur(&localpos, pdf->posstruct, ur); 256 pos_ur = localpos.pos; 257 258 if (pos_ll.h > pos_ur.h) { 259 tmp.h = pos_ll.h; 260 pos_ll.h = pos_ur.h; 261 pos_ur.h = tmp.h; 262 } 263 if (pos_ll.v > pos_ur.v) { 264 tmp.v = pos_ll.v; 265 pos_ll.v = pos_ur.v; 266 pos_ur.v = tmp.v; 267 } 268 if (global_shipping_mode == SHIPPING_PAGE && matrixused()) { 269 matrixtransformrect(pos_ll.h, pos_ll.v, pos_ur.h, pos_ur.v); 270 pos_ll.h = getllx(); 271 pos_ll.v = getlly(); 272 pos_ur.h = geturx(); 273 pos_ur.v = getury(); 274 } 275 pdf_ann_left(p) = pos_ll.h - margin; 276 pdf_ann_bottom(p) = pos_ll.v - margin; 277 pdf_ann_right(p) = pos_ur.h + margin; 278 pdf_ann_top(p) = pos_ur.v + margin; 279} 280 281@ @c 282void libpdffinish(PDF pdf) 283{ 284 strbuf_free(pdf->fb); 285 xfree(pdf->job_id_string); 286 fm_free(); 287 t1_free(); 288 enc_free(); 289 epdf_free(); 290 ttf_free(); 291 sfd_free(); 292 glyph_unicode_free(); 293 zip_free(pdf); 294} 295 296@ Store some of the pdftex data structures in the format. The idea here is 297to ensure that any data structures referenced from pdftex-specific whatsit 298nodes are retained. For the sake of simplicity and speed, all the filled parts 299of |pdf->mem| and |obj_tab| are retained, in the present implementation. We also 300retain three of the linked lists that start from |head_tab|, so that it is 301possible to, say, load an image in the \.{INITEX} run and then reference it in a 302\.{VIRTEX} run that uses the dumped format. 303 304@c 305void dump_pdftex_data(PDF pdf) 306{ 307 int k, x; 308 pdf_object_list *l; 309 dumpimagemeta(); /* the image information array */ 310 dump_int(pdf->mem_size); 311 dump_int(pdf->mem_ptr); 312 for (k = 1; k <= pdf->mem_ptr - 1; k++) { 313 x = pdf->mem[k]; 314 dump_int(x); 315 } 316 print_ln(); 317 print_int(pdf->mem_ptr - 1); 318 tprint(" words of pdf memory"); 319 x = pdf->obj_tab_size; 320 dump_int(x); 321 x = pdf->obj_ptr; 322 dump_int(x); 323 for (k = 1; k <= pdf->obj_ptr; k++) { 324 x = obj_info(pdf, k); 325 dump_int(x); 326 x = obj_link(pdf, k); 327 dump_int(x); 328 x = obj_os_idx(pdf, k); 329 dump_int(x); 330 x = obj_aux(pdf, k); 331 dump_int(x); 332 x = obj_type(pdf, k); 333 dump_int(x); 334 } 335 print_ln(); 336 print_int(pdf->obj_ptr); 337 tprint(" indirect objects"); 338 dump_int(pdf->obj_count); 339 dump_int(pdf->xform_count); 340 dump_int(pdf->ximage_count); 341 if ((l = get_page_resources_list(pdf, obj_type_obj)) != NULL) { 342 while (l != NULL) { 343 dump_int(l->info); 344 l = l->link; 345 } 346 } 347 dump_int(0); /* signal end of |obj_list| */ 348 if ((l = get_page_resources_list(pdf, obj_type_xform)) != NULL) { 349 while (l != NULL) { 350 dump_int(l->info); 351 l = l->link; 352 } 353 } 354 dump_int(0); /* signal end of |xform_list| */ 355 if ((l = get_page_resources_list(pdf, obj_type_ximage)) != NULL) { 356 while (l != NULL) { 357 dump_int(l->info); 358 l = l->link; 359 } 360 } 361 dump_int(0); /* signal end of |ximage_list| */ 362 x = pdf->head_tab[obj_type_obj]; 363 dump_int(x); 364 x = pdf->head_tab[obj_type_xform]; 365 dump_int(x); 366 x = pdf->head_tab[obj_type_ximage]; 367 dump_int(x); 368 dump_int(pdf_last_obj); 369 dump_int(pdf_last_xform); 370 dump_int(pdf_last_ximage); 371} 372 373@ And restoring the pdftex data structures from the format. The 374two function arguments to |undumpimagemeta| have been restored 375already in an earlier module. 376 377@c 378void undump_pdftex_data(PDF pdf) 379{ 380 int k, x; 381 undumpimagemeta(pdf, pdf_minor_version, pdf_inclusion_errorlevel); /* the image information array */ 382 undump_int(pdf->mem_size); 383 pdf->mem = xreallocarray(pdf->mem, int, (unsigned) pdf->mem_size); 384 undump_int(pdf->mem_ptr); 385 for (k = 1; k <= pdf->mem_ptr - 1; k++) { 386 undump_int(x); 387 pdf->mem[k] = (int) x; 388 } 389 undump_int(x); 390 pdf->obj_tab_size = x; 391 undump_int(x); 392 pdf->obj_ptr = x; 393 for (k = 1; k <= pdf->obj_ptr; k++) { 394 undump_int(x); 395 obj_info(pdf, k) = x; 396 undump_int(x); 397 obj_link(pdf, k) = x; 398 set_obj_offset(pdf, k, -1); 399 undump_int(x); 400 obj_os_idx(pdf, k) = x; 401 undump_int(x); 402 obj_aux(pdf, k) = x; 403 undump_int(x); 404 obj_type(pdf, k) = x; 405 } 406 407 undump_int(x); 408 pdf->obj_count = x; 409 undump_int(x); 410 pdf->xform_count = x; 411 undump_int(x); 412 pdf->ximage_count = x; 413 /* todo : the next 3 loops can be done much more efficiently */ 414 undump_int(x); 415 while (x != 0) { 416 addto_page_resources(pdf, obj_type_obj, x); 417 undump_int(x); 418 } 419 undump_int(x); 420 while (x != 0) { 421 addto_page_resources(pdf, obj_type_xform, x); 422 undump_int(x); 423 } 424 undump_int(x); 425 while (x != 0) { 426 addto_page_resources(pdf, obj_type_ximage, x); 427 undump_int(x); 428 } 429 430 undump_int(x); 431 pdf->head_tab[obj_type_obj] = x; 432 undump_int(x); 433 pdf->head_tab[obj_type_xform] = x; 434 undump_int(x); 435 pdf->head_tab[obj_type_ximage] = x; 436 undump_int(pdf_last_obj); 437 undump_int(pdf_last_xform); 438 undump_int(pdf_last_ximage); 439} 440