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