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