1% pdfgen.w
2%
3% Copyright 2009-2013 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
26#include <kpathsea/c-dir.h>
27#include <kpathsea/c-ctype.h>
28#include "lua/luatex-api.h"
29#include "md5.h"
30
31#define is_hex_char isxdigit
32
33#define check_nprintf(size_get, size_want) \
34    if ((unsigned)(size_get) >= (unsigned)(size_want)) \
35        luatex_fail ("snprintf failed: file %s, line %d", __FILE__, __LINE__);
36
37PDF static_pdf = NULL;
38
39@ commandline interface
40@c
41int pdf_output_option;
42int pdf_output_value;
43int pdf_draftmode_option;
44int pdf_draftmode_value;
45
46halfword pdf_info_toks;         /* additional keys of Info dictionary */
47halfword pdf_catalog_toks;      /* additional keys of Catalog dictionary */
48halfword pdf_catalog_openaction;
49halfword pdf_names_toks;        /* additional keys of Names dictionary */
50halfword pdf_trailer_toks;      /* additional keys of Trailer dictionary */
51shipping_mode_e global_shipping_mode = NOT_SHIPPING;       /* set to |shipping_mode| when |ship_out| starts */
52
53@ Create a new buffer |strbuf_s| of size |size| and maximum allowed size |limit|.
54Initialize it and set |p| to begin of data.
55@c
56strbuf_s *new_strbuf(size_t size, size_t limit)
57{
58    strbuf_s *b;
59    assert(limit >= size);
60    b = xtalloc(1, strbuf_s);
61    b->size = size;
62    b->limit = limit;
63    if (size > 0)
64        b->p = b->data = xtalloc(b->size, unsigned char);
65    else
66        b->p = b->data = NULL;  /* for other alloc */
67    return b;
68}
69
70@ Check that |n| bytes more fit into buffer; increase it if required.
71@c
72static void strbuf_room(strbuf_s * b, size_t n)
73{
74    unsigned int a;
75    size_t l = (size_t) (b->p - b->data);
76    if (n > b->limit - l)
77        overflow("PDF buffer", (unsigned) b->size);
78    if (n + l > b->size) {
79        a = (unsigned int) (b->size >> 2);
80        if (n + l > b->size + a)
81            b->size = n + l;
82        else if (b->size < b->limit - a)
83            b->size = b->size + a;
84        else
85            b->size = b->limit;
86        b->data = xreallocarray(b->data, unsigned char, (unsigned) b->size);
87        b->p = b->data + l;
88    }
89}
90
91@ Seek to position |offset| within buffer. Position must be valid.
92@c
93void strbuf_seek(strbuf_s * b, off_t offset)
94{
95    assert(offset >= 0 && offset < (off_t) b->size);
96    b->p = b->data + offset;
97}
98
99@ Get the current buffer fill level, the number of characters.
100@c
101size_t strbuf_offset(strbuf_s * b)
102{
103    return (size_t) (b->p - b->data);
104}
105
106@ Put one character into buffer. Make room before if needed.
107@c
108void strbuf_putchar(strbuf_s * b, unsigned char c)
109{
110    if ((size_t) (b->p - b->data + 1) > b->size)
111        strbuf_room(b, 1);
112    *b->p++ = c;
113}
114
115@ Dump filled buffer part to PDF.
116@c
117void strbuf_flush(PDF pdf, strbuf_s * b)
118{
119    pdf_out_block(pdf, (const char *) b->data, strbuf_offset(b));
120    strbuf_seek(b, 0);
121}
122
123@ Free all dynamically allocated buffer structures.
124@c
125void strbuf_free(strbuf_s * b)
126{
127    xfree(b->data);
128    xfree(b);
129}
130
131@ |init_pdf_struct()| is called early, only once, from maincontrol.w
132@c
133PDF init_pdf_struct(PDF pdf)
134{
135    os_struct *os;
136    assert(pdf == NULL);
137    pdf = xtalloc(1, pdf_output_file);
138    memset(pdf, 0, sizeof(pdf_output_file));
139    pdf->job_name = makecstring(job_name);
140
141    pdf->o_mode = OMODE_NONE;   /* will be set by |fix_o_mode()| */
142    pdf->o_state = ST_INITIAL;
143
144    /* init PDF and object stream writing */
145    pdf->os = os = xtalloc(1, os_struct);
146    memset(pdf->os, 0, sizeof(os_struct));
147    os->buf[PDFOUT_BUF] = new_strbuf(inf_pdfout_buf_size, sup_pdfout_buf_size);
148    os->buf[OBJSTM_BUF] = new_strbuf(inf_objstm_buf_size, sup_objstm_buf_size);
149    os->buf[LUASTM_BUF] = new_strbuf(0, 0);
150    os->obj = xtalloc(PDF_OS_MAX_OBJS, os_obj_data);
151    os->cur_objstm = 0;
152    os->trigger_luastm = false;
153
154    os->curbuf = PDFOUT_BUF;
155    pdf->buf = os->buf[os->curbuf];
156
157    /* Later  ttf_seek_outbuf(TABDIR_OFF + n * 4 * TTF_ULONG_SIZE) */
158    /* in ttf_init_font will need 236 bytes, so we start with 256 bytes as in pdftex. */
159    pdf->fb = new_strbuf(256, 100000000);
160
161    pdf->stream_deflate = false;
162    pdf->stream_writing = false;
163
164    /* Sometimes it is neccesary to allocate memory for PDF output that cannot
165       be deallocated then, so we use |mem| for this purpose. */
166    pdf->mem_size = inf_pdf_mem_size;   /* allocated size of |mem| array */
167    pdf->mem = xtalloc(pdf->mem_size, int);
168    pdf->mem_ptr = 1;           /* the first word is not used so we can use zero as a value for testing
169                                   whether a pointer to |mem| is valid  */
170    pdf->pstruct = NULL;
171
172    pdf->posstruct = xtalloc(1, posstructure);
173    pdf->posstruct->pos.h = 0;
174    pdf->posstruct->pos.v = 0;
175    pdf->posstruct->dir = dir_TLT;
176
177    pdf->obj_tab_size = (unsigned) inf_obj_tab_size;    /* allocated size of |obj_tab| array */
178    pdf->obj_tab = xtalloc(pdf->obj_tab_size + 1, obj_entry);
179    memset(pdf->obj_tab, 0, sizeof(obj_entry));
180
181    pdf->minor_version = -1;    /* unset */
182    pdf->decimal_digits = 4;
183    pdf->gamma = 65536;
184    pdf->image_gamma = 65536;
185    pdf->image_hicolor = 1;
186    pdf->image_apply_gamma = 0;
187    pdf->objcompresslevel = 0;
188    pdf->compress_level = 0;
189    pdf->draftmode = 0;
190    pdf->inclusion_copy_font = 1;
191    pdf->replace_font = 0;
192    pdf->pk_resolution = 0;
193    pdf->pk_scale_factor = 0;
194
195    init_dest_names(pdf);
196    pdf->page_resources = NULL;
197
198    init_pdf_pagecalculations(pdf);
199    pdf->pdflua_ref = new_pdflua();
200
201    pdf->vfstruct = new_vfstruct();
202
203    return pdf;
204}
205
206@  We use |pdf_get_mem| to allocate memory in |mem|.
207
208@c
209int pdf_get_mem(PDF pdf, int s)
210{                               /* allocate |s| words in |mem| */
211    int a;
212    int ret;
213    if (s > sup_pdf_mem_size - pdf->mem_ptr)
214        overflow("PDF memory size (pdf_mem_size)", (unsigned) pdf->mem_size);
215    if (pdf->mem_ptr + s > pdf->mem_size) {
216        a = pdf->mem_size >> 2;
217        if (pdf->mem_ptr + s > pdf->mem_size + a) {
218            pdf->mem_size = pdf->mem_ptr + s;
219        } else if (pdf->mem_size < sup_pdf_mem_size - a) {
220            pdf->mem_size = pdf->mem_size + a;
221        } else {
222            pdf->mem_size = sup_pdf_mem_size;
223        }
224        pdf->mem = xreallocarray(pdf->mem, int, (unsigned) pdf->mem_size);
225    }
226    ret = pdf->mem_ptr;
227    pdf->mem_ptr = pdf->mem_ptr + s;
228    return ret;
229}
230
231@ |get_o_mode| translates from |pdf_output| to |o_mode|.
232
233@c
234static output_mode get_o_mode(void)
235{
236    output_mode o_mode;
237    if (pdf_output > 0) {
238    /* ls-hh: for the moment disabled ... incomplete old experiment */
239    /*
240        if (pdf_output == 2009)
241            o_mode = OMODE_LUA;
242        else
243    */
244            o_mode = OMODE_PDF;
245    } else
246        o_mode = OMODE_DVI;
247    return o_mode;
248}
249
250@ |fix_o_mode| freezes |pdf->o_mode| as soon as anything goes through
251the backend, be it \.{PDF}, \.{DVI}, or \.{Lua}.
252
253@c
254void fix_o_mode(PDF pdf)
255{
256    output_mode o_mode = get_o_mode();
257    if (pdf->o_mode == OMODE_NONE)
258        pdf->o_mode = o_mode;
259    else if (pdf->o_mode != o_mode)
260        pdf_error("setup", "\\pdfoutput can only be changed before anything is written to the output");
261}
262
263@ This ensures that |pdfminorversion| is set only before any bytes have
264been written to the generated \.{PDF} file. Here also all variables for
265\.{PDF} output are initialized, the \.{PDF} file is opened by |ensure_pdf_open|,
266and the \.{PDF} header is written.
267
268@c
269void fix_pdf_minorversion(PDF pdf)
270{
271    if (pdf->minor_version < 0) {       /* unset */
272        if ((pdf_minor_version < 0) || (pdf_minor_version > 9)) {
273            const char *hlp[] = { "The pdfminorversion must be between 0 and 9.", "I changed this to 4.", NULL };
274            char msg[256];
275            (void) snprintf(msg, 255, "LuaTeX error (illegal pdfminorversion %d)", (int) pdf_minor_version);
276            tex_error(msg, hlp);
277            pdf_minor_version = 4;
278        }
279        pdf->minor_version = pdf_minor_version;
280    } else {
281        /* Check that variables for \.{PDF} output are unchanged */
282        if (pdf->minor_version != pdf_minor_version)
283            pdf_error("setup", "\\pdfminorversion cannot be changed after data is written to the PDF file");
284        if (pdf->draftmode != pdf_draftmode)
285            pdf_error("setup", "\\pdfdraftmode cannot be changed after data is written to the PDF file");
286    }
287    if (pdf->draftmode != 0) {
288        pdf->compress_level = 0;        /* re-fix it, might have been changed inbetween */
289        pdf->objcompresslevel = 0;
290    }
291}
292
293@ @c
294#define ZIP_BUF_SIZE  32768
295
296#define check_err(f, fn)                        \
297  if (f != Z_OK)                                \
298    luatex_fail("zlib: %s() failed (error code %d)", fn, f)
299
300@ @c
301static void write_zip(PDF pdf)
302{
303    int flush, err = Z_OK;
304    uInt zip_len;
305    strbuf_s *buf = pdf->buf;
306    z_stream *s = pdf->c_stream;
307    boolean finish = pdf->zip_write_state == ZIP_FINISH;
308    assert(pdf->compress_level > 0);
309    /* This was just to suppress the filename report in |luatex_fail|
310       but zlib errors are rare enough (especially now that the
311       compress level is fixed) that I don't care about the slightly
312       ugly error message that could result.
313     */
314#if 0
315    cur_file_name = NULL;
316#endif
317    if (pdf->stream_length == 0) {
318        if (s == NULL) {
319            s = pdf->c_stream = xtalloc(1, z_stream);
320            s->zalloc = (alloc_func) 0;
321            s->zfree = (free_func) 0;
322            s->opaque = (voidpf) 0;
323            check_err(deflateInit(s, pdf->compress_level), "deflateInit");
324            assert(pdf->zipbuf == NULL);
325            pdf->zipbuf = xtalloc(ZIP_BUF_SIZE, char);
326        } else
327            check_err(deflateReset(s), "deflateReset");
328        s->next_out = (Bytef *) pdf->zipbuf;
329        s->avail_out = ZIP_BUF_SIZE;
330    }
331    assert(s != NULL);
332    assert(pdf->zipbuf != NULL);
333    s->next_in = buf->data;
334    s->avail_in = (uInt) (buf->p - buf->data);
335    while (true) {
336        if (s->avail_out == 0 || (finish && s->avail_out < ZIP_BUF_SIZE)) {
337            zip_len = ZIP_BUF_SIZE - s->avail_out;
338            pdf->gone += (off_t) xfwrite(pdf->zipbuf, 1, zip_len, pdf->file);
339            pdf->last_byte = pdf->zipbuf[zip_len - 1];
340            s->next_out = (Bytef *) pdf->zipbuf;
341            s->avail_out = ZIP_BUF_SIZE;
342        }
343        if (finish) {
344            if (err == Z_STREAM_END) {
345                assert(s->avail_in == 0);
346                assert(s->avail_out == ZIP_BUF_SIZE);
347                xfflush(pdf->file);
348                pdf->zip_write_state = NO_ZIP;
349                break;
350            }
351            flush = Z_FINISH;
352        } else {
353            if (s->avail_in == 0)
354                break;
355            flush = Z_NO_FLUSH;
356        }
357        err = deflate(s, flush);
358        if (err != Z_OK && err != Z_STREAM_END)
359            luatex_fail("zlib: deflate() failed (error code %d)", err);
360    }
361    pdf->stream_length = (off_t) s->total_out;
362}
363
364@ @c
365void zip_free(PDF pdf)
366{
367    if (pdf->zipbuf != NULL) {
368        check_err(deflateEnd(pdf->c_stream), "deflateEnd");
369        xfree(pdf->zipbuf);
370    }
371    xfree(pdf->c_stream);
372}
373
374@ @c
375static void write_nozip(PDF pdf)
376{
377    strbuf_s *buf = pdf->buf;
378    size_t l = strbuf_offset(buf);
379    if (l == 0)
380        return;
381    pdf->stream_length = pdf_offset(pdf) - pdf->save_offset;
382    pdf->gone +=
383        (off_t) xfwrite((char *) buf->data, sizeof(char), l, pdf->file);
384    pdf->last_byte = *(buf->p - 1);
385}
386
387@ The PDF buffer is flushed by calling |pdf_flush|, which checks the
388variable |zip_write_state| and will compress the buffer before flushing if
389neccesary. We call |pdf_begin_stream| to begin a stream  and |pdf_end_stream|
390to finish it. The stream contents will be compressed if compression is turn on.
391
392@c
393void pdf_flush(PDF pdf)
394{                               /* flush out the |pdf->buf| */
395    os_struct *os = pdf->os;
396    off_t saved_pdf_gone = pdf->gone;
397    assert(pdf->buf == os->buf[os->curbuf]);
398    switch (os->curbuf) {
399    case PDFOUT_BUF:
400        if (pdf->draftmode == 0) {
401            switch (pdf->zip_write_state) {
402            case NO_ZIP:
403                write_nozip(pdf);
404                break;
405            case ZIP_WRITING:
406            case ZIP_FINISH:
407                write_zip(pdf);
408                break;
409            default:
410                assert(0);
411            }
412        } else
413            pdf->zip_write_state = NO_ZIP;
414        strbuf_seek(pdf->buf, 0);
415        if (saved_pdf_gone > pdf->gone)
416            pdf_error("file size", "File size exceeds architectural limits (pdf_gone wraps around)");
417        break;
418    case LUASTM_BUF:
419        luaL_addsize(&(os->b), strbuf_offset(pdf->buf));
420        pdf->buf->p = pdf->buf->data = (unsigned char *) luaL_prepbuffer(&(os->b));     /* for next stream piece */
421        break;
422    case OBJSTM_BUF:
423        break;
424    default:
425        assert(0);
426    }
427}
428
429@ @c
430static void pdf_buffer_select(PDF pdf, buffer_e buf)
431{
432    os_struct *os = pdf->os;
433    if (pdf->os_enable && buf == OBJSTM_BUF)
434        os->curbuf = OBJSTM_BUF;        /* switch to object stream */
435    else
436        os->curbuf = PDFOUT_BUF;        /* switch to PDF stream */
437    pdf->buf = os->buf[pdf->os->curbuf];
438}
439
440@ create new \.{/ObjStm} object if required, and set up cross reference info
441
442@c
443static void pdf_prepare_obj(PDF pdf, int k, int pdf_os_threshold)
444{
445    os_struct *os = pdf->os;
446    strbuf_s *obuf = os->buf[OBJSTM_BUF];
447    assert(os->curbuf != LUASTM_BUF);
448    assert(pdf_os_threshold >= OBJSTM_ALWAYS);
449    if (pdf->objcompresslevel >= pdf_os_threshold)
450        pdf_buffer_select(pdf, OBJSTM_BUF);
451    else
452        pdf_buffer_select(pdf, PDFOUT_BUF);
453    assert(pdf->buf == os->buf[os->curbuf]);
454    switch (os->curbuf) {
455    case PDFOUT_BUF:
456        obj_offset(pdf, k) = pdf_offset(pdf);
457        obj_os_idx(pdf, k) = PDF_OS_MAX_OBJS;   /* mark it as not included in any ObjStm */
458        break;
459    case LUASTM_BUF:
460        assert(0);
461        break;
462    case OBJSTM_BUF:
463        if (os->cur_objstm == 0) {
464            os->cur_objstm =
465                (unsigned int) pdf_create_obj(pdf, obj_type_objstm, 0);
466            os->idx = 0;
467            obuf->p = obuf->data;       /* start fresh object stream */
468            os->ostm_ctr++;     /* only for statistics */
469        }
470        assert(os->idx < PDF_OS_MAX_OBJS);      /* for marking below */
471        obj_os_idx(pdf, k) = (int) os->idx;
472        obj_os_objnum(pdf, k) = (int) os->cur_objstm;
473        os->obj[os->idx].num = k;
474        os->obj[os->idx].off = obuf->p - obuf->data;
475        break;
476    default:
477        assert(0);
478    }
479}
480
481@* Low-level buffer checkers.
482
483@ Set the active buffer pointer.
484Make sure that there are at least |n| bytes free in that buffer,
485flush if needed.
486@c
487void pdf_room(PDF pdf, int n)
488{
489    os_struct *os = pdf->os;
490    strbuf_s *buf = pdf->buf;
491    if ((size_t) (n + buf->p - buf->data) <= buf->size)
492        return;
493    assert(buf == os->buf[os->curbuf]);
494    switch (os->curbuf) {
495    case PDFOUT_BUF:
496        if ((size_t) n > buf->size)
497            overflow("PDF output buffer", (unsigned) buf->size);
498        if ((size_t) (n + buf->p - buf->data) < buf->limit)
499            strbuf_room(buf, (size_t) n);       /* grow it if possible */
500        else
501            pdf_flush(pdf);
502        break;
503    case LUASTM_BUF:
504        if ((size_t) n > buf->size)
505            overflow("PDF output buffer", (unsigned) buf->size);
506        pdf_flush(pdf);
507        break;
508    case OBJSTM_BUF:
509        strbuf_room(buf, (size_t) n);   /* just grow it */
510        break;
511    default:
512        assert(0);
513    }
514}
515
516@ @c
517void pdf_out_block(PDF pdf, const char *s, size_t n)
518{
519    size_t l;
520    strbuf_s *buf = pdf->buf;
521    do {
522        l = n;
523        if (l > buf->size)
524            l = buf->size;
525        pdf_room(pdf, (int) l);
526        (void) memcpy(buf->p, s, l);
527        buf->p += l;
528        s += l;
529        n -= l;
530    } while (n > 0);
531}
532
533@ @c
534__attribute__ ((format(printf, 2, 3)))
535void pdf_printf(PDF pdf, const char *fmt, ...)
536{
537    va_list args;
538    va_start(args, fmt);
539    if (pdf->printf_buf == NULL) {
540        pdf->printf_buf = xtalloc(PRINTF_BUF_SIZE, char);
541    }
542    (void) vsnprintf(pdf->printf_buf, PRINTF_BUF_SIZE, fmt, args);
543    pdf_puts(pdf, pdf->printf_buf);
544    va_end(args);
545}
546
547@ print out a string to PDF buffer
548@c
549void pdf_print(PDF pdf, str_number s)
550{
551    const char *ss;
552    size_t l;
553    if (s >= STRING_OFFSET) {
554        ss = (const char *) str_string(s);
555        l = str_length(s);
556        pdf_out_block(pdf, ss, l);
557    } else {
558        assert(s < 256);
559        pdf_out(pdf, s);
560    }
561}
562
563@ print out a integer to PDF buffer
564@c
565void pdf_print_int(PDF pdf, longinteger n)
566{
567    char s[24];
568    int w;
569    w = snprintf(s, 23, "%" LONGINTEGER_PRI "d", (LONGINTEGER_TYPE) n);
570    check_nprintf(w, 23);
571    pdf_out_block(pdf, (const char *) s, (size_t) w);
572}
573
574@ @c
575void print_pdffloat(PDF pdf, pdffloat f)
576{
577    char a[24];
578    int e = f.e, i, j, l;
579    int64_t m = f.m;
580    if (m < 0) {
581        pdf_out(pdf, '-');
582        m *= -1;
583    }
584    l = m / ten_pow[e];
585    pdf_print_int(pdf, l);
586    l = m % ten_pow[e];
587    if (l != 0) {
588        pdf_out(pdf, '.');
589        j = snprintf(a, 23, "%d", l + ten_pow[e]);
590        assert(j < 23);
591        for (i = e; i > 0; i--) {
592            if (a[i] != '0')
593                break;
594            a[i] = '\0';
595        }
596        pdf_puts(pdf, (a + 1));
597    }
598}
599
600@ print out |s| as string in PDF output
601@c
602void pdf_print_str(PDF pdf, const char *s)
603{
604    const char *orig = s;
605    int l = (int) strlen(s) - 1;        /* last string index */
606    if (l < 0) {
607        pdf_puts(pdf, "()");
608        return;
609    }
610    /* the next is not really safe, the string could be "(a)xx(b)" */
611    if ((s[0] == '(') && (s[l] == ')')) {
612        pdf_puts(pdf, s);
613        return;
614    }
615    if ((s[0] != '<') || (s[l] != '>') || odd((l + 1))) {
616        pdf_out(pdf, '(');
617        pdf_puts(pdf, s);
618        pdf_out(pdf, ')');
619        return;
620    }
621    s++;
622    while (is_hex_char((unsigned char)*s))
623        s++;
624    if (s != orig + l) {
625        pdf_out(pdf, '(');
626        pdf_puts(pdf, orig);
627        pdf_out(pdf, ')');
628        return;
629    }
630    pdf_puts(pdf, orig);        /* it was a hex string after all  */
631}
632
633@ begin a stream (needs to have a stream dictionary also)
634@c
635void pdf_begin_stream(PDF pdf)
636{
637    os_struct *os = pdf->os;
638    strbuf_s *lbuf = os->buf[LUASTM_BUF];
639    assert(os->curbuf == PDFOUT_BUF);
640    assert(pdf->buf == os->buf[os->curbuf]);
641    assert(pdf->zip_write_state == NO_ZIP);
642    pdf_puts(pdf, "\nstream\n");
643    pdf_save_offset(pdf);
644    pdf_flush(pdf);
645
646    if (callback_defined(pdf_stream_filter_callback)) {
647    /*if (os->trigger_luastm) {*/
648        os->trigger_luastm = false;     /* this was just a trigger */
649        luaL_buffinit(Luas, &(os->b));
650        lbuf->p = lbuf->data = (unsigned char *) luaL_prepbuffer(&(os->b));
651        lbuf->size = lbuf->limit = LUAL_BUFFERSIZE;
652        os->curbuf = LUASTM_BUF;
653        pdf->buf = os->buf[os->curbuf];
654    }
655    if (pdf->stream_deflate) {
656        assert(pdf->compress_level > 0);
657        pdf->zip_write_state = ZIP_WRITING;
658    }
659    pdf->stream_writing = true;
660    pdf->stream_length = 0;
661    pdf->last_byte = 0;
662}
663
664@ end a stream
665@c
666void pdf_end_stream(PDF pdf)
667{
668    typedef struct strbuf_const_s_ {
669    unsigned const char *data;   /* a PDF stream buffer */
670    unsigned const char *p;     /* pointer to the next character in the PDF stream buffer */
671    size_t size;                /* currently allocated size of the PDF stream buffer, grows dynamically */
672    size_t limit;               /* maximum allowed PDF stream buffer size */
673    } strbuf_const_s;
674
675
676    os_struct *os = pdf->os;
677    /*  Old code,                             */
678    /*  strbuf_s *lbuf = os->buf[LUASTM_BUF]; */
679    strbuf_const_s *lbuf = (strbuf_const_s * )os->buf[LUASTM_BUF];
680    const_lstring ls;
681    int callback_id ;
682    assert(pdf->buf == os->buf[os->curbuf]);
683    switch (os->curbuf) {
684    case PDFOUT_BUF:
685        if (pdf->zip_write_state == ZIP_WRITING)
686            pdf->zip_write_state = ZIP_FINISH;
687        pdf_flush(pdf);         /* sets pdf->last_byte */
688        break;
689    case LUASTM_BUF:
690        luaL_addsize(&(os->b), strbuf_offset(os->buf[LUASTM_BUF]));
691        luaL_pushresult(&(os->b));
692        /* now the complete page stream is on the Lua stack */
693        /* TODO: pagestream filter callback here */
694
695        callback_id = callback_defined(pdf_stream_filter_callback);
696        if (callback_id > 0) {
697            run_callback(callback_id, "S->S");
698        }
699
700        ls.s = lua_tolstring(Luas, -1, &ls.l);
701        /* lbuf->data = (unsigned char *) ls.s; */
702        lbuf->data = (unsigned const char *) ls.s;
703        lbuf->p = lbuf->data + ls.l;
704        os->curbuf = LUASTM_BUF;
705        pdf->buf = os->buf[os->curbuf];
706        if (pdf->zip_write_state == ZIP_WRITING) {
707            pdf->zip_write_state = ZIP_FINISH;
708            write_zip(pdf);
709        } else
710            write_nozip(pdf);
711        lua_pop(Luas, 1);
712        os->curbuf = PDFOUT_BUF;
713        pdf->buf = os->buf[os->curbuf];
714        assert(pdf->buf->data == pdf->buf->p);
715        break;
716    case OBJSTM_BUF:
717        assert(0);
718        break;
719    default:
720        assert(0);
721    }
722    assert(pdf->zip_write_state == NO_ZIP);
723    assert(os->curbuf == PDFOUT_BUF);
724    assert(pdf->buf == os->buf[os->curbuf]);
725    pdf->stream_deflate = false;
726    pdf->stream_writing = false;
727    pdf_out(pdf, '\n');     /* doesn't really belong to the stream */
728    pdf_puts(pdf, "endstream");
729    /* write stream /Length */
730    if (pdf->seek_write_length && pdf->draftmode == 0) {
731        xfseeko(pdf->file, (off_t)pdf->stream_length_offset, SEEK_SET,
732                pdf->job_name);
733        fprintf(pdf->file, "%" LONGINTEGER_PRI "i", (LONGINTEGER_TYPE) pdf->stream_length);
734        xfseeko(pdf->file, 0, SEEK_END, pdf->job_name);
735    }
736    pdf->seek_write_length = false;
737}
738
739@ To print |scaled| value to PDF output we need some subroutines to ensure
740accurary.
741
742@c
743#define max_integer 0x7FFFFFFF  /* $2^{31}-1$ */
744
745/* scaled value corresponds to 100in, exact, 473628672 */
746scaled one_hundred_inch = 7227 * 65536;
747
748/* scaled value corresponds to 1in (rounded to 4736287) */
749scaled one_inch = (7227 * 65536 + 50) / 100;
750
751/* scaled value corresponds to 1truein (rounded!) */
752scaled one_true_inch = (7227 * 65536 + 50) / 100;
753
754/* scaled value corresponds to 100bp */
755scaled one_hundred_bp = (7227 * 65536) / 72;
756
757/* scaled value corresponds to 1bp (rounded to 65782) */
758/* changed on 20110411 to be exactly 65781, as in tex itself,
759  because this value is also used for \pdfpxdimen */
760scaled one_bp = 65781;
761
762/* $10^0..10^9$ */
763int ten_pow[10] = {
764    1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000
765};
766
767
768@ The function |divide_scaled| divides |s| by |m| using |dd| decimal
769digits of precision. It is defined in C because it is a good candidate
770for optimizations that are not possible in pascal.
771
772@c
773scaled round_xn_over_d(scaled x, int n, unsigned int d)
774{
775    boolean positive = true;           /* was |x>=0|, |n>=0| ? */
776    unsigned t, u, v;           /* intermediate quantities */
777    if (x < 0) {
778        positive = !positive;
779        x = -(x);
780    }
781    if (n < 0) {
782        positive = !positive;
783        n = -(n);
784    }
785    t = (unsigned) ((x % 0100000) * n);
786    u = (unsigned) (((unsigned) (x) / 0100000) * (unsigned) n + (t / 0100000));
787    v = (u % d) * 0100000 + (t % 0100000);
788    if (u / d >= 0100000)
789        arith_error = true;
790    else
791        u = 0100000 * (u / d) + (v / d);
792    v = v % d;
793    if (2 * v >= d)
794        u++;
795    if (positive)
796        return (scaled) u;
797    else
798        return (-(scaled) u);
799}
800
801
802@ @c
803void pdf_add_bp(PDF pdf, scaled s)
804{                               /* print scaled as |bp| */
805    pdffloat a;
806    pdfstructure *p = pdf->pstruct;
807    assert(p != NULL);
808    a.m = i64round(s * p->k1);
809    a.e = pdf->decimal_digits;
810    if (pdf->cave > 0)
811        pdf_out(pdf, ' ');
812    print_pdffloat(pdf, a);
813    pdf->cave = 1;
814}
815
816void pdf_add_mag_bp(PDF pdf, scaled s)
817{                               /* take |mag| into account */
818    pdffloat a;
819    pdfstructure *p = pdf->pstruct;
820    prepare_mag();
821    if (int_par(mag_code) != 1000)
822        a.m = i64round(s * (double) int_par(mag_code) / 1000.0 * p->k1);
823    else
824        a.m = i64round(s * p->k1);
825    a.e = pdf->decimal_digits;
826    if (pdf->cave > 0)
827        pdf_out(pdf, ' ');
828    print_pdffloat(pdf, a);
829    pdf->cave = 1;
830}
831
832@* handling page resources.
833
834@c
835typedef struct {
836    int obj_type;
837    pdf_object_list *list;
838} pr_entry;
839
840@ @c
841static int comp_page_resources(const void *pa, const void *pb, void *p)
842{
843    int a, b;
844    (void) p;
845    a = ((const pr_entry *) pa)->obj_type;
846    b = ((const pr_entry *) pb)->obj_type;
847    if (a > b)
848        return 1;
849    if (a < b)
850        return -1;
851    return 0;
852}
853
854@ @c
855void addto_page_resources(PDF pdf, pdf_obj_type t, int k)
856{
857    pdf_resource_struct *re;
858    pr_entry *pr, tmp;
859    void **pp;
860    pdf_object_list *p, *item = NULL;
861    assert(pdf != NULL);
862    re = pdf->page_resources;
863    assert(re != NULL);
864    assert(t <= PDF_OBJ_TYPE_MAX);
865    if (re->resources_tree == NULL) {
866        re->resources_tree =
867            avl_create(comp_page_resources, NULL, &avl_xallocator);
868        if (re->resources_tree == NULL)
869            luatex_fail
870                ("addto_page_resources(): avl_create() page_resource_tree failed");
871    }
872    tmp.obj_type = t;
873    pr = (pr_entry *) avl_find(re->resources_tree, &tmp);
874    if (pr == NULL) {
875        pr = xtalloc(1, pr_entry);
876        pr->obj_type = t;
877        pr->list = NULL;
878        pp = avl_probe(re->resources_tree, pr);
879        if (pp == NULL)
880            luatex_fail
881                ("addto_page_resources(): avl_probe() out of memory in insertion");
882    }
883    if (pr->list == NULL) {
884        item = xtalloc(1, pdf_object_list);
885        item->link = NULL;
886        item->info = k;
887        pr->list = item;
888        if (obj_type(pdf, k) == (int)t)
889            set_obj_scheduled(pdf, k);  /* k is an object number */
890    } else {
891        for (p = pr->list; p->info != k && p->link != NULL; p = p->link);
892        if (p->info != k) {
893            item = xtalloc(1, pdf_object_list);
894            item->link = NULL;
895            item->info = k;
896            p->link = item;
897            if (obj_type(pdf, k) == (int)t)
898                set_obj_scheduled(pdf, k);
899        }
900    }
901}
902
903@ @c
904pdf_object_list *get_page_resources_list(PDF pdf, pdf_obj_type t)
905{
906    pdf_resource_struct *re = pdf->page_resources;
907    pr_entry *pr, tmp;
908    if (re == NULL || re->resources_tree == NULL)
909        return NULL;
910    tmp.obj_type = t;
911    pr = (pr_entry *) avl_find(re->resources_tree, &tmp);
912    if (pr == NULL)
913        return NULL;
914    return pr->list;
915}
916
917@ @c
918static void reset_page_resources(PDF pdf)
919{
920    pdf_resource_struct *re = pdf->page_resources;
921    pr_entry *p;
922    struct avl_traverser t;
923    pdf_object_list *l1, *l2;
924    if (re == NULL || re->resources_tree == NULL)
925        return;
926    avl_t_init(&t, re->resources_tree);
927    for (p = avl_t_first(&t, re->resources_tree); p != NULL; p = avl_t_next(&t)) {
928        if (p->list != NULL) {
929            for (l1 = p->list; l1 != NULL; l1 = l2) {
930                l2 = l1->link;
931                free(l1);
932            }
933            p->list = NULL;     /* but the AVL tree remains */
934        }
935    }
936}
937
938@ @c
939static void destroy_pg_res_tree(void *pa, void *param)
940{
941    (void) param;
942    xfree(pa);
943}
944
945@ @c
946static void destroy_page_resources_tree(PDF pdf)
947{
948    pdf_resource_struct *re = pdf->page_resources;
949    reset_page_resources(pdf);
950    if (re->resources_tree != NULL)
951        avl_destroy(re->resources_tree, destroy_pg_res_tree);
952    re->resources_tree = NULL;
953}
954
955@* Subroutines to print out various PDF objects.
956
957@ print out an integer |n| with fixed width |w|; used for outputting cross-reference table
958@c
959static void pdf_print_fw_int(PDF pdf, longinteger n, size_t w)
960{
961    int k;                      /* $0\le k\le23$ */
962    unsigned char digits[24];
963    k = (int) w;
964    do {
965        k--;
966        digits[k] = (unsigned char) ('0' + (n % 10));
967        n /= 10;
968    } while (k != 0);
969    pdf_out_block(pdf, (const char *) digits, w);
970}
971
972@ print out an integer |n| as a fixed number |w| of bytes; used for outputting \.{/XRef} cross-reference stream
973@c
974static void pdf_out_bytes(PDF pdf, longinteger n, size_t w)
975{
976    int k;
977    unsigned char bytes[8];     /* digits in a number being output */
978    k = (int) w;
979    do {
980        k--;
981        bytes[k] = (unsigned char) (n % 256);
982        n /= 256;
983    } while (k != 0);
984    pdf_out_block(pdf, (const char *) bytes, w);
985}
986
987@ print out |s| as string in PDF output
988@c
989void pdf_print_str_ln(PDF pdf, const char *s)
990{
991    pdf_print_str(pdf, s);
992    pdf_out(pdf, '\n');
993}
994
995@ @c
996void pdf_print_toks(PDF pdf, halfword p)
997{
998    int len = 0;
999    char *s = tokenlist_to_cstring(p, true, &len);
1000    if (len > 0) {
1001        if (pdf->cave > 0)
1002            pdf_out(pdf, ' ');
1003        pdf_puts(pdf, s);
1004        pdf->cave = 1;
1005    }
1006    xfree(s);
1007}
1008
1009@ prints a rect spec
1010@c
1011void pdf_add_rect_spec(PDF pdf, halfword r)
1012{
1013    pdf_add_mag_bp(pdf, pdf_ann_left(r));
1014    pdf_add_mag_bp(pdf, pdf_ann_bottom(r));
1015    pdf_add_mag_bp(pdf, pdf_ann_right(r));
1016    pdf_add_mag_bp(pdf, pdf_ann_top(r));
1017}
1018
1019@ output a rectangle specification to PDF file
1020@c
1021void pdf_rectangle(PDF pdf, halfword r)
1022{
1023    prepare_mag();
1024    pdf_add_name(pdf, "Rect");
1025    pdf_begin_array(pdf);
1026    pdf_add_rect_spec(pdf, r);
1027    pdf_end_array(pdf);
1028}
1029
1030@ @c
1031static void init_pdf_outputparameters(PDF pdf)
1032{
1033    assert(pdf->o_mode == OMODE_PDF);
1034    pdf->draftmode = fix_int(pdf_draftmode, 0, 1);
1035    pdf->compress_level = fix_int(pdf_compress_level, 0, 9);
1036    pdf->decimal_digits = fix_int(pdf_decimal_digits, 0, 4);
1037    pdf->gamma = fix_int(pdf_gamma, 0, 1000000);
1038    pdf->image_gamma = fix_int(pdf_image_gamma, 0, 1000000);
1039    pdf->image_hicolor = fix_int(pdf_image_hicolor, 0, 1);
1040    pdf->image_apply_gamma = fix_int(pdf_image_apply_gamma, 0, 1);
1041    pdf->objcompresslevel = fix_int(pdf_objcompresslevel, 0, MAX_OBJ_COMPRESS_LEVEL);
1042    pdf->inclusion_copy_font = fix_int(pdf_inclusion_copy_font, 0, 1);
1043    pdf->replace_font = fix_int(pdf_replace_font, 0, 1);
1044    pdf->pk_resolution = fix_int(pdf_pk_resolution, 72, 8000);
1045    if ((pdf->minor_version >= 5) && (pdf->objcompresslevel > 0)) {
1046        pdf->os_enable = true;
1047    } else {
1048        if (pdf->objcompresslevel > 0) {
1049            pdf_warning("Object streams",
1050                        "\\pdfobjcompresslevel > 0 requires \\pdfminorversion > 4. Object streams disabled now.",
1051                        true, true);
1052            pdf->objcompresslevel = 0;
1053        }
1054        pdf->os_enable = false;
1055    }
1056    if (pdf->pk_resolution == 0)        /* if not set from format file or by user */
1057        pdf->pk_resolution = pk_dpi;    /* take it from \.{texmf.cnf} */
1058    pdf->pk_scale_factor =
1059        divide_scaled(72, pdf->pk_resolution, 5 + pdf->decimal_digits);
1060    if (!callback_defined(read_pk_file_callback)) {
1061        if (pdf_pk_mode != null) {
1062            char *s = tokenlist_to_cstring(pdf_pk_mode, true, NULL);
1063            kpse_init_prog("PDFTEX", (unsigned) pdf->pk_resolution, s, nil);
1064            xfree(s);
1065        } else {
1066            kpse_init_prog("PDFTEX", (unsigned) pdf->pk_resolution, nil, nil);
1067        }
1068        if (!kpse_var_value("MKTEXPK"))
1069            kpse_set_program_enabled(kpse_pk_format, 1, kpse_src_cmdline);
1070    }
1071    set_job_id(pdf, int_par(year_code),
1072               int_par(month_code), int_par(day_code), int_par(time_code));
1073    if ((pdf_unique_resname > 0) && (pdf->resname_prefix == NULL))
1074        pdf->resname_prefix = get_resname_prefix(pdf);
1075}
1076
1077@ Checks that we have a name for the generated PDF file and that it's open.
1078
1079@c
1080static void ensure_output_file_open(PDF pdf, const char *ext)
1081{
1082    char *fn;
1083    if (pdf->file_name != NULL)
1084        return;
1085    if (job_name == 0)
1086        open_log_file();
1087    fn = pack_job_name(ext);
1088    if (pdf->draftmode == 0 || pdf->o_mode == OMODE_DVI) {
1089        while (!lua_b_open_out(&pdf->file, fn))
1090            fn = prompt_file_name("file name for output", ext);
1091    }
1092    pdf->file_name = fn;
1093}
1094
1095@ @c
1096static void ensure_pdf_header_written(PDF pdf)
1097{
1098    assert(pdf->o_state == ST_FILE_OPEN);
1099    assert(pdf->o_mode == OMODE_PDF);
1100    /* Initialize variables for \.{PDF} output */
1101    fix_pdf_minorversion(pdf);
1102    init_pdf_outputparameters(pdf);
1103    /* Write \.{PDF} header */
1104    pdf_printf(pdf, "%%PDF-1.%d\n", pdf->minor_version);
1105    pdf_out(pdf, '%');
1106    pdf_out(pdf, 'P' + 128);
1107    pdf_out(pdf, 'T' + 128);
1108    pdf_out(pdf, 'E' + 128);
1109    pdf_out(pdf, 'X' + 128);
1110    pdf_out(pdf, '\n');
1111}
1112
1113@ @c
1114void ensure_output_state(PDF pdf, output_state s)
1115{
1116    if (pdf->o_state < s) {
1117        if (s > ST_INITIAL)
1118            ensure_output_state(pdf, s - 1);
1119        switch (s - 1) {
1120        case ST_INITIAL:
1121            fix_o_mode(pdf);
1122            break;
1123        case ST_OMODE_FIX:
1124            switch (pdf->o_mode) {
1125            case OMODE_DVI:
1126                ensure_output_file_open(pdf, ".dvi");
1127                break;
1128            case OMODE_PDF:
1129                ensure_output_file_open(pdf, ".pdf");
1130                break;
1131            case OMODE_LUA:
1132                break;
1133            default:
1134                assert(0);
1135            }
1136            break;
1137        case ST_FILE_OPEN:
1138            switch (pdf->o_mode) {
1139            case OMODE_DVI:
1140                ensure_dvi_header_written(pdf);
1141                break;
1142            case OMODE_PDF:
1143                ensure_pdf_header_written(pdf);
1144                break;
1145            case OMODE_LUA:
1146                break;
1147            default:
1148                assert(0);
1149            }
1150            break;
1151        case ST_HEADER_WRITTEN:
1152            break;
1153        case ST_FILE_CLOSED:
1154            break;
1155        default:
1156            assert(0);
1157        }
1158        pdf->o_state++;
1159    }
1160}
1161
1162@ Write out an accumulated object stream.
1163
1164First the object number and byte offset pairs are generated
1165and appended to the ready buffered object stream.
1166By this the value of \.{/First} can be calculated.
1167Then a new \.{/ObjStm} object is generated, and everything is
1168copied to the PDF output buffer, where also compression is done.
1169When calling this procedure, |pdf_os_mode| must be |true|.
1170
1171@c
1172static void pdf_os_write_objstream(PDF pdf)
1173{
1174    os_struct *os = pdf->os;
1175    unsigned int i, j, n1, n2;  /* n1, n2: ObjStm buffer may be reallocated! */
1176    strbuf_s *obuf = os->buf[OBJSTM_BUF];
1177    if (os->cur_objstm == 0)    /* no object stream started */
1178        return;
1179    assert(pdf->buf == obuf);   /* yes, pdf_out() still goes into ObjStm */
1180    assert(os->idx > 0);        /* yes, there are objects for the ObjStm */
1181    n1 = (unsigned int) strbuf_offset(obuf);    /* remember end of collected object stream contents */
1182    /* this is needed here to calculate /First for the ObjStm dict */
1183    for (i = 0, j = 0; i < os->idx; i++) {      /* add object-number/byte-offset list to buffer */
1184        pdf_print_int(pdf, (int) os->obj[i].num);
1185        pdf_out(pdf, ' ');
1186        pdf_print_int(pdf, (int) os->obj[i].off);
1187        if (j == 9 || i == os->idx - 1) {       /* print out in groups of ten for better readability */
1188            pdf_out(pdf, '\n');
1189            j = 0;
1190        } else {
1191            pdf_out(pdf, ' ');
1192            j++;
1193        }
1194    }
1195    n2 = (unsigned int) strbuf_offset(obuf);    /* remember current buffer end */
1196    pdf_begin_obj(pdf, (int) os->cur_objstm, OBJSTM_NEVER);     /* switch to PDF stream writing */
1197    pdf_begin_dict(pdf);
1198    pdf_dict_add_name(pdf, "Type", "ObjStm");
1199    pdf_dict_add_int(pdf, "N", (int) os->idx);  /* number of objects in ObjStm */
1200    pdf_dict_add_int(pdf, "First", (int) (n2 - n1));
1201    pdf_dict_add_streaminfo(pdf);
1202    pdf_end_dict(pdf);
1203    pdf_begin_stream(pdf);
1204    /* write object-number/byte-offset list */
1205    pdf_out_block(pdf, (const char *) (obuf->data + n1), (size_t) (n2 - n1));
1206    /* write collected object stream contents */
1207    pdf_out_block(pdf, (const char *) obuf->data, (size_t) n1);
1208    pdf_end_stream(pdf);
1209    pdf_end_obj(pdf);
1210    os->cur_objstm = 0;         /* to force object stream generation next time */
1211}
1212
1213@ begin a PDF dictionary
1214@c
1215void pdf_begin_dict(PDF pdf)
1216{
1217    pdf_puts(pdf, "<<");
1218    pdf->cave = 0;
1219}
1220
1221@ end a PDF dictionary
1222@c
1223void pdf_end_dict(PDF pdf)
1224{
1225    pdf_puts(pdf, ">>");
1226    pdf->cave = 0;
1227}
1228
1229@ add integer object to dict
1230@c
1231void pdf_dict_add_bool(PDF pdf, const char *key, int i)
1232{
1233    pdf_add_name(pdf, key);
1234    pdf_add_bool(pdf, i);
1235}
1236
1237@ add integer object to dict
1238@c
1239void pdf_dict_add_int(PDF pdf, const char *key, int i)
1240{
1241    pdf_add_name(pdf, key);
1242    pdf_add_int(pdf, i);
1243}
1244
1245@ add name object to dict
1246@c
1247void pdf_dict_add_name(PDF pdf, const char *key, const char *val)
1248{
1249    pdf_add_name(pdf, key);
1250    pdf_add_name(pdf, val);
1251}
1252
1253@ add string object to dict
1254@c
1255void pdf_dict_add_string(PDF pdf, const char *key, const char *val)
1256{
1257    if (val == NULL)
1258        return;
1259    pdf_add_name(pdf, key);
1260    if (pdf->cave > 0)
1261        pdf_out(pdf, ' ');
1262    pdf->cave = 0;
1263    pdf_print_str(pdf, val);
1264}
1265
1266@ add name reference to dict
1267@c
1268void pdf_dict_add_ref(PDF pdf, const char *key, int num)
1269{
1270    pdf_add_name(pdf, key);
1271    pdf_add_ref(pdf, num);
1272}
1273
1274@ add objects of different types
1275@c
1276void pdf_add_null(PDF pdf)
1277{
1278    if (pdf->cave > 0)
1279        pdf_out(pdf, ' ');
1280    pdf_puts(pdf, "null");
1281    pdf->cave = 1;
1282}
1283
1284void pdf_add_bool(PDF pdf, int i)
1285{
1286    if (pdf->cave > 0)
1287        pdf_out(pdf, ' ');
1288    if (i == 0)
1289        pdf_puts(pdf, "false");
1290    else
1291        pdf_puts(pdf, "true");
1292    pdf->cave = 1;
1293}
1294
1295void pdf_add_int(PDF pdf, int i)
1296{
1297    if (pdf->cave > 0)
1298        pdf_out(pdf, ' ');
1299    pdf_print_int(pdf, i);
1300    pdf->cave = 1;
1301}
1302
1303void pdf_add_longint(PDF pdf, longinteger n)
1304{
1305    if (pdf->cave > 0)
1306        pdf_out(pdf, ' ');
1307    pdf_print_int(pdf, n);
1308    pdf->cave = 1;
1309}
1310
1311void pdf_add_string(PDF pdf, const char *s)
1312{
1313    if (pdf->cave > 0)
1314        pdf_out(pdf, ' ');
1315    pdf_print_str(pdf, s);
1316    pdf->cave = 1;
1317}
1318
1319void pdf_add_name(PDF pdf, const char *name)
1320{
1321    pdf_out(pdf, '/');
1322    pdf_puts(pdf, name);
1323    pdf->cave = 1;
1324}
1325
1326void pdf_add_ref(PDF pdf, int num)
1327{
1328    if (pdf->cave > 0)
1329        pdf_out(pdf, ' ');
1330    pdf_print_int(pdf, num);
1331    pdf_puts(pdf, " 0 R");
1332    pdf->cave = 1;
1333}
1334
1335@ add stream length and filter entries to a stream dictionary,
1336remember file position for seek
1337@c
1338void pdf_dict_add_streaminfo(PDF pdf)
1339{
1340    assert(pdf->buf == pdf->os->buf[PDFOUT_BUF]);
1341    pdf_add_name(pdf, "Length");
1342    pdf->stream_length_offset = pdf_offset(pdf) + 1;
1343    pdf->seek_write_length = true;      /* fill in length at |pdf_end_stream| call */
1344    pdf_puts(pdf, " x         ");       /* space for 10 decimal digits */
1345    pdf->cave = 1;
1346    if (pdf->compress_level > 0) {
1347        pdf_dict_add_name(pdf, "Filter", "FlateDecode");
1348        pdf->stream_deflate = true;
1349    }
1350}
1351
1352@ begin a PDF array
1353@c
1354void pdf_begin_array(PDF pdf)
1355{
1356    pdf_out(pdf, '[');
1357    pdf->cave = 0;
1358}
1359
1360@ end a PDF array
1361@c
1362void pdf_end_array(PDF pdf)
1363{
1364    pdf_out(pdf, ']');
1365    pdf->cave = 0;
1366}
1367
1368@ begin a PDF object
1369@c
1370void pdf_begin_obj(PDF pdf, int i, int pdf_os_threshold)
1371{
1372    os_struct *os = pdf->os;
1373    ensure_output_state(pdf, ST_HEADER_WRITTEN);
1374    pdf_prepare_obj(pdf, i, pdf_os_threshold);
1375    assert(pdf->buf == os->buf[os->curbuf]);
1376    switch (os->curbuf) {
1377    case PDFOUT_BUF:
1378        pdf_printf(pdf, "%d 0 obj\n", (int) i);
1379        break;
1380    case LUASTM_BUF:
1381        assert(0);
1382        break;
1383    case OBJSTM_BUF:
1384        if (pdf->compress_level == 0)
1385            pdf_printf(pdf, "%% %d 0 obj\n", (int) i);  /* debugging help */
1386        break;
1387    default:
1388        assert(0);
1389    }
1390    pdf->cave = 0;
1391}
1392
1393@ end a PDF object
1394@c
1395void pdf_end_obj(PDF pdf)
1396{
1397    os_struct *os = pdf->os;
1398    assert(pdf->buf == os->buf[os->curbuf]);
1399    switch (os->curbuf) {
1400    case PDFOUT_BUF:
1401        pdf_puts(pdf, "\nendobj\n");    /* end a PDF object */
1402        break;
1403    case LUASTM_BUF:
1404        assert(0);
1405        break;
1406    case OBJSTM_BUF:
1407        os->idx++;              /* = number of objects collected so far in ObjStm */
1408        os->o_ctr++;            /* only for statistics */
1409        if (os->idx == PDF_OS_MAX_OBJS)
1410            pdf_os_write_objstream(pdf);
1411        else
1412            pdf_out(pdf, '\n'); /* Adobe Reader seems to need this */
1413        break;
1414    default:
1415        assert(0);
1416    }
1417}
1418
1419@ Converts any string given in in in an allowed PDF string which can be
1420 handled by printf et.al.: \.{\\} is escaped to \.{\\\\}, parenthesis are escaped and
1421 control characters are octal encoded.
1422 This assumes that the string does not contain any already escaped
1423 characters!
1424
1425@c
1426char *convertStringToPDFString(const char *in, int len)
1427{
1428    static char pstrbuf[MAX_PSTRING_LEN];
1429    char *out = pstrbuf;
1430    int i, j, k;
1431    char buf[5];
1432    j = 0;
1433    for (i = 0; i < len; i++) {
1434        check_buf((unsigned) j + sizeof(buf), MAX_PSTRING_LEN);
1435        if (((unsigned char) in[i] < '!') || ((unsigned char) in[i] > '~')) {
1436            /* convert control characters into oct */
1437            k = snprintf(buf, sizeof(buf), "\\%03o", (unsigned int) (unsigned char) in[i]);
1438            check_nprintf(k, sizeof(buf));
1439            out[j++] = buf[0];
1440            out[j++] = buf[1];
1441            out[j++] = buf[2];
1442            out[j++] = buf[3];
1443        } else if ((in[i] == '(') || (in[i] == ')')) {
1444            /* escape paranthesis */
1445            out[j++] = '\\';
1446            out[j++] = in[i];
1447        } else if (in[i] == '\\') {
1448            /* escape backslash */
1449            out[j++] = '\\';
1450            out[j++] = '\\';
1451        } else {
1452            /* copy char :-) */
1453            out[j++] = in[i];
1454        }
1455    }
1456    out[j] = '\0';
1457    return pstrbuf;
1458}
1459
1460@ Converts any string given in in in an allowed PDF string which is
1461 hexadecimal encoded;
1462 |sizeof(out)| should be at least $|lin|*2+1$.
1463
1464@c
1465static void convertStringToHexString(const char *in, char *out, int lin)
1466{
1467    int i, j, k;
1468    char buf[3];
1469    j = 0;
1470    for (i = 0; i < lin; i++) {
1471        k = snprintf(buf, sizeof(buf), "%02X", (unsigned int) (unsigned char) in[i]);
1472        check_nprintf(k, sizeof(buf));
1473        out[j++] = buf[0];
1474        out[j++] = buf[1];
1475    }
1476    out[j] = '\0';
1477}
1478
1479@ Compute the ID string as per PDF1.4 9.3:
1480\medskip
1481{\obeylines\obeyspaces
1482    File identifers are defined by the optional ID entry in a PDF file's
1483    trailer dictionary (see Section 3.4.4, "File Trailer"; see also
1484    implementation note 105 in Appendix H). The value of this entry is an
1485    array of two strings. The first string is a permanent identifier based
1486    on the contents of the file at the time it was originally created, and
1487    does not change when the file is incrementally updated. The second
1488    string is a changing identifier based on the file's contents at the
1489    time it was last updated. When a file is first written, both
1490    identifiers are set to the same value. If both identifiers match when a
1491    file reference is resolved, it is very likely that the correct file has
1492    been found; if only the first identifier matches, then a different
1493    version of the correct file has been found.
1494        To help ensure the uniqueness of file identifiers, it is recommend
1495    that they be computed using a message digest algorithm such as MD5
1496    (described in Internet RFC 1321, The MD5 Message-Digest Algorithm; see
1497    the Bibliography), using the following information (see implementation
1498    note 106 in Appendix H):
1499    - The current time
1500    - A string representation of the file's location, usually a pathname
1501    - The size of the file in bytes
1502    - The values of all entries in the file's document information
1503      dictionary (see Section 9.2.1,  Document Information Dictionary )
1504}
1505\medskip
1506  This stipulates only that the two IDs must be identical when the file is
1507  created and that they should be reasonably unique. Since it's difficult
1508  to get the file size at this point in the execution of pdfTeX and
1509  scanning the info dict is also difficult, we start with a simpler
1510  implementation using just the first two items.
1511
1512@c
1513static void print_ID(PDF pdf)
1514{
1515    time_t t;
1516    size_t size;
1517    char time_str[32];
1518    md5_state_t state;
1519    md5_byte_t digest[16];
1520    char id[64];
1521    char pwd[4096];
1522    /* start md5 */
1523    md5_init(&state);
1524    /* get the time */
1525    t = time(NULL);
1526    size = strftime(time_str, sizeof(time_str), "%Y%m%dT%H%M%SZ", gmtime(&t));
1527    md5_append(&state, (const md5_byte_t *) time_str, (int) size);
1528    /* get the file name */
1529    if (getcwd(pwd, sizeof(pwd)) == NULL)
1530        luatex_fail("getcwd() failed (%s), (path too long?)", strerror(errno));
1531#ifdef WIN32
1532    {
1533        char *p;
1534        for (p = pwd; *p; p++) {
1535            if (*p == '\\')
1536                *p = '/';
1537            else if (IS_KANJI(p))
1538                p++;
1539        }
1540    }
1541#endif
1542    md5_append(&state, (const md5_byte_t *) pwd, (int) strlen(pwd));
1543    md5_append(&state, (const md5_byte_t *) "/", 1);
1544    md5_append(&state, (const md5_byte_t *) pdf->file_name,
1545               (int) strlen(pdf->file_name));
1546    /* finish md5 */
1547    md5_finish(&state, digest);
1548    /* write the IDs */
1549    convertStringToHexString((char *) digest, id, 16);
1550    pdf_add_name(pdf, "ID");
1551    pdf_begin_array(pdf);
1552    pdf_printf(pdf, "<%s> <%s>", id, id);
1553    pdf_end_array(pdf);
1554}
1555
1556@ Print the /CreationDate entry.
1557
1558  PDF Reference, third edition says about the expected date format:
1559\medskip
1560{\obeylines\obeyspaces
1561    3.8.2 Dates
1562
1563      PDF defines a standard date format, which closely follows that of
1564      the international standard ASN.1 (Abstract Syntax Notation One),
1565      defined in ISO/IEC 8824 (see the Bibliography). A date is a string
1566      of the form
1567
1568        (D:YYYYMMDDHHmmSSOHH'mm')
1569
1570      where
1571
1572        YYYY is the year
1573        MM is the month
1574        DD is the day (01-31)
1575        HH is the hour (00-23)
1576        mm is the minute (00-59)
1577        SS is the second (00-59)
1578        O is the relationship of local time to Universal Time (UT),
1579          denoted by one of the characters +, -, or Z (see below)
1580        HH followed by ' is the absolute value of the offset from UT
1581          in hours (00-23)
1582        mm followed by ' is the absolute value of the offset from UT
1583          in minutes (00-59)
1584
1585      The apostrophe character (') after HH and mm is part of the syntax.
1586      All fields after the year are optional. (The prefix D:, although also
1587      optional, is strongly recommended.) The default values for MM and DD
1588      are both 01; all other numerical fields default to zero values.  A plus
1589      sign (+) as the value of the O field signifies that local time is
1590      later than UT, a minus sign (-) that local time is earlier than UT,
1591      and the letter Z that local time is equal to UT. If no UT information
1592      is specified, the relationship of the specified time to UT is
1593      considered to be unknown. Whether or not the time zone is known, the
1594      rest of the date should be specified in local time.
1595
1596      For example, December 23, 1998, at 7:52 PM, U.S. Pacific Standard
1597      Time, is represented by the string
1598
1599        D:199812231952-08'00'
1600}
1601
1602  The main difficulty is get the time zone offset. |strftime()| does this in ISO
1603  C99 (e.g. newer glibc) with \%z, but we have to work with other systems (e.g.
1604  Solaris 2.5).
1605
1606@c
1607#define TIME_STR_SIZE 30        /* minimum size for |time_str| is 24: |"D:YYYYmmddHHMMSS+HH'MM'"| */
1608
1609static void makepdftime(PDF pdf)
1610{
1611    struct tm lt, gmt;
1612    size_t size;
1613    int i, off, off_hours, off_mins;
1614    time_t t = pdf->start_time;
1615    char *time_str = pdf->start_time_str;
1616
1617    /* get the time */
1618    lt = *localtime(&t);
1619    size = strftime(time_str, TIME_STR_SIZE, "D:%Y%m%d%H%M%S", &lt);
1620    /* expected format: "YYYYmmddHHMMSS" */
1621    if (size == 0) {
1622        /* unexpected, contents of |time_str| is undefined */
1623        time_str[0] = '\0';
1624        return;
1625    }
1626
1627    /* correction for seconds: \%S can be in range 00..61,
1628       the PDF reference expects 00..59,
1629       therefore we map "60" and "61" to "59" */
1630    if (time_str[14] == '6') {
1631        time_str[14] = '5';
1632        time_str[15] = '9';
1633        time_str[16] = '\0';    /* for safety */
1634    }
1635
1636    /* get the time zone offset */
1637    gmt = *gmtime(&t);
1638
1639    /* this calculation method was found in exim's tod.c */
1640    off = 60 * (lt.tm_hour - gmt.tm_hour) + lt.tm_min - gmt.tm_min;
1641    if (lt.tm_year != gmt.tm_year) {
1642        off += (lt.tm_year > gmt.tm_year) ? 1440 : -1440;
1643    } else if (lt.tm_yday != gmt.tm_yday) {
1644        off += (lt.tm_yday > gmt.tm_yday) ? 1440 : -1440;
1645    }
1646
1647    if (off == 0) {
1648        time_str[size++] = 'Z';
1649        time_str[size] = 0;
1650    } else {
1651        off_hours = off / 60;
1652        off_mins = abs(off - off_hours * 60);
1653        i = snprintf(&time_str[size], 9, "%+03d'%02d'", off_hours, off_mins);
1654        check_nprintf(i, 9);
1655    }
1656    pdf->start_time = t;
1657}
1658
1659@ @c
1660void init_start_time(PDF pdf)
1661{
1662    assert(pdf);
1663    if (pdf->start_time == 0) {
1664        pdf->start_time = time((time_t *) NULL);
1665        pdf->start_time_str = xtalloc(TIME_STR_SIZE, char);
1666        makepdftime(pdf);
1667    }
1668}
1669
1670@ @c
1671char *getcreationdate(PDF pdf)
1672{
1673    assert(pdf);
1674    init_start_time(pdf);
1675    return pdf->start_time_str;
1676}
1677
1678@ @c
1679void remove_pdffile(PDF pdf)
1680{
1681    if (pdf != NULL) {
1682        if (!kpathsea_debug && pdf->file_name && (pdf->draftmode != 0)) {
1683            xfclose(pdf->file, pdf->file_name);
1684            remove(pdf->file_name);
1685        }
1686    }
1687}
1688
1689@ @c
1690void pdf_error(const char *t, const char *p)
1691{
1692    normalize_selector();
1693    print_err("LuaTeX error");
1694    if (t != NULL) {
1695        tprint(" (");
1696        tprint(t);
1697        tprint(")");
1698    }
1699    tprint(": ");
1700    if (p != NULL)
1701        tprint(p);
1702    succumb();
1703}
1704
1705@ @c
1706void pdf_warning(const char *t, const char *p, boolean prepend_nl,
1707                 boolean append_nl)
1708{
1709    if (prepend_nl)
1710        print_ln();
1711    tprint("LuaTeX warning");
1712    if (t != NULL) {
1713        tprint(" (");
1714        tprint(t);
1715        tprint(")");
1716    }
1717    tprint(": ");
1718    if (p != NULL)
1719        tprint(p);
1720    if (append_nl)
1721        print_ln();
1722    if (history == spotless)
1723        history = warning_issued;
1724}
1725
1726@ Use |check_o_mode()| in the backend-specific "Implement..." chunks
1727
1728@c
1729void check_o_mode(PDF pdf, const char *s, int o_mode_bitpattern, boolean strict)
1730{
1731
1732    char warn_string[100];
1733    output_mode o_mode;
1734    const char *m = NULL;
1735
1736    /* in warn mode (strict == false):
1737       only check, don't do |fix_o_mode()| here! |pdf->o_mode| is left
1738       in possibly wrong state until real output, ok.
1739     */
1740
1741    if (pdf->o_mode == OMODE_NONE)
1742        o_mode = get_o_mode();
1743    else
1744        o_mode = pdf->o_mode;
1745    if (!((1 << o_mode) & o_mode_bitpattern)) { /* warning or error */
1746        switch (o_mode) {
1747        case OMODE_DVI:
1748            m = "DVI";
1749            break;
1750        case OMODE_PDF:
1751            m = "PDF";
1752            break;
1753        case OMODE_LUA:
1754            m = "Lua";
1755            break;
1756        default:
1757            assert(0);
1758        }
1759        snprintf(warn_string, 99, "not allowed in %s mode (\\pdfpoutput = %d)",
1760                 m, (int) pdf_output);
1761        if (strict)
1762            pdf_error(s, warn_string);
1763        else
1764            pdf_warning(s, warn_string, true, true);
1765    } else if (strict)
1766        ensure_output_state(pdf, ST_HEADER_WRITTEN);
1767}
1768
1769@ @c
1770void set_job_id(PDF pdf, int year, int month, int day, int time)
1771{
1772    char *name_string, *format_string, *s;
1773    size_t slen;
1774    int i;
1775
1776    if (pdf->job_id_string != NULL)
1777        return;
1778
1779    name_string = makecstring(job_name);
1780    format_string = makecstring(format_ident);
1781    slen = SMALL_BUF_SIZE +
1782        strlen(name_string) + strlen(format_string) + strlen(luatex_banner);
1783    s = xtalloc(slen, char);
1784    /* The Web2c version string starts with a space.  */
1785    i = snprintf(s, slen,
1786                 "%.4d/%.2d/%.2d %.2d:%.2d %s %s %s",
1787                 year, month, day, time / 60, time % 60,
1788                 name_string, format_string, luatex_banner);
1789    check_nprintf(i, slen);
1790    pdf->job_id_string = xstrdup(s);
1791    xfree(s);
1792    xfree(name_string);
1793    xfree(format_string);
1794}
1795
1796@ @c
1797char *get_resname_prefix(PDF pdf)
1798{
1799    static char name_str[] =
1800        "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
1801    static char prefix[7];      /* make a tag of 6 chars long */
1802    unsigned long crc;
1803    short i;
1804    size_t base = strlen(name_str);
1805    crc = crc32(0L, Z_NULL, 0);
1806    crc =
1807        crc32(crc, (Bytef *) pdf->job_id_string,
1808              (uInt) strlen(pdf->job_id_string));
1809    for (i = 0; i < 6; i++) {
1810        prefix[i] = name_str[crc % base];
1811        crc /= base;
1812    }
1813    prefix[6] = '\0';
1814    return prefix;
1815}
1816
1817@ @c
1818#define mag int_par(mag_code)
1819
1820#define pdf_xform_attr equiv(pdf_xform_attr_loc)
1821#define pdf_xform_resources equiv(pdf_xform_resources_loc)
1822
1823void pdf_begin_page(PDF pdf)
1824{
1825    pdffloat f;
1826    scaled form_margin = 0;     /* was one_bp until SVN4066 */
1827    ensure_output_state(pdf, ST_HEADER_WRITTEN);
1828    init_pdf_pagecalculations(pdf);
1829    if (pdf->page_resources == NULL) {
1830        pdf->page_resources = xtalloc(1, pdf_resource_struct);
1831        pdf->page_resources->resources_tree = NULL;
1832    }
1833    pdf->page_resources->last_resources =
1834        pdf_create_obj(pdf, obj_type_others, 0);
1835    reset_page_resources(pdf);
1836
1837    if (global_shipping_mode == SHIPPING_PAGE) {
1838        pdf->last_page = pdf_get_obj(pdf, obj_type_page, total_pages + 1, 0);
1839        set_obj_aux(pdf, pdf->last_page, 1);    /* mark that this page has been created */
1840        pdf->last_stream = pdf_create_obj(pdf, obj_type_pagestream, 0);
1841        pdf_begin_obj(pdf, pdf->last_stream, OBJSTM_NEVER);
1842        pdf->last_thread = null;
1843        pdf_begin_dict(pdf);
1844        pdflua_begin_page(pdf);
1845    } else {
1846        assert(global_shipping_mode == SHIPPING_FORM);
1847        pdf_begin_obj(pdf, pdf_cur_form, OBJSTM_NEVER);
1848        pdf->last_stream = pdf_cur_form;
1849
1850        /* Write out Form stream header */
1851        pdf_begin_dict(pdf);
1852        pdf_dict_add_name(pdf, "Type", "XObject");
1853        pdf_dict_add_name(pdf, "Subtype", "Form");
1854        if (pdf_xform_attr != null)
1855            pdf_print_toks(pdf, pdf_xform_attr);
1856        if (obj_xform_attr(pdf, pdf_cur_form) != null) {
1857            pdf_print_toks(pdf, obj_xform_attr(pdf, pdf_cur_form));
1858            delete_token_ref(obj_xform_attr(pdf, pdf_cur_form));
1859            set_obj_xform_attr(pdf, pdf_cur_form, null);
1860        }
1861        pdf_add_name(pdf, "BBox");
1862        pdf_begin_array(pdf);
1863        pdf_add_bp(pdf, -form_margin);
1864        pdf_add_bp(pdf, -form_margin);
1865        pdf_add_bp(pdf, pdf->page_size.h + form_margin);
1866        pdf_add_bp(pdf, pdf->page_size.v + form_margin);
1867        pdf_end_array(pdf);
1868        pdf_dict_add_int(pdf, "FormType", 1);
1869        pdf_add_name(pdf, "Matrix");
1870        pdf_begin_array(pdf);
1871        pdf_add_int(pdf, 1);
1872        pdf_add_int(pdf, 0);
1873        pdf_add_int(pdf, 0);
1874        pdf_add_int(pdf, 1);
1875        pdf_add_int(pdf, 0);
1876        pdf_add_int(pdf, 0);
1877        pdf_end_array(pdf);
1878        pdf_dict_add_ref(pdf, "Resources", pdf->page_resources->last_resources);
1879    }
1880    /* Start stream of page/form contents */
1881    pdf_dict_add_streaminfo(pdf);
1882    pdf_end_dict(pdf);
1883    pdf->os->trigger_luastm = false;    /* if it's true, the page stream goes through Lua */
1884    pdf_begin_stream(pdf);
1885    if (global_shipping_mode == SHIPPING_PAGE) {
1886        /* Adjust transformation matrix for the magnification ratio */
1887        if (mag != 1000) {
1888            setpdffloat(f, mag, 3);
1889            print_pdffloat(pdf, f);
1890            pdf_puts(pdf, " 0 0 ");
1891            print_pdffloat(pdf, f);
1892            pdf_puts(pdf, " 0 0 cm\n");
1893        }
1894    }
1895    pos_stack_used = 0;         /* start with empty stack */
1896
1897    if (global_shipping_mode == SHIPPING_PAGE) {
1898        colorstackpagestart();
1899    }
1900    if (global_shipping_mode == SHIPPING_PAGE)
1901        pdf_out_colorstack_startpage(pdf);
1902}
1903
1904@ @c
1905void print_pdf_table_string(PDF pdf, const char *s)
1906{
1907    size_t len;
1908    const char *ls;
1909    lua_rawgeti(Luas, LUA_REGISTRYINDEX, lua_key_index(pdf_data));
1910    lua_rawget(Luas, LUA_REGISTRYINDEX);
1911    lua_pushstring(Luas, s);    /* s t ... */
1912    lua_rawget(Luas, -2);     /* s? t ... */
1913    if (lua_isstring(Luas, -1)) {       /* s t ... */
1914        ls = lua_tolstring(Luas, -1, &len);
1915        if (len > 0) {
1916            if (pdf->cave == 1)
1917                pdf_out(pdf, ' ');
1918            pdf_out_block(pdf, ls, len);
1919            pdf->cave = 1;
1920        }
1921    }
1922    lua_pop(Luas, 2);           /* ... */
1923}
1924
1925@ @c
1926const char *get_pdf_table_string(const char *s)
1927{
1928    const_lstring ls;
1929    lua_rawgeti(Luas, LUA_REGISTRYINDEX, lua_key_index(pdf_data));
1930    lua_rawget(Luas, LUA_REGISTRYINDEX);
1931    lua_pushstring(Luas, s);    /* s t ... */
1932    lua_rawget(Luas, -2);     /* s? t ... */
1933    if (lua_isstring(Luas, -1)) {       /* s t ... */
1934        ls.s = lua_tolstring(Luas, -1, &ls.l);
1935	/*  s is  supposed to be anchored (e.g in the registry)
1936	    so it's not garbage collected */
1937        lua_pop(Luas, 2);           /* ... */
1938	return ls.s;
1939    }
1940    lua_pop(Luas, 2);           /* ... */
1941    return NULL ;
1942}
1943
1944@ @c
1945#define pdf_page_attr equiv(pdf_page_attr_loc)
1946#define pdf_page_resources equiv(pdf_page_resources_loc)
1947
1948void pdf_end_page(PDF pdf)
1949{
1950    char s[64], *p;
1951    int j, annots = 0, beads = 0, callback_id;
1952    pdf_resource_struct *res_p = pdf->page_resources;
1953    pdf_resource_struct local_page_resources;
1954    pdf_object_list *annot_list, *bead_list, *link_list, *ol, *ol1;
1955    scaledpos save_cur_page_size;       /* to save |pdf->page_size| during flushing pending forms */
1956    shipping_mode_e save_shipping_mode;
1957    int procset = PROCSET_PDF;
1958
1959    /* Finish stream of page/form contents */
1960    pdf_goto_pagemode(pdf);
1961    if (pos_stack_used > 0) {
1962        luatex_fail("%u unmatched \\pdfsave after %s shipout",
1963                    (unsigned int) pos_stack_used,
1964                    ((global_shipping_mode ==
1965                      SHIPPING_PAGE) ? "page" : "form"));
1966    }
1967    pdf_end_stream(pdf);
1968    pdf_end_obj(pdf);
1969
1970    /* hh-ls : new call back finish_pdfpage_callback */
1971    callback_id = callback_defined(finish_pdfpage_callback);
1972    if (callback_id > 0)
1973      run_callback(callback_id, "b->",(global_shipping_mode == SHIPPING_PAGE));
1974
1975    if (global_shipping_mode == SHIPPING_PAGE) {
1976
1977        pdf->last_pages = pdf_do_page_divert(pdf, pdf->last_page, 0);
1978
1979        /* Write out /Page object */
1980        pdf_begin_obj(pdf, pdf->last_page, OBJSTM_ALWAYS);
1981        pdf_begin_dict(pdf);
1982        pdf_dict_add_name(pdf, "Type", "Page");
1983        pdf_dict_add_ref(pdf, "Contents", pdf->last_stream);
1984        pdf_dict_add_ref(pdf, "Resources", res_p->last_resources);
1985        pdf_add_name(pdf, "MediaBox");
1986        pdf_begin_array(pdf);
1987        pdf_add_int(pdf, 0);
1988        pdf_add_int(pdf, 0);
1989        pdf_add_mag_bp(pdf, pdf->page_size.h);
1990        pdf_add_mag_bp(pdf, pdf->page_size.v);
1991        pdf_end_array(pdf);
1992        if (pdf_page_attr != null)
1993            pdf_print_toks(pdf, pdf_page_attr);
1994        print_pdf_table_string(pdf, "pageattributes");
1995        pdf_dict_add_ref(pdf, "Parent", pdf->last_pages);
1996        if (pdf->img_page_group_val != 0) {
1997            assert(pdf->img_page_group_val > 0);
1998            pdf_dict_add_ref(pdf, "Group", pdf->img_page_group_val);
1999        }
2000        annot_list = get_page_resources_list(pdf, obj_type_annot);
2001        link_list = get_page_resources_list(pdf, obj_type_link);
2002        if (annot_list != NULL || link_list != NULL) {
2003            annots = pdf_create_obj(pdf, obj_type_annots, 0);
2004            pdf_dict_add_ref(pdf, "Annots", annots);
2005        }
2006        bead_list = get_page_resources_list(pdf, obj_type_bead);
2007        if (bead_list != NULL) {
2008            beads = pdf_create_obj(pdf, obj_type_beads, 0);
2009            pdf_dict_add_ref(pdf, "B", beads);
2010        }
2011        pdf_end_dict(pdf);
2012        pdf_end_obj(pdf);
2013        pdflua_end_page(pdf, annots, beads);
2014
2015        pdf->img_page_group_val = 0;
2016
2017        /* Generate array of annotations or beads in page */
2018        if (annot_list != NULL || link_list != NULL) {
2019            pdf_begin_obj(pdf, annots, OBJSTM_ALWAYS);
2020            pdf_begin_array(pdf);
2021            while (annot_list != NULL) {
2022                assert(annot_list->info > 0);
2023                pdf_add_ref(pdf, annot_list->info);
2024                annot_list = annot_list->link;
2025            }
2026            while (link_list != NULL) {
2027                pdf_add_ref(pdf, link_list->info);
2028                link_list = link_list->link;
2029            }
2030            pdf_end_array(pdf);
2031            pdf_end_obj(pdf);
2032        }
2033        if (bead_list != NULL) {
2034            pdf_begin_obj(pdf, beads, OBJSTM_ALWAYS);
2035            pdf_begin_array(pdf);
2036            while (bead_list != NULL) {
2037                pdf_add_ref(pdf, bead_list->info);
2038                bead_list = bead_list->link;
2039            }
2040            pdf_end_array(pdf);
2041            pdf_end_obj(pdf);
2042        }
2043    }
2044
2045    /* Write out resource lists */
2046    /* Write out pending raw objects */
2047    ol = get_page_resources_list(pdf, obj_type_obj);
2048    while (ol != NULL) {
2049        if (!is_obj_written(pdf, ol->info))
2050            pdf_write_obj(pdf, ol->info);
2051        ol = ol->link;
2052    }
2053
2054    /* Write out pending forms */
2055    /* When flushing pending forms we need to save and restore resource lists
2056       which are also used by page shipping.
2057       Saving and restoring |pdf->page_size| is needed for proper
2058       writing out pending PDF marks. */
2059    ol = get_page_resources_list(pdf, obj_type_xform);
2060    while (ol != NULL) {
2061        if (!is_obj_written(pdf, ol->info)) {
2062            pdf_cur_form = ol->info;
2063            save_cur_page_size = pdf->page_size;
2064            save_shipping_mode = global_shipping_mode;
2065            pdf->page_resources = &local_page_resources;
2066            local_page_resources.resources_tree = NULL;
2067            ship_out(pdf, obj_xform_box(pdf, pdf_cur_form), SHIPPING_FORM);
2068            /* Restore page size and page resources */
2069            pdf->page_size = save_cur_page_size;
2070            global_shipping_mode = save_shipping_mode;
2071            destroy_page_resources_tree(pdf);
2072            pdf->page_resources = res_p;
2073        }
2074        ol = ol->link;
2075    }
2076
2077    /* Write out pending images */
2078    ol = get_page_resources_list(pdf, obj_type_ximage);
2079    while (ol != NULL) {
2080        if (!is_obj_written(pdf, ol->info))
2081            pdf_write_image(pdf, ol->info);
2082        ol = ol->link;
2083    }
2084
2085    if (global_shipping_mode == SHIPPING_PAGE) {
2086        /* Write out pending PDF marks */
2087        /* Write out PDF annotations */
2088        ol = get_page_resources_list(pdf, obj_type_annot);
2089        while (ol != NULL) {
2090            if (ol->info > 0 && obj_type(pdf, ol->info) == obj_type_annot) {
2091                j = obj_annot_ptr(pdf, ol->info);       /* |j| points to |pdf_annot_node| */
2092                pdf_begin_obj(pdf, ol->info, OBJSTM_ALWAYS);
2093                pdf_begin_dict(pdf);
2094                pdf_dict_add_name(pdf, "Type", "Annot");
2095                pdf_print_toks(pdf, pdf_annot_data(j));
2096                pdf_rectangle(pdf, j);
2097                pdf_end_dict(pdf);
2098                pdf_end_obj(pdf);
2099            }
2100            ol = ol->link;
2101        }
2102
2103        /* Write out PDF link annotations */
2104        if ((ol = get_page_resources_list(pdf, obj_type_link)) != NULL) {
2105            while (ol != NULL) {
2106                j = obj_annot_ptr(pdf, ol->info);
2107                pdf_begin_obj(pdf, ol->info, OBJSTM_ALWAYS);
2108                pdf_begin_dict(pdf);
2109                pdf_dict_add_name(pdf, "Type", "Annot");
2110                if (pdf_action_type(pdf_link_action(j)) != pdf_action_user)
2111                    pdf_dict_add_name(pdf, "Subtype", "Link");
2112                if (pdf_link_attr(j) != null)
2113                    pdf_print_toks(pdf, pdf_link_attr(j));
2114                pdf_rectangle(pdf, j);
2115                if (pdf_action_type(pdf_link_action(j)) != pdf_action_user)
2116                    pdf_puts(pdf, "/A ");
2117                write_action(pdf, pdf_link_action(j));
2118                pdf_end_dict(pdf);
2119                pdf_end_obj(pdf);
2120                ol = ol->link;
2121            }
2122            /* Flush |pdf_start_link_node|'s created by |append_link| */
2123            ol = get_page_resources_list(pdf, obj_type_link);
2124            while (ol != NULL) {
2125                j = obj_annot_ptr(pdf, ol->info);
2126                /* nodes with |subtype = pdf_link_data_node| were created by |append_link| and
2127                   must be flushed here, as they are not linked in any list */
2128                if (subtype(j) == pdf_link_data_node)
2129                    flush_node(j);
2130                ol = ol->link;
2131            }
2132        }
2133
2134        /* Write out PDF mark destinations */
2135        write_out_pdf_mark_destinations(pdf);
2136        /* Write out PDF bead rectangle specifications */
2137        print_bead_rectangles(pdf);
2138
2139    }
2140    /* Write out resources dictionary */
2141    pdf_begin_obj(pdf, res_p->last_resources, OBJSTM_ALWAYS);
2142    pdf_begin_dict(pdf);
2143    /* Print additional resources */
2144    if (global_shipping_mode == SHIPPING_PAGE) {
2145        if (pdf_page_resources != null)
2146            pdf_print_toks(pdf, pdf_page_resources);
2147        print_pdf_table_string(pdf, "pageresources");
2148    } else {
2149        if (pdf_xform_resources != null)
2150            pdf_print_toks(pdf, pdf_xform_resources);
2151        if (obj_xform_resources(pdf, pdf_cur_form) != null) {
2152            pdf_print_toks(pdf, obj_xform_resources(pdf, pdf_cur_form));
2153            delete_token_ref(obj_xform_resources(pdf, pdf_cur_form));
2154            set_obj_xform_resources(pdf, pdf_cur_form, null);
2155        }
2156    }
2157
2158    /* Generate font resources */
2159    if ((ol = get_page_resources_list(pdf, obj_type_font)) != NULL) {
2160        pdf_add_name(pdf, "Font");
2161        pdf_begin_dict(pdf);
2162        while (ol != NULL) {
2163            assert(ol->info > 0);       /* always base font: an object number */
2164            p = s;
2165            p += snprintf(p, 20, "F%i", obj_info(pdf, ol->info));
2166            if (pdf->resname_prefix != NULL)
2167                p += snprintf(p, 20, "%s", pdf->resname_prefix);
2168            pdf_dict_add_ref(pdf, s, ol->info);
2169            ol = ol->link;
2170        }
2171        pdf_end_dict(pdf);
2172        procset |= PROCSET_TEXT;
2173    }
2174
2175    /* Generate XObject resources */
2176    ol = get_page_resources_list(pdf, obj_type_xform);
2177    ol1 = get_page_resources_list(pdf, obj_type_ximage);
2178    if (ol != NULL || ol1 != NULL) {
2179        pdf_add_name(pdf, "XObject");
2180        pdf_begin_dict(pdf);
2181        while (ol != NULL) {
2182            p = s;
2183            p += snprintf(p, 20, "Fm%i", obj_info(pdf, ol->info));
2184            if (pdf->resname_prefix != NULL)
2185                p += snprintf(p, 20, "%s", pdf->resname_prefix);
2186            pdf_dict_add_ref(pdf, s, ol->info);
2187            ol = ol->link;
2188        }
2189        while (ol1 != null) {
2190            p = s;
2191            p += snprintf(p, 20, "Im%i", obj_info(pdf, ol1->info));
2192            if (pdf->resname_prefix != NULL)
2193                p += snprintf(p, 20, "%s", pdf->resname_prefix);
2194            pdf_dict_add_ref(pdf, s, ol1->info);
2195            procset |= img_procset(idict_array[obj_data_ptr(pdf, ol1->info)]);
2196            ol1 = ol1->link;
2197        }
2198        pdf_end_dict(pdf);
2199    }
2200
2201    /* Generate ProcSet */
2202    pdf_add_name(pdf, "ProcSet");
2203    pdf_begin_array(pdf);
2204    if ((procset & PROCSET_PDF) != 0)
2205        pdf_add_name(pdf, "PDF");
2206    if ((procset & PROCSET_TEXT) != 0)
2207        pdf_add_name(pdf, "Text");
2208    if ((procset & PROCSET_IMAGE_B) != 0)
2209        pdf_add_name(pdf, "ImageB");
2210    if ((procset & PROCSET_IMAGE_C) != 0)
2211        pdf_add_name(pdf, "ImageC");
2212    if ((procset & PROCSET_IMAGE_I) != 0)
2213        pdf_add_name(pdf, "ImageI");
2214    pdf_end_array(pdf);
2215    pdf_end_dict(pdf);
2216    pdf_end_obj(pdf);
2217}
2218
2219@* Finishing the PDF output file.
2220
2221@ Destinations that have been referenced but don't exists have
2222|obj_dest_ptr=null|. Leaving them undefined might cause troubles for
2223PDF browsers, so we need to fix them; they point to the last page.
2224
2225@c
2226static void check_nonexisting_destinations(PDF pdf)
2227{
2228    int k;
2229    for (k = pdf->head_tab[obj_type_dest]; k != 0; k = obj_link(pdf, k)) {
2230        if (obj_dest_ptr(pdf, k) == null) {
2231            pdf_warning("dest", NULL, false, false);
2232            if (obj_info(pdf, k) < 0) {
2233                tprint("name{");
2234                print(-obj_info(pdf, k));
2235                tprint("}");
2236            } else {
2237                tprint("num");
2238                print_int(obj_info(pdf, k));
2239            }
2240            tprint
2241                (" has been referenced but does not exist, replaced by a fixed one");
2242            print_ln();
2243            print_ln();
2244
2245            pdf_begin_obj(pdf, k, OBJSTM_ALWAYS);
2246            pdf_begin_array(pdf);
2247            pdf_add_ref(pdf, pdf->last_page);
2248            pdf_add_name(pdf, "Fit");
2249            pdf_end_array(pdf);
2250            pdf_end_obj(pdf);
2251        }
2252    }
2253}
2254
2255@ @c
2256static void check_nonexisting_pages(PDF pdf)
2257{
2258    struct avl_traverser t;
2259    oentry *p;
2260    struct avl_table *page_tree = pdf->obj_tree[obj_type_page];
2261    avl_t_init(&t, page_tree);
2262    /* search from the end backward until the last real page is found */
2263    for (p = avl_t_last(&t, page_tree);
2264         p != NULL && obj_aux(pdf, p->objptr) == 0; p = avl_t_prev(&t)) {
2265        pdf_warning("dest", "Page ", false, false);
2266        print_int(obj_info(pdf, p->objptr));
2267        tprint(" has been referenced but does not exist!");
2268        print_ln();
2269        print_ln();
2270    }
2271}
2272
2273@ If the same keys in a dictionary are given several times, then it is not
2274defined which value is choosen by an application.  Therefore the keys
2275|/Producer| and |/Creator| are only set if the token list
2276|pdf_info_toks| converted to a string does not contain these key strings.
2277
2278@c
2279static boolean substr_of_str(const char *s, const char *t)
2280{
2281    if (strstr(t, s) == NULL)
2282        return false;
2283    return true;
2284}
2285
2286static int pdf_print_info(PDF pdf, int luatexversion,
2287                          str_number luatexrevision)
2288{                               /* print info object */
2289    boolean creator_given, producer_given, creationdate_given, moddate_given,
2290        trapped_given;
2291    char *s = NULL;
2292    const char *p = NULL;
2293    int k, len = 0;
2294    k = pdf_create_obj(pdf, obj_type_info, 0);
2295    pdf_begin_obj(pdf, k, 3);   /* keep Info readable unless explicitely forced */
2296    creator_given = false;
2297    producer_given = false;
2298    creationdate_given = false;
2299    moddate_given = false;
2300    trapped_given = false;
2301    pdf_begin_dict(pdf);
2302    if (pdf_info_toks != 0) {
2303        s = tokenlist_to_cstring(pdf_info_toks, true, &len);
2304        creator_given = substr_of_str("/Creator", s);
2305        producer_given = substr_of_str("/Producer", s);
2306        creationdate_given = substr_of_str("/CreationDate", s);
2307        moddate_given = substr_of_str("/ModDate", s);
2308        trapped_given = substr_of_str("/Trapped", s);
2309    }
2310    p = get_pdf_table_string("info");
2311    if (p && strlen(p) > 0) {
2312        creator_given = creator_given || substr_of_str("/Creator", p);
2313        producer_given = producer_given || substr_of_str("/Producer", p);
2314        creationdate_given = creationdate_given || substr_of_str("/CreationDate", p);
2315        moddate_given = moddate_given || substr_of_str("/ModDate", p);
2316        trapped_given = trapped_given || substr_of_str("/Trapped", p);
2317    }
2318    if (pdf_info_toks != null) {
2319        if (len > 0) {
2320            pdf_out(pdf, '\n');
2321            pdf_puts(pdf, s);
2322            pdf_out(pdf, '\n');
2323            xfree(s);
2324        }
2325        delete_token_ref(pdf_info_toks);
2326        pdf_info_toks = null;
2327    }
2328    if (p && strlen(p) > 0) {
2329        pdf_out(pdf, '\n');
2330        pdf_puts(pdf, p); /* no free, pointer */
2331        pdf_out(pdf, '\n');
2332    }
2333    if (!producer_given) {
2334        /* Print the Producer key */
2335        pdf_add_name(pdf, "Producer");
2336        pdf_puts(pdf, " (LuaTeX-");
2337        pdf_print_int(pdf, luatexversion / 100);
2338        pdf_out(pdf, '.');
2339        pdf_print_int(pdf, luatexversion % 100);
2340        pdf_out(pdf, '.');
2341        pdf_print(pdf, luatexrevision);
2342        pdf_out(pdf, ')');
2343    }
2344    if (!creator_given)
2345        pdf_dict_add_string(pdf, "Creator", "TeX");
2346    if (!creationdate_given) {
2347        init_start_time(pdf);
2348        pdf_dict_add_string(pdf, "CreationDate", pdf->start_time_str);
2349    }
2350    if (!moddate_given) {
2351        init_start_time(pdf);
2352        pdf_dict_add_string(pdf, "ModDate", pdf->start_time_str);
2353    }
2354    if (!trapped_given) {
2355        pdf_dict_add_name(pdf, "Trapped", "False");
2356    }
2357    pdf_dict_add_string(pdf, "PTEX.Fullbanner", luatex_banner);
2358    pdf_end_dict(pdf);
2359    pdf_end_obj(pdf);
2360    return k;
2361}
2362
2363static void build_free_object_list(PDF pdf)
2364{
2365    int k, l;
2366    l = 0;
2367    set_obj_fresh(pdf, l);      /* null object at begin of list of free objects */
2368    for (k = 1; k <= pdf->obj_ptr; k++) {
2369        if (!is_obj_written(pdf, k)) {
2370            set_obj_link(pdf, l, k);
2371            l = k;
2372        }
2373    }
2374    set_obj_link(pdf, l, 0);
2375}
2376
2377@ Now the finish of PDF output file. At this moment all Page objects
2378are already written completely to PDF output file.
2379
2380@c
2381void finish_pdf_file(PDF pdf, int luatexversion, str_number luatexrevision)
2382{
2383    int i, j, k;
2384    int root, info, xref_stm = 0, outlines, threads, names_tree;
2385    size_t xref_offset_width;
2386    int callback_id = callback_defined(stop_run_callback);
2387    int callback_id1 = callback_defined(finish_pdffile_callback);
2388
2389    if (total_pages == 0) {
2390        if (callback_id == 0) {
2391            tprint_nl("No pages of output.");
2392            print_ln();
2393        } else if (callback_id > 0) {
2394            run_callback(callback_id, "->");
2395        }
2396        if (pdf->gone > 0)
2397            garbage_warning();
2398    } else {
2399        if (pdf->draftmode == 0) {
2400            pdf_flush(pdf);     /* to make sure that the output file name has been already created */
2401            flush_jbig2_page0_objects(pdf);     /* flush page 0 objects from JBIG2 images, if any */
2402            if (callback_id1 > 0)
2403                run_callback(callback_id1, "->");
2404
2405            check_nonexisting_pages(pdf);
2406            check_nonexisting_destinations(pdf);
2407
2408            /* Output fonts definition */
2409            for (k = 1; k <= max_font_id(); k++) {
2410                if (font_used(k) && (pdf_font_num(k) < 0)) {
2411                    i = -pdf_font_num(k);
2412                    assert(pdf_font_num(i) > 0);
2413                    for (j = font_bc(k); j <= font_ec(k); j++)
2414                        if (quick_char_exists(k, j) && pdf_char_marked(k, j))
2415                            pdf_mark_char(i, j);
2416                    if ((pdf_font_attr(i) == 0) && (pdf_font_attr(k) != 0)) {
2417                        set_pdf_font_attr(i, pdf_font_attr(k));
2418                    } else if ((pdf_font_attr(k) == 0)
2419                               && (pdf_font_attr(i) != 0)) {
2420                        set_pdf_font_attr(k, pdf_font_attr(i));
2421                    } else if ((pdf_font_attr(i) != 0)
2422                               && (pdf_font_attr(k) != 0)
2423                               &&
2424                               (!str_eq_str
2425                                (pdf_font_attr(i), pdf_font_attr(k)))) {
2426                        pdf_warning("\\pdffontattr", "fonts ", false, false);
2427                        print_font_identifier(i);
2428                        tprint(" and ");
2429                        print_font_identifier(k);
2430                        tprint
2431                            (" have conflicting attributes; I will ignore the attributes assigned to ");
2432                        print_font_identifier(i);
2433                        print_ln();
2434                        print_ln();
2435                    }
2436                }
2437            }
2438            pdf->gen_tounicode = pdf_gen_tounicode;
2439            k = pdf->head_tab[obj_type_font];
2440            while (k != 0) {
2441                int f = obj_info(pdf, k);
2442                assert(pdf_font_num(f) > 0);
2443                assert(pdf_font_num(f) == k);
2444                do_pdf_font(pdf, f);
2445                k = obj_link(pdf, k);
2446            }
2447            write_fontstuff(pdf);
2448
2449            pdf->last_pages = output_pages_tree(pdf);
2450            pdflua_output_pages_tree(pdf);
2451            /* Output outlines */
2452            outlines = print_outlines(pdf);
2453
2454            /* Output name tree */
2455            /* The name tree is very similiar to Pages tree so its construction should be
2456               certain from Pages tree construction. For intermediate node |obj_info| will be
2457               the first name and |obj_link| will be the last name in \.{\\Limits} array.
2458               Note that |pdf_dest_names_ptr| will be less than |obj_ptr|, so we test if
2459               |k < pdf_dest_names_ptr| then |k| is index of leaf in |dest_names|; else
2460               |k| will be index in |obj_tab| of some intermediate node.
2461             */
2462            names_tree = output_name_tree(pdf);
2463
2464            /* Output article threads */
2465            if (pdf->head_tab[obj_type_thread] != 0) {
2466                threads = pdf_create_obj(pdf, obj_type_others, 0);
2467                pdf_begin_obj(pdf, threads, OBJSTM_ALWAYS);
2468                pdf_begin_array(pdf);
2469                k = pdf->head_tab[obj_type_thread];
2470                while (k != 0) {
2471                    pdf_add_ref(pdf, k);
2472                    k = obj_link(pdf, k);
2473                }
2474                pdf_end_array(pdf);
2475                pdf_end_obj(pdf);
2476                k = pdf->head_tab[obj_type_thread];
2477                while (k != 0) {
2478                    out_thread(pdf, k);
2479                    k = obj_link(pdf, k);
2480                }
2481            } else {
2482                threads = 0;
2483            }
2484
2485            /* Output the /Catalog object */
2486            root = pdf_create_obj(pdf, obj_type_catalog, 0);
2487            pdf_begin_obj(pdf, root, OBJSTM_ALWAYS);
2488            pdf_begin_dict(pdf);
2489            pdf_dict_add_name(pdf, "Type", "Catalog");
2490            pdf_dict_add_ref(pdf, "Pages", pdf->last_pages);
2491            if (threads != 0)
2492                pdf_dict_add_ref(pdf, "Threads", threads);
2493            if (outlines != 0)
2494                pdf_dict_add_ref(pdf, "Outlines", outlines);
2495            if (names_tree != 0)
2496                pdf_dict_add_ref(pdf, "Names", names_tree);
2497            if (pdf_catalog_toks != null) {
2498                pdf_print_toks(pdf, pdf_catalog_toks);
2499                delete_token_ref(pdf_catalog_toks);
2500                pdf_catalog_toks = null;
2501            }
2502            print_pdf_table_string(pdf, "catalog");
2503            if (pdf_catalog_openaction != 0)
2504                pdf_dict_add_ref(pdf, "OpenAction", pdf_catalog_openaction);
2505            pdf_end_dict(pdf);
2506            pdf_end_obj(pdf);
2507
2508            /* last candidate for object stream */
2509            info = pdf_print_info(pdf, luatexversion, luatexrevision);  /* final object for pdf->os_enable == false */
2510
2511            if (pdf->os_enable) {
2512                pdf_buffer_select(pdf, OBJSTM_BUF);
2513                pdf_os_write_objstream(pdf);
2514                pdf_flush(pdf);
2515                pdf_buffer_select(pdf, PDFOUT_BUF);
2516                /* Output the cross-reference stream dictionary */
2517                xref_stm = pdf_create_obj(pdf, obj_type_others, 0);
2518                pdf_begin_obj(pdf, xref_stm, OBJSTM_NEVER);     /* final object for pdf->os_enable == true */
2519                if ((obj_offset(pdf, pdf->obj_ptr) / 256) > 16777215)
2520                    xref_offset_width = 5;
2521                else if (obj_offset(pdf, pdf->obj_ptr) > 16777215)
2522                    xref_offset_width = 4;
2523                else if (obj_offset(pdf, pdf->obj_ptr) > 65535)
2524                    xref_offset_width = 3;
2525                else
2526                    xref_offset_width = 2;
2527                /* Build a linked list of free objects */
2528                build_free_object_list(pdf);
2529                pdf_begin_dict(pdf);
2530                pdf_dict_add_name(pdf, "Type", "XRef");
2531                pdf_add_name(pdf, "Index");
2532                pdf_begin_array(pdf);
2533                pdf_add_int(pdf, 0);
2534                pdf_add_int(pdf, pdf->obj_ptr + 1);
2535                pdf_end_array(pdf);
2536                pdf_dict_add_int(pdf, "Size", pdf->obj_ptr + 1);
2537                pdf_add_name(pdf, "W");
2538                pdf_begin_array(pdf);
2539                pdf_add_int(pdf, 1);
2540                pdf_add_int(pdf, (int) xref_offset_width);
2541                pdf_add_int(pdf, 1);
2542                pdf_end_array(pdf);
2543                pdf_dict_add_ref(pdf, "Root", root);
2544                pdf_dict_add_ref(pdf, "Info", info);
2545                if (pdf_trailer_toks != null) {
2546                    pdf_print_toks(pdf, pdf_trailer_toks);
2547                    delete_token_ref(pdf_trailer_toks);
2548                    pdf_trailer_toks = null;
2549                }
2550                print_pdf_table_string(pdf, "trailer");
2551                print_ID(pdf);
2552                pdf_dict_add_streaminfo(pdf);
2553                pdf_end_dict(pdf);
2554                pdf_begin_stream(pdf);
2555                for (k = 0; k <= pdf->obj_ptr; k++) {
2556                    if (!is_obj_written(pdf, k)) {      /* a free object */
2557                        pdf_out(pdf, 0);
2558                        pdf_out_bytes(pdf, obj_link(pdf, k), xref_offset_width);
2559                        pdf_out(pdf, 255);
2560                    } else if (obj_os_idx(pdf, k) == PDF_OS_MAX_OBJS) { /* object not in object stream */
2561                        pdf_out(pdf, 1);
2562                        pdf_out_bytes(pdf, obj_offset(pdf, k),
2563                                      xref_offset_width);
2564                        pdf_out(pdf, 0);
2565                    } else {    /* object in object stream */
2566                        pdf_out(pdf, 2);
2567                        pdf_out_bytes(pdf, obj_offset(pdf, k),
2568                                      xref_offset_width);
2569                        pdf_out(pdf, obj_os_idx(pdf, k));
2570                    }
2571                }
2572                pdf_end_stream(pdf);
2573                pdf_end_obj(pdf);
2574                /* TODO: generate a debug version of the crossref */
2575
2576                pdf_flush(pdf);
2577            } else {
2578                /* Output the |obj_tab| */
2579                /* Build a linked list of free objects */
2580                build_free_object_list(pdf);
2581
2582                pdf_save_offset(pdf);
2583                pdf_puts(pdf, "xref\n");
2584                pdf_puts(pdf, "0 ");
2585                pdf_print_int_ln(pdf, pdf->obj_ptr + 1);
2586                pdf_print_fw_int(pdf, obj_link(pdf, 0), 10);
2587                pdf_puts(pdf, " 65535 f \n");
2588                for (k = 1; k <= pdf->obj_ptr; k++) {
2589                    if (!is_obj_written(pdf, k)) {
2590                        pdf_print_fw_int(pdf, obj_link(pdf, k), 10);
2591                        pdf_puts(pdf, " 00000 f \n");
2592                    } else {
2593                        pdf_print_fw_int(pdf, obj_offset(pdf, k), 10);
2594                        pdf_puts(pdf, " 00000 n \n");
2595                    }
2596                }
2597
2598            }
2599
2600            /* Output the trailer */
2601            if (!pdf->os_enable) {
2602                pdf_puts(pdf, "trailer\n");
2603                pdf_begin_dict(pdf);
2604                pdf_dict_add_int(pdf, "Size", pdf->obj_ptr + 1);
2605                pdf_dict_add_ref(pdf, "Root", root);
2606                pdf_dict_add_ref(pdf, "Info", info);
2607                if (pdf_trailer_toks != null) {
2608                    pdf_print_toks(pdf, pdf_trailer_toks);
2609                    delete_token_ref(pdf_trailer_toks);
2610                    pdf_trailer_toks = null;
2611                }
2612                print_ID(pdf);
2613                pdf_end_dict(pdf);
2614                pdf_out(pdf, '\n');
2615            }
2616            pdf_puts(pdf, "startxref\n");
2617            pdf->cave = 0;
2618            if (pdf->os_enable)
2619                pdf_add_longint(pdf, (longinteger) obj_offset(pdf, xref_stm));
2620            else
2621                pdf_add_longint(pdf, (longinteger) pdf->save_offset);
2622            pdf_puts(pdf, "\n%%EOF\n");
2623
2624            pdf_flush(pdf);
2625
2626            if (callback_id == 0) {
2627                tprint_nl("Output written on ");
2628                tprint(pdf->file_name);
2629                tprint(" (");
2630                print_int(total_pages);
2631                tprint(" page");
2632                if (total_pages != 1)
2633                    print_char('s');
2634                tprint(", ");
2635                print_int(pdf_offset(pdf));
2636                tprint(" bytes).");
2637                print_ln();
2638            } else if (callback_id > 0) {
2639                run_callback(callback_id, "->");
2640            }
2641        }
2642        libpdffinish(pdf);
2643        if (pdf->draftmode == 0)
2644            close_file(pdf->file);
2645        else
2646            pdf_warning(NULL,
2647                        "\\pdfdraftmode enabled, not changing output pdf",
2648                        true, true);
2649    }
2650
2651    if (callback_id == 0) {
2652        if (log_opened_global) {
2653            fprintf(log_file,
2654                    "\nPDF statistics: %d PDF objects out of %d (max. %d)\n",
2655                    (int) pdf->obj_ptr, (int) pdf->obj_tab_size,
2656                    (int) sup_obj_tab_size);
2657            if (pdf->os->ostm_ctr > 0) {
2658                fprintf(log_file,
2659                        " %d compressed objects within %d object stream%s\n",
2660                        (int) pdf->os->o_ctr, (int) pdf->os->ostm_ctr,
2661                        (pdf->os->ostm_ctr > 1 ? "s" : ""));
2662            }
2663            fprintf(log_file, " %d named destinations out of %d (max. %d)\n",
2664                    (int) pdf->dest_names_ptr, (int) pdf->dest_names_size,
2665                    (int) sup_dest_names_size);
2666            fprintf(log_file,
2667                    " %d words of extra memory for PDF output out of %d (max. %d)\n",
2668                    (int) pdf->mem_ptr, (int) pdf->mem_size,
2669                    (int) sup_pdf_mem_size);
2670        }
2671    }
2672}
2673
2674@ @c
2675void scan_pdfcatalog(PDF pdf)
2676{
2677    halfword p;
2678    scan_pdf_ext_toks();
2679    pdf_catalog_toks = concat_tokens(pdf_catalog_toks, def_ref);
2680    if (scan_keyword("openaction")) {
2681        if (pdf_catalog_openaction != 0) {
2682            pdf_error("ext1", "duplicate of openaction");
2683        } else {
2684            check_o_mode(pdf, "\\pdfcatalog", 1 << OMODE_PDF, true);
2685            p = scan_action(pdf);
2686            pdf_catalog_openaction = pdf_create_obj(pdf, obj_type_others, 0);
2687            pdf_begin_obj(pdf, pdf_catalog_openaction, OBJSTM_ALWAYS);
2688            write_action(pdf, p);
2689            pdf_end_obj(pdf);
2690            delete_action_ref(p);
2691        }
2692    }
2693}
2694