summaryrefslogtreecommitdiff
path: root/Build/source/texk/web2c/luatexdir/pdf/pdfgen.w
diff options
context:
space:
mode:
Diffstat (limited to 'Build/source/texk/web2c/luatexdir/pdf/pdfgen.w')
-rw-r--r--Build/source/texk/web2c/luatexdir/pdf/pdfgen.w1499
1 files changed, 810 insertions, 689 deletions
diff --git a/Build/source/texk/web2c/luatexdir/pdf/pdfgen.w b/Build/source/texk/web2c/luatexdir/pdf/pdfgen.w
index 3543ec3b5ef..8e2ab31177f 100644
--- a/Build/source/texk/web2c/luatexdir/pdf/pdfgen.w
+++ b/Build/source/texk/web2c/luatexdir/pdf/pdfgen.w
@@ -1,26 +1,26 @@
% pdfgen.w
-
-% Copyright 2009-2010 Taco Hoekwater <taco@@luatex.org>
-
+%
+% Copyright 2009-2013 Taco Hoekwater <taco@@luatex.org>
+%
% This file is part of LuaTeX.
-
+%
% LuaTeX is free software; you can redistribute it and/or modify it under
% the terms of the GNU General Public License as published by the Free
% Software Foundation; either version 2 of the License, or (at your
% option) any later version.
-
+%
% LuaTeX is distributed in the hope that it will be useful, but WITHOUT
% ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
% FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
% License for more details.
-
+%
% You should have received a copy of the GNU General Public License along
% with LuaTeX; if not, see <http://www.gnu.org/licenses/>.
@ @c
static const char _svn_version[] =
- "$Id: pdfgen.w 4253 2011-05-09 11:13:00Z taco $"
- "$URL: http://foundry.supelec.fr/svn/luatex/branches/0.70.x/source/texk/web2c/luatexdir/pdf/pdfgen.w $";
+ "$Id: pdfgen.w 4568 2013-01-27 13:10:11Z hhenkel $"
+ "$URL: http://foundry.supelec.fr/svn/luatex/trunk/source/texk/web2c/luatexdir/pdf/pdfgen.w $";
#include "ptexlib.h"
@@ -38,8 +38,6 @@ static const char _svn_version[] =
PDF static_pdf = NULL;
-static char *jobname_cstr = NULL;
-
@ commandline interface
@c
int pdf_output_option;
@@ -54,26 +52,114 @@ halfword pdf_names_toks; /* additional keys of Names dictionary */
halfword pdf_trailer_toks; /* additional keys of Trailer dictionary */
shipping_mode_e global_shipping_mode = NOT_SHIPPING; /* set to |shipping_mode| when |ship_out| starts */
-@ |init_pdf_struct()| is called early, only once, from maincontrol.w
+@ Create a new buffer |strbuf_s| of size |size| and maximum allowed size |limit|.
+Initialize it and set |p| to begin of data.
+@c
+strbuf_s *new_strbuf(size_t size, size_t limit)
+{
+ strbuf_s *b;
+ assert(limit >= size);
+ b = xtalloc(1, strbuf_s);
+ b->size = size;
+ b->limit = limit;
+ if (size > 0)
+ b->p = b->data = xtalloc(b->size, unsigned char);
+ else
+ b->p = b->data = NULL; /* for other alloc */
+ return b;
+}
+
+@ Check that |n| bytes more fit into buffer; increase it if required.
+@c
+static void strbuf_room(strbuf_s * b, size_t n)
+{
+ unsigned int a;
+ size_t l = (size_t) (b->p - b->data);
+ if (n > b->limit - l)
+ overflow("PDF buffer", (unsigned) b->size);
+ if (n + l > b->size) {
+ a = (unsigned int) (b->size >> 2);
+ if (n + l > b->size + a)
+ b->size = n + l;
+ else if (b->size < b->limit - a)
+ b->size = b->size + a;
+ else
+ b->size = b->limit;
+ b->data = xreallocarray(b->data, unsigned char, (unsigned) b->size);
+ b->p = b->data + l;
+ }
+}
+
+@ Seek to position |offset| within buffer. Position must be valid.
+@c
+void strbuf_seek(strbuf_s * b, off_t offset)
+{
+ assert(offset >= 0 && offset < (off_t) b->size);
+ b->p = b->data + offset;
+}
+
+@ Get the current buffer fill level, the number of characters.
+@c
+size_t strbuf_offset(strbuf_s * b)
+{
+ return (size_t) (b->p - b->data);
+}
+
+@ Put one character into buffer. Make room before if needed.
+@c
+void strbuf_putchar(strbuf_s * b, unsigned char c)
+{
+ if ((size_t) (b->p - b->data + 1) > b->size)
+ strbuf_room(b, 1);
+ *b->p++ = c;
+}
+@ Dump filled buffer part to PDF.
+@c
+void strbuf_flush(PDF pdf, strbuf_s * b)
+{
+ pdf_out_block(pdf, (const char *) b->data, strbuf_offset(b));
+ strbuf_seek(b, 0);
+}
+
+@ Free all dynamically allocated buffer structures.
+@c
+void strbuf_free(strbuf_s * b)
+{
+ xfree(b->data);
+ xfree(b);
+}
+
+@ |init_pdf_struct()| is called early, only once, from maincontrol.w
@c
PDF init_pdf_struct(PDF pdf)
{
+ os_struct *os;
assert(pdf == NULL);
pdf = xtalloc(1, pdf_output_file);
memset(pdf, 0, sizeof(pdf_output_file));
+ pdf->job_name = makecstring(job_name);
pdf->o_mode = OMODE_NONE; /* will be set by |fix_o_mode()| */
pdf->o_state = ST_INITIAL;
- pdf->os_obj = xtalloc(pdf_os_max_objs, os_obj_data);
- pdf->os_buf_size = inf_pdf_os_buf_size;
- pdf->os_buf = xtalloc(pdf->os_buf_size, unsigned char);
- pdf->op_buf_size = inf_pdf_op_buf_size;
- pdf->op_buf = xtalloc(pdf->op_buf_size, unsigned char);
+ /* init PDF and object stream writing */
+ pdf->os = os = xtalloc(1, os_struct);
+ memset(pdf->os, 0, sizeof(os_struct));
+ os->buf[PDFOUT_BUF] = new_strbuf(inf_pdfout_buf_size, sup_pdfout_buf_size);
+ os->buf[OBJSTM_BUF] = new_strbuf(inf_objstm_buf_size, sup_objstm_buf_size);
+ os->buf[LUASTM_BUF] = new_strbuf(0, 0);
+ os->obj = xtalloc(PDF_OS_MAX_OBJS, os_obj_data);
+ os->cur_objstm = 0;
+ os->trigger_luastm = false;
+
+ os->curbuf = PDFOUT_BUF;
+ pdf->buf = os->buf[os->curbuf];
- pdf->buf_size = pdf->op_buf_size;
- pdf->buf = pdf->op_buf;
+ pdf->fb = new_strbuf(1, 100000000);
+
+ pdf->stream_deflate = false;
+ pdf->stream_writing = false;
/* Sometimes it is neccesary to allocate memory for PDF output that cannot
be deallocated then, so we use |mem| for this purpose. */
@@ -112,26 +198,9 @@ PDF init_pdf_struct(PDF pdf)
init_pdf_pagecalculations(pdf);
pdf->pdflua_ref = new_pdflua();
- return pdf;
-}
-
-@ @c
-static void pdf_shipout_begin(void)
-{
- pos_stack_used = 0; /* start with empty stack */
-
- if (global_shipping_mode == SHIPPING_PAGE) {
- colorstackpagestart();
- }
-}
+ pdf->vfstruct = new_vfstruct();
-static void pdf_shipout_end(void)
-{
- if (pos_stack_used > 0) {
- pdftex_fail("%u unmatched \\pdfsave after %s shipout",
- (unsigned int) pos_stack_used,
- ((global_shipping_mode == SHIPPING_PAGE) ? "page" : "form"));
- }
+ return pdf;
}
@ We use |pdf_get_mem| to allocate memory in |mem|.
@@ -144,7 +213,7 @@ int pdf_get_mem(PDF pdf, int s)
if (s > sup_pdf_mem_size - pdf->mem_ptr)
overflow("PDF memory size (pdf_mem_size)", (unsigned) pdf->mem_size);
if (pdf->mem_ptr + s > pdf->mem_size) {
- a = pdf->mem_size / 5;
+ a = pdf->mem_size >> 2;
if (pdf->mem_ptr + s > pdf->mem_size + a) {
pdf->mem_size = pdf->mem_ptr + s;
} else if (pdf->mem_size < sup_pdf_mem_size - a) {
@@ -238,8 +307,9 @@ static void write_zip(PDF pdf)
{
int flush, err = Z_OK;
uInt zip_len;
+ strbuf_s *buf = pdf->buf;
z_stream *s = pdf->c_stream;
- boolean finish = pdf->zip_write_state == zip_finish;
+ boolean finish = pdf->zip_write_state == ZIP_FINISH;
assert(pdf->compress_level > 0);
/* This was just to suppress the filename report in |pdftex_fail|
but zlib errors are rare enough (especially now that the
@@ -265,8 +335,8 @@ static void write_zip(PDF pdf)
}
assert(s != NULL);
assert(pdf->zipbuf != NULL);
- s->next_in = pdf->buf;
- s->avail_in = (uInt) pdf->ptr;
+ s->next_in = buf->data;
+ s->avail_in = (uInt) (buf->p - buf->data);
while (true) {
if (s->avail_out == 0 || (finish && s->avail_out < ZIP_BUF_SIZE)) {
zip_len = ZIP_BUF_SIZE - s->avail_out;
@@ -280,6 +350,7 @@ static void write_zip(PDF pdf)
assert(s->avail_in == 0);
assert(s->avail_out == ZIP_BUF_SIZE);
xfflush(pdf->file);
+ pdf->zip_write_state = NO_ZIP;
break;
}
flush = Z_FINISH;
@@ -305,6 +376,19 @@ void zip_free(PDF pdf)
xfree(pdf->c_stream);
}
+@ @c
+static void write_nozip(PDF pdf)
+{
+ strbuf_s *buf = pdf->buf;
+ size_t l = strbuf_offset(buf);
+ if (l == 0)
+ return;
+ pdf->stream_length = pdf_offset(pdf) - pdf->save_offset;
+ pdf->gone +=
+ (off_t) xfwrite((char *) buf->data, sizeof(char), l, pdf->file);
+ pdf->last_byte = *(buf->p - 1);
+}
+
@ The PDF buffer is flushed by calling |pdf_flush|, which checks the
variable |zip_write_state| and will compress the buffer before flushing if
neccesary. We call |pdf_begin_stream| to begin a stream and |pdf_end_stream|
@@ -312,173 +396,146 @@ to finish it. The stream contents will be compressed if compression is turn on.
@c
void pdf_flush(PDF pdf)
-{ /* flush out the |pdf_buf| */
-
- off_t saved_pdf_gone;
- if (!pdf->os_mode) {
- saved_pdf_gone = pdf->gone;
- switch (pdf->zip_write_state) {
- case no_zip:
- if (pdf->ptr > 0) {
- if (pdf->draftmode == 0)
- (void) xfwrite((char *) pdf->buf, sizeof(char),
- (size_t) pdf->ptr, pdf->file);
- pdf->gone += pdf->ptr;
- pdf->last_byte = pdf->buf[pdf->ptr - 1];
- }
- break;
- case zip_writing:
- if (pdf->draftmode == 0)
- write_zip(pdf);
- break;
- case zip_finish:
- if (pdf->draftmode == 0)
+{ /* flush out the |pdf->buf| */
+ os_struct *os = pdf->os;
+ off_t saved_pdf_gone = pdf->gone;
+ assert(pdf->buf == os->buf[os->curbuf]);
+ switch (os->curbuf) {
+ case PDFOUT_BUF:
+ if (pdf->draftmode == 0) {
+ switch (pdf->zip_write_state) {
+ case NO_ZIP:
+ write_nozip(pdf);
+ break;
+ case ZIP_WRITING:
+ case ZIP_FINISH:
write_zip(pdf);
- pdf->zip_write_state = no_zip;
- break;
- }
- pdf->ptr = 0;
+ break;
+ default:
+ assert(0);
+ }
+ } else
+ pdf->zip_write_state = NO_ZIP;
+ strbuf_seek(pdf->buf, 0);
if (saved_pdf_gone > pdf->gone)
pdf_error("file size",
"File size exceeds architectural limits (pdf_gone wraps around)");
+ break;
+ case LUASTM_BUF:
+ luaL_addsize(&(os->b), strbuf_offset(pdf->buf));
+ pdf->buf->p = pdf->buf->data = (unsigned char *) luaL_prepbuffer(&(os->b)); /* for next stream piece */
+ break;
+ case OBJSTM_BUF:
+ break;
+ default:
+ assert(0);
}
}
-@ switch between PDF stream and object stream mode
-
-@c
-static void pdf_os_switch(PDF pdf, boolean pdf_os)
-{
- if (pdf_os && pdf->os_enable) {
- if (!pdf->os_mode) { /* back up PDF stream variables */
- pdf->op_ptr = pdf->ptr;
- pdf->ptr = pdf->os_ptr;
- pdf->buf = pdf->os_buf;
- pdf->buf_size = pdf->os_buf_size;
- pdf->os_mode = true; /* switch to object stream */
- }
- } else {
- if (pdf->os_mode) { /* back up object stream variables */
- pdf->os_ptr = pdf->ptr;
- pdf->ptr = pdf->op_ptr;
- pdf->buf = pdf->op_buf;
- pdf->buf_size = pdf->op_buf_size;
- pdf->os_mode = false; /* switch to PDF stream */
- }
- }
+@ @c
+static void pdf_buffer_select(PDF pdf, buffer_e buf)
+{
+ os_struct *os = pdf->os;
+ if (pdf->os_enable && buf == OBJSTM_BUF)
+ os->curbuf = OBJSTM_BUF; /* switch to object stream */
+ else
+ os->curbuf = PDFOUT_BUF; /* switch to PDF stream */
+ pdf->buf = os->buf[pdf->os->curbuf];
}
-@ create new \.{/ObjStm} object if required, and set up cross reference info
+@ create new \.{/ObjStm} object if required, and set up cross reference info
@c
-static void pdf_os_prepare_obj(PDF pdf, int i, int pdf_os_level)
-{
- pdf_os_switch(pdf, ((pdf_os_level > 0)
- && (pdf->objcompresslevel >= pdf_os_level)));
- if (pdf->os_mode) {
- if (pdf->os_cur_objnum == 0) {
- pdf->os_cur_objnum =
- pdf_create_obj(pdf, obj_type_objstm, pdf->obj_ptr + 1);
- pdf->os_cntr++; /* only for statistics */
- pdf->os_idx = 0;
- pdf->ptr = 0; /* start fresh object stream */
- } else {
- pdf->os_idx++;
+static void pdf_prepare_obj(PDF pdf, int k, int pdf_os_threshold)
+{
+ os_struct *os = pdf->os;
+ strbuf_s *obuf = os->buf[OBJSTM_BUF];
+ assert(os->curbuf != LUASTM_BUF);
+ assert(pdf_os_threshold >= OBJSTM_ALWAYS);
+ if (pdf->objcompresslevel >= pdf_os_threshold)
+ pdf_buffer_select(pdf, OBJSTM_BUF);
+ else
+ pdf_buffer_select(pdf, PDFOUT_BUF);
+ assert(pdf->buf == os->buf[os->curbuf]);
+ switch (os->curbuf) {
+ case PDFOUT_BUF:
+ obj_offset(pdf, k) = pdf_offset(pdf);
+ obj_os_idx(pdf, k) = PDF_OS_MAX_OBJS; /* mark it as not included in any ObjStm */
+ break;
+ case LUASTM_BUF:
+ assert(0);
+ break;
+ case OBJSTM_BUF:
+ if (os->cur_objstm == 0) {
+ os->cur_objstm =
+ (unsigned int) pdf_create_obj(pdf, obj_type_objstm, 0);
+ os->idx = 0;
+ obuf->p = obuf->data; /* start fresh object stream */
+ os->ostm_ctr++; /* only for statistics */
}
- obj_os_idx(pdf, i) = pdf->os_idx;
- obj_offset(pdf, i) = pdf->os_cur_objnum;
- pdf->os_obj[pdf->os_idx].num = i;
- pdf->os_obj[pdf->os_idx].off = pdf->ptr;
- } else {
- obj_offset(pdf, i) = pdf_offset(pdf);
- obj_os_idx(pdf, i) = -1; /* mark it as not included in object stream */
+ assert(os->idx < PDF_OS_MAX_OBJS); /* for marking below */
+ obj_os_idx(pdf, k) = (int) os->idx;
+ obj_os_objnum(pdf, k) = (int) os->cur_objstm;
+ os->obj[os->idx].num = k;
+ os->obj[os->idx].off = obuf->p - obuf->data;
+ break;
+ default:
+ assert(0);
}
}
-@* low-level buffer checkers.
+@* Low-level buffer checkers.
-@ check that |s| bytes more fit into |pdf_os_buf|; increase it if required
-@c
-static void pdf_os_get_os_buf(PDF pdf, int s)
-{
- int a;
- if (s > sup_pdf_os_buf_size - pdf->ptr)
- overflow("PDF object stream buffer", (unsigned) pdf->os_buf_size);
- if (pdf->ptr + s > pdf->os_buf_size) {
- a = pdf->os_buf_size / 5;
- if (pdf->ptr + s > pdf->os_buf_size + a)
- pdf->os_buf_size = pdf->ptr + s;
- else if (pdf->os_buf_size < sup_pdf_os_buf_size - a)
- pdf->os_buf_size = pdf->os_buf_size + a;
- else
- pdf->os_buf_size = sup_pdf_os_buf_size;
- pdf->os_buf =
- xreallocarray(pdf->os_buf, unsigned char,
- (unsigned) pdf->os_buf_size);
- pdf->buf = pdf->os_buf;
- pdf->buf_size = pdf->os_buf_size;
- }
-}
-
-@ make sure that there are at least |n| bytes free in PDF buffer
+@ Set the active buffer pointer.
+Make sure that there are at least |n| bytes free in that buffer,
+flush if needed.
@c
void pdf_room(PDF pdf, int n)
{
- if (pdf->os_mode && (n + pdf->ptr > pdf->buf_size))
- pdf_os_get_os_buf(pdf, n);
- else if ((!pdf->os_mode) && (n > pdf->buf_size))
- overflow("PDF output buffer", (unsigned) pdf->op_buf_size);
- else if ((!pdf->os_mode) && (n + pdf->ptr > pdf->buf_size))
- pdf_flush(pdf);
-}
-
-
-@ print out a character to PDF buffer; the character will be printed in octal
- form in the following cases: chars <= 32, backslash (92), left parenthesis
- (40) and right parenthesis (41)
-
-@c
-#define pdf_print_escaped(c) \
- if ((c)<=32||(c)=='\\'||(c)=='('||(c)==')'||(c)>127) { \
- pdf_room(pdf,4); \
- pdf_quick_out(pdf,'\\'); \
- pdf_quick_out(pdf,(unsigned char)('0' + (((c)>>6) & 0x3))); \
- pdf_quick_out(pdf,(unsigned char)('0' + (((c)>>3) & 0x7))); \
- pdf_quick_out(pdf,(unsigned char)('0' + ( (c) & 0x7))); \
- } else { \
- pdf_out(pdf,(c)); \
- }
-
-void pdf_print_char(PDF pdf, int c)
-{
- if (c > 255)
+ os_struct *os = pdf->os;
+ strbuf_s *buf = pdf->buf;
+ if ((size_t) (n + buf->p - buf->data) <= buf->size)
return;
- pdf_print_escaped(c);
+ assert(buf == os->buf[os->curbuf]);
+ switch (os->curbuf) {
+ case PDFOUT_BUF:
+ if ((size_t) n > buf->size)
+ overflow("PDF output buffer", (unsigned) buf->size);
+ if ((size_t) (n + buf->p - buf->data) < buf->limit)
+ strbuf_room(buf, (size_t) n); /* grow it if possible */
+ else
+ pdf_flush(pdf);
+ break;
+ case LUASTM_BUF:
+ if ((size_t) n > buf->size)
+ overflow("PDF output buffer", (unsigned) buf->size);
+ pdf_flush(pdf);
+ break;
+ case OBJSTM_BUF:
+ strbuf_room(buf, (size_t) n); /* just grow it */
+ break;
+ default:
+ assert(0);
+ }
}
@ @c
void pdf_out_block(PDF pdf, const char *s, size_t n)
{
size_t l;
+ strbuf_s *buf = pdf->buf;
do {
l = n;
- if ((int) l > pdf->buf_size)
- l = (size_t) pdf->buf_size;
+ if (l > buf->size)
+ l = buf->size;
pdf_room(pdf, (int) l);
- (void) memcpy(pdf->buf + pdf->ptr, s, l);
- pdf->ptr += (int) l;
+ (void) memcpy(buf->p, s, l);
+ buf->p += l;
s += l;
n -= l;
} while (n > 0);
}
-void pdf_print_wide_char(PDF pdf, int c)
-{
- char hex[5];
- snprintf(hex, 5, "%04X", c);
- pdf_out_block(pdf, (const char *) hex, 4);
-}
-
@ @c
__attribute__ ((format(printf, 2, 3)))
void pdf_printf(PDF pdf, const char *fmt, ...)
@@ -513,60 +570,40 @@ void pdf_print(PDF pdf, str_number s)
@c
void pdf_print_int(PDF pdf, longinteger n)
{
- register int k = 0; /* current digit; we assume that $|n|<10^{23}$ */
- int dig[24];
- if (n < 0) {
- pdf_out(pdf, '-');
- if (n < -0x7FFFFFFF) { /* need to negate |n| more carefully */
- register longinteger m;
- k++;
- m = -1 - n;
- n = m / 10;
- m = (m % 10) + 1;
- if (m < 10) {
- dig[0] = (int) m;
- } else {
- dig[0] = 0;
- n++;
- }
- } else {
- n = -n;
- }
- }
- do {
- dig[k++] = (int) (n % 10);
- n /= 10;
- } while (n != 0);
- pdf_room(pdf, k);
- while (k-- > 0) {
- pdf_quick_out(pdf, (unsigned char) ('0' + dig[k]));
- }
+ char s[24];
+ int w;
+ w = snprintf(s, 23, "%" LONGINTEGER_PRI "d", n);
+ check_nprintf(w, 23);
+ pdf_out_block(pdf, (const char *) s, (size_t) w);
}
-@ print $m/10^d$ as real
-@c
-void pdf_print_real(PDF pdf, int m, int d)
+@ @c
+void print_pdffloat(PDF pdf, pdffloat f)
{
+ char a[24];
+ int e = f.e, i, j;
+ long l, m = f.m;
if (m < 0) {
pdf_out(pdf, '-');
- m = -m;
- };
- pdf_print_int(pdf, m / ten_pow[d]);
- m = m % ten_pow[d];
- if (m > 0) {
+ m *= -1;
+ }
+ l = m / ten_pow[e];
+ pdf_print_int(pdf, l);
+ l = m % ten_pow[e];
+ if (l != 0) {
pdf_out(pdf, '.');
- d--;
- while (m < ten_pow[d]) {
- pdf_out(pdf, '0');
- d--;
+ j = snprintf(a, 23, "%ld", l + ten_pow[e]);
+ assert(j < 23);
+ for (i = e; i > 0; i--) {
+ if (a[i] != '0')
+ break;
+ a[i] = '\0';
}
- while (m % 10 == 0)
- m /= 10;
- pdf_print_int(pdf, m);
+ pdf_puts(pdf, (a + 1));
}
}
-@ print out |s| as string in PDF output
+@ print out |s| as string in PDF output
@c
void pdf_print_str(PDF pdf, const char *s)
{
@@ -599,64 +636,93 @@ void pdf_print_str(PDF pdf, const char *s)
pdf_puts(pdf, orig); /* it was a hex string after all */
}
-@ begin a stream
+@ begin a stream (needs to have a stream dictionary also)
@c
void pdf_begin_stream(PDF pdf)
{
- assert(pdf->os_mode == false);
- pdf_puts(pdf, "/Length \n");
- pdf->seek_write_length = true; /* fill in length at |pdf_end_stream| call */
- pdf->stream_length_offset = pdf_offset(pdf) - 11;
+ os_struct *os = pdf->os;
+ strbuf_s *lbuf = os->buf[LUASTM_BUF];
+ assert(os->curbuf == PDFOUT_BUF);
+ assert(pdf->buf == os->buf[os->curbuf]);
+ assert(pdf->zip_write_state == NO_ZIP);
+ pdf_puts(pdf, "\nstream\n");
+ pdf_save_offset(pdf);
+ pdf_flush(pdf);
+ if (os->trigger_luastm) {
+ os->trigger_luastm = false; /* this was just a trigger */
+ luaL_buffinit(Luas, &(os->b));
+ lbuf->p = lbuf->data = (unsigned char *) luaL_prepbuffer(&(os->b));
+ lbuf->size = lbuf->limit = LUAL_BUFFERSIZE;
+ os->curbuf = LUASTM_BUF;
+ pdf->buf = os->buf[os->curbuf];
+ }
+ if (pdf->stream_deflate) {
+ assert(pdf->compress_level > 0);
+ pdf->zip_write_state = ZIP_WRITING;
+ }
+ pdf->stream_writing = true;
pdf->stream_length = 0;
pdf->last_byte = 0;
- if (pdf->compress_level > 0) {
- pdf_puts(pdf, "/Filter /FlateDecode\n");
- pdf_puts(pdf, ">>\n");
- pdf_puts(pdf, "stream\n");
- pdf_flush(pdf);
- pdf->zip_write_state = zip_writing;
- } else {
- pdf_puts(pdf, ">>\n");
- pdf_puts(pdf, "stream\n");
- pdf_save_offset(pdf);
- }
}
-@ @c
-static void write_stream_length(PDF pdf, longinteger length, longinteger offset)
-{
- if (jobname_cstr == NULL)
- jobname_cstr = makecstring(job_name);
- if (pdf->draftmode == 0) {
- xfseeko(pdf->file, (off_t) offset, SEEK_SET, jobname_cstr);
- fprintf(pdf->file, "%" LONGINTEGER_PRI "i", (LONGINTEGER_TYPE) length);
- xfseeko(pdf->file, (off_t) pdf_offset(pdf), SEEK_SET, jobname_cstr);
- }
-}
-
-@ end a stream
+@ end a stream
@c
void pdf_end_stream(PDF pdf)
{
- if (pdf->zip_write_state == zip_writing)
- pdf->zip_write_state = zip_finish;
- else
- pdf->stream_length = pdf_offset(pdf) - pdf_saved_offset(pdf);
- pdf_flush(pdf);
- if (pdf->seek_write_length)
- write_stream_length(pdf, pdf->stream_length,
- pdf->stream_length_offset);
+ os_struct *os = pdf->os;
+ strbuf_s *lbuf = os->buf[LUASTM_BUF];
+ const_lstring ls;
+ assert(pdf->buf == os->buf[os->curbuf]);
+ switch (os->curbuf) {
+ case PDFOUT_BUF:
+ if (pdf->zip_write_state == ZIP_WRITING)
+ pdf->zip_write_state = ZIP_FINISH;
+ pdf_flush(pdf); /* sets pdf->last_byte */
+ break;
+ case LUASTM_BUF:
+ luaL_addsize(&(os->b), strbuf_offset(os->buf[LUASTM_BUF]));
+ luaL_pushresult(&(os->b));
+
+ /* now the complete page stream is on the Lua stack */
+ /* TODO: pagestream filter callback here */
+
+ ls.s = lua_tolstring(Luas, -1, &ls.l);
+ lbuf->data = (unsigned char *) ls.s;
+ lbuf->p = lbuf->data + ls.l;
+ os->curbuf = LUASTM_BUF;
+ pdf->buf = os->buf[os->curbuf];
+ if (pdf->zip_write_state == ZIP_WRITING) {
+ pdf->zip_write_state = ZIP_FINISH;
+ write_zip(pdf);
+ } else
+ write_nozip(pdf);
+ lua_pop(Luas, 1);
+ os->curbuf = PDFOUT_BUF;
+ pdf->buf = os->buf[os->curbuf];
+ assert(pdf->buf->data == pdf->buf->p);
+ break;
+ case OBJSTM_BUF:
+ assert(0);
+ break;
+ default:
+ assert(0);
+ }
+ assert(pdf->zip_write_state == NO_ZIP);
+ assert(os->curbuf == PDFOUT_BUF);
+ assert(pdf->buf == os->buf[os->curbuf]);
+ pdf->stream_deflate = false;
+ pdf->stream_writing = false;
+ if (pdf->last_byte != '\n')
+ pdf_out(pdf, '\n'); /* doesn't really belong to the stream */
+ pdf_puts(pdf, "endstream");
+ /* write stream /Length */
+ if (pdf->seek_write_length && pdf->draftmode == 0) {
+ xfseeko(pdf->file, (off_t)pdf->stream_length_offset, SEEK_SET,
+ pdf->job_name);
+ fprintf(pdf->file, "%" LONGINTEGER_PRI "i", pdf->stream_length);
+ xfseeko(pdf->file, 0, SEEK_END, pdf->job_name);
+ }
pdf->seek_write_length = false;
- if (pdf->last_byte != pdf_newline_char)
- pdf_out(pdf, pdf_newline_char);
- pdf_puts(pdf, "endstream\n");
- pdf_end_obj(pdf);
-}
-
-void pdf_remove_last_space(PDF pdf)
-{
- if ((pdf->ptr > 0) && (pdf->buf[pdf->ptr - 1] == ' '))
- pdf->ptr--;
}
@ To print |scaled| value to PDF output we need some subroutines to ensure
@@ -720,19 +786,20 @@ scaled round_xn_over_d(scaled x, int n, unsigned int d)
}
@ @c
-#define lround(a) (long) floor((a) + 0.5)
-
-void pdf_print_bp(PDF pdf, scaled s)
+void pdf_add_bp(PDF pdf, scaled s)
{ /* print scaled as |bp| */
pdffloat a;
pdfstructure *p = pdf->pstruct;
assert(p != NULL);
a.m = lround(s * p->k1);
a.e = pdf->decimal_digits;
+ if (pdf->cave > 0)
+ pdf_out(pdf, ' ');
print_pdffloat(pdf, a);
+ pdf->cave = 1;
}
-void pdf_print_mag_bp(PDF pdf, scaled s)
+void pdf_add_mag_bp(PDF pdf, scaled s)
{ /* take |mag| into account */
pdffloat a;
pdfstructure *p = pdf->pstruct;
@@ -742,18 +809,12 @@ void pdf_print_mag_bp(PDF pdf, scaled s)
else
a.m = lround(s * p->k1);
a.e = pdf->decimal_digits;
+ if (pdf->cave > 0)
+ pdf_out(pdf, ' ');
print_pdffloat(pdf, a);
+ pdf->cave = 1;
}
-#define set_p_or_return(a) do { \
- p = a; \
- if (p==NULL) { \
- a = item; \
- return; \
- } \
- } while (0)
-
-
@* handling page resources.
@c
@@ -879,7 +940,7 @@ static void destroy_page_resources_tree(PDF pdf)
@* Subroutines to print out various PDF objects.
-@ print out an integer |n| with fixed width |w|; used for outputting cross-reference table
+@ print out an integer |n| with fixed width |w|; used for outputting cross-reference table
@c
static void pdf_print_fw_int(PDF pdf, longinteger n, size_t w)
{
@@ -894,7 +955,7 @@ static void pdf_print_fw_int(PDF pdf, longinteger n, size_t w)
pdf_out_block(pdf, (const char *) digits, w);
}
-@ print out an integer |n| as a fixed number |w| of bytes; used for outputting \.{/XRef} cross-reference stream
+@ print out an integer |n| as a fixed number |w| of bytes; used for outputting \.{/XRef} cross-reference stream
@c
static void pdf_out_bytes(PDF pdf, longinteger n, size_t w)
{
@@ -909,59 +970,12 @@ static void pdf_out_bytes(PDF pdf, longinteger n, size_t w)
pdf_out_block(pdf, (const char *) bytes, w);
}
-@ print out an entry in dictionary with integer value to PDF buffer
-@c
-void pdf_int_entry(PDF pdf, const char *s, int v)
-{
- pdf_printf(pdf, "/%s ", s);
- pdf_print_int(pdf, v);
-}
-
-void pdf_int_entry_ln(PDF pdf, const char *s, int v)
-{
-
- pdf_int_entry(pdf, s, v);
- pdf_print_nl(pdf);
-}
-
-@ print out an indirect entry in dictionary
-@c
-void pdf_indirect(PDF pdf, const char *s, int o)
-{
- pdf_printf(pdf, "/%s %d 0 R", s, (int) o);
-}
-
-void pdf_indirect_ln(PDF pdf, const char *s, int o)
-{
-
- pdf_indirect(pdf, s, o);
- pdf_print_nl(pdf);
-}
-
-@ print out |s| as string in PDF output
+@ print out |s| as string in PDF output
@c
void pdf_print_str_ln(PDF pdf, const char *s)
{
pdf_print_str(pdf, s);
- pdf_print_nl(pdf);
-}
-
-@ print out an entry in dictionary with string value to PDF buffer
-@c
-void pdf_str_entry(PDF pdf, const char *s, const char *v)
-{
- if (v == 0)
- return;
- pdf_printf(pdf, "/%s ", s);
- pdf_print_str(pdf, v);
-}
-
-void pdf_str_entry_ln(PDF pdf, const char *s, const char *v)
-{
- if (v == 0)
- return;
- pdf_str_entry(pdf, s, v);
- pdf_print_nl(pdf);
+ pdf_out(pdf, '\n');
}
@ @c
@@ -969,43 +983,34 @@ void pdf_print_toks(PDF pdf, halfword p)
{
int len = 0;
char *s = tokenlist_to_cstring(p, true, &len);
- if (len > 0)
- pdf_puts(pdf, s);
- xfree(s);
-}
-
-void pdf_print_toks_ln(PDF pdf, halfword p)
-{
- int len = 0;
- char *s = tokenlist_to_cstring(p, true, &len);
if (len > 0) {
+ if (pdf->cave > 0)
+ pdf_out(pdf, ' ');
pdf_puts(pdf, s);
- pdf_print_nl(pdf);
+ pdf->cave = 1;
}
xfree(s);
}
-@ prints a rect spec
+@ prints a rect spec
@c
-void pdf_print_rect_spec(PDF pdf, halfword r)
+void pdf_add_rect_spec(PDF pdf, halfword r)
{
- pdf_print_mag_bp(pdf, pdf_ann_left(r));
- pdf_out(pdf, ' ');
- pdf_print_mag_bp(pdf, pdf_ann_bottom(r));
- pdf_out(pdf, ' ');
- pdf_print_mag_bp(pdf, pdf_ann_right(r));
- pdf_out(pdf, ' ');
- pdf_print_mag_bp(pdf, pdf_ann_top(r));
+ pdf_add_mag_bp(pdf, pdf_ann_left(r));
+ pdf_add_mag_bp(pdf, pdf_ann_bottom(r));
+ pdf_add_mag_bp(pdf, pdf_ann_right(r));
+ pdf_add_mag_bp(pdf, pdf_ann_top(r));
}
-@ output a rectangle specification to PDF file
+@ output a rectangle specification to PDF file
@c
void pdf_rectangle(PDF pdf, halfword r)
{
prepare_mag();
- pdf_puts(pdf, "/Rect [");
- pdf_print_rect_spec(pdf, r);
- pdf_puts(pdf, "]\n");
+ pdf_add_name(pdf, "Rect");
+ pdf_begin_array(pdf);
+ pdf_add_rect_spec(pdf, r);
+ pdf_end_array(pdf);
}
@ @c
@@ -1019,7 +1024,7 @@ static void init_pdf_outputparameters(PDF pdf)
pdf->image_gamma = fix_int(pdf_image_gamma, 0, 1000000);
pdf->image_hicolor = fix_int(pdf_image_hicolor, 0, 1);
pdf->image_apply_gamma = fix_int(pdf_image_apply_gamma, 0, 1);
- pdf->objcompresslevel = fix_int(pdf_objcompresslevel, 0, 3);
+ pdf->objcompresslevel = fix_int(pdf_objcompresslevel, 0, MAX_OBJ_COMPRESS_LEVEL);
pdf->inclusion_copy_font = fix_int(pdf_inclusion_copy_font, 0, 1);
pdf->replace_font = fix_int(pdf_replace_font, 0, 1);
pdf->pk_resolution = fix_int(pdf_pk_resolution, 72, 8000);
@@ -1041,13 +1046,13 @@ static void init_pdf_outputparameters(PDF pdf)
if (!callback_defined(read_pk_file_callback)) {
if (pdf_pk_mode != null) {
char *s = tokenlist_to_cstring(pdf_pk_mode, true, NULL);
- kpseinitprog("PDFTEX", (unsigned) pdf->pk_resolution, s, nil);
+ kpse_init_prog("PDFTEX", (unsigned) pdf->pk_resolution, s, nil);
xfree(s);
} else {
- kpseinitprog("PDFTEX", (unsigned) pdf->pk_resolution, nil, nil);
+ kpse_init_prog("PDFTEX", (unsigned) pdf->pk_resolution, nil, nil);
}
- if (!kpsevarvalue("MKTEXPK"))
- kpsesetprogramenabled(kpsepkformat, 1, kpsesrccmdline);
+ if (!kpse_var_value("MKTEXPK"))
+ kpse_set_program_enabled(kpse_pk_format, 1, kpse_src_cmdline);
}
set_job_id(pdf, int_par(year_code),
int_par(month_code), int_par(day_code), int_par(time_code));
@@ -1055,7 +1060,7 @@ static void init_pdf_outputparameters(PDF pdf)
pdf->resname_prefix = get_resname_prefix(pdf);
}
-@ Checks that we have a name for the generated PDF file and that it's open.
+@ Checks that we have a name for the generated PDF file and that it's open.
@c
static void ensure_output_file_open(PDF pdf, const char *ext)
@@ -1088,7 +1093,7 @@ static void ensure_pdf_header_written(PDF pdf)
pdf_out(pdf, 'T' + 128);
pdf_out(pdf, 'E' + 128);
pdf_out(pdf, 'X' + 128);
- pdf_print_nl(pdf);
+ pdf_out(pdf, '\n');
}
@ @c
@@ -1152,117 +1157,248 @@ When calling this procedure, |pdf_os_mode| must be |true|.
@c
static void pdf_os_write_objstream(PDF pdf)
{
- halfword i, j, p, q;
- if (pdf->os_cur_objnum == 0) /* no object stream started */
+ os_struct *os = pdf->os;
+ unsigned int i, j, n1, n2; /* n1, n2: ObjStm buffer may be reallocated! */
+ strbuf_s *obuf = os->buf[OBJSTM_BUF];
+ if (os->cur_objstm == 0) /* no object stream started */
return;
- p = pdf->ptr;
- i = 0;
- j = 0;
- while (i <= pdf->os_idx) { /* assemble object number and byte offset pairs */
- pdf_printf(pdf, "%d %d", (int) pdf->os_obj[i].num,
- (int) pdf->os_obj[i].off);
- if (j == 9) { /* print out in groups of ten for better readability */
- pdf_out(pdf, pdf_newline_char);
+ assert(pdf->buf == obuf); /* yes, pdf_out() still goes into ObjStm */
+ assert(os->idx > 0); /* yes, there are objects for the ObjStm */
+ n1 = (unsigned int) strbuf_offset(obuf); /* remember end of collected object stream contents */
+ /* this is needed here to calculate /First for the ObjStm dict */
+ for (i = 0, j = 0; i < os->idx; i++) { /* add object-number/byte-offset list to buffer */
+ pdf_print_int(pdf, (int) os->obj[i].num);
+ pdf_out(pdf, ' ');
+ pdf_print_int(pdf, (int) os->obj[i].off);
+ if (j == 9 || i == os->idx - 1) { /* print out in groups of ten for better readability */
+ pdf_out(pdf, '\n');
j = 0;
} else {
pdf_out(pdf, ' ');
j++;
}
- i++;
- }
- pdf->buf[pdf->ptr - 1] = pdf_newline_char; /* no risk of flush, as we are in |pdf_os_mode| */
- q = pdf->ptr;
- pdf_begin_dict(pdf, pdf->os_cur_objnum, 0); /* switch to PDF stream writing */
- pdf_puts(pdf, "/Type /ObjStm\n");
- pdf_printf(pdf, "/N %d\n", (int) (pdf->os_idx + 1));
- pdf_printf(pdf, "/First %d\n", (int) (q - p));
- pdf_begin_stream(pdf);
- /* write object number and byte offset pairs;
- |q - p| should always fit into the PDF output buffer */
- pdf_out_block(pdf, (const char *) (pdf->os_buf + p), (size_t) (q - p));
- i = 0;
- while (i < p) {
- q = i + pdf->buf_size;
- if (q > p)
- q = p;
- pdf_room(pdf, q - i);
- while (i < q) { /* write the buffered objects */
- pdf_quick_out(pdf, pdf->os_buf[i]);
- i++;
- }
}
+ n2 = (unsigned int) strbuf_offset(obuf); /* remember current buffer end */
+ pdf_begin_obj(pdf, (int) os->cur_objstm, OBJSTM_NEVER); /* switch to PDF stream writing */
+ pdf_begin_dict(pdf);
+ pdf_dict_add_name(pdf, "Type", "ObjStm");
+ pdf_dict_add_int(pdf, "N", (int) os->idx); /* number of objects in ObjStm */
+ pdf_dict_add_int(pdf, "First", (int) (n2 - n1));
+ pdf_dict_add_streaminfo(pdf);
+ pdf_end_dict(pdf);
+ pdf_begin_stream(pdf);
+ /* write object-number/byte-offset list */
+ pdf_out_block(pdf, (const char *) (obuf->data + n1), (size_t) (n2 - n1));
+ /* write collected object stream contents */
+ pdf_out_block(pdf, (const char *) obuf->data, (size_t) n1);
pdf_end_stream(pdf);
- pdf->os_cur_objnum = 0; /* to force object stream generation next time */
+ pdf_end_obj(pdf);
+ os->cur_objstm = 0; /* to force object stream generation next time */
}
-@ begin a PDF dictionary object
+@ begin a PDF dictionary
@c
-void pdf_begin_dict(PDF pdf, int i, int pdf_os_level)
+void pdf_begin_dict(PDF pdf)
{
- ensure_output_state(pdf, ST_HEADER_WRITTEN);
- pdf_os_prepare_obj(pdf, i, pdf_os_level);
- if (!pdf->os_mode) {
- pdf_printf(pdf, "%d 0 obj\n<<\n", (int) i);
- } else {
- if (pdf->compress_level == 0)
- pdf_printf(pdf, "%% %d 0 obj\n", (int) i); /* debugging help */
- pdf_puts(pdf, "<<\n");
- }
+ pdf_puts(pdf, "<<");
+ pdf->cave = 0;
}
-@ begin a new PDF dictionary object
+@ end a PDF dictionary
@c
-int pdf_new_dict(PDF pdf, int t, int i, int pdf_os_level)
+void pdf_end_dict(PDF pdf)
{
- int k = pdf_create_obj(pdf, t, i);
- pdf_begin_dict(pdf, k, pdf_os_level);
- return k;
+ pdf_puts(pdf, ">>");
+ pdf->cave = 0;
}
-@ end a PDF dictionary object
+@ add integer object to dict
@c
-void pdf_end_dict(PDF pdf)
+void pdf_dict_add_bool(PDF pdf, const char *key, int i)
{
- if (pdf->os_mode) {
- pdf_puts(pdf, ">>\n");
- if (pdf->os_idx == pdf_os_max_objs - 1)
- pdf_os_write_objstream(pdf);
- } else {
- pdf_puts(pdf, ">>\nendobj\n");
- }
+ pdf_add_name(pdf, key);
+ pdf_add_bool(pdf, i);
}
-@ begin a PDF object
+@ add integer object to dict
@c
-void pdf_begin_obj(PDF pdf, int i, int pdf_os_level)
+void pdf_dict_add_int(PDF pdf, const char *key, int i)
{
- ensure_output_state(pdf, ST_HEADER_WRITTEN);
- pdf_os_prepare_obj(pdf, i, pdf_os_level);
- if (!pdf->os_mode) {
- pdf_printf(pdf, "%d 0 obj\n", (int) i);
- } else if (pdf->compress_level == 0) {
- pdf_printf(pdf, "%% %d 0 obj\n", (int) i); /* debugging help */
+ pdf_add_name(pdf, key);
+ pdf_add_int(pdf, i);
+}
+
+@ add name object to dict
+@c
+void pdf_dict_add_name(PDF pdf, const char *key, const char *val)
+{
+ pdf_add_name(pdf, key);
+ pdf_add_name(pdf, val);
+}
+
+@ add string object to dict
+@c
+void pdf_dict_add_string(PDF pdf, const char *key, const char *val)
+{
+ if (val == NULL)
+ return;
+ pdf_add_name(pdf, key);
+ if (pdf->cave > 0)
+ pdf_out(pdf, ' ');
+ pdf->cave = 0;
+ pdf_print_str(pdf, val);
+}
+
+@ add name reference to dict
+@c
+void pdf_dict_add_ref(PDF pdf, const char *key, int num)
+{
+ pdf_add_name(pdf, key);
+ pdf_add_ref(pdf, num);
+}
+
+@ add objects of different types
+@c
+void pdf_add_null(PDF pdf)
+{
+ if (pdf->cave > 0)
+ pdf_out(pdf, ' ');
+ pdf_puts(pdf, "null");
+ pdf->cave = 1;
+}
+
+void pdf_add_bool(PDF pdf, int i)
+{
+ if (pdf->cave > 0)
+ pdf_out(pdf, ' ');
+ if (i == 0)
+ pdf_puts(pdf, "false");
+ else
+ pdf_puts(pdf, "true");
+ pdf->cave = 1;
+}
+
+void pdf_add_int(PDF pdf, int i)
+{
+ if (pdf->cave > 0)
+ pdf_out(pdf, ' ');
+ pdf_print_int(pdf, i);
+ pdf->cave = 1;
+}
+
+void pdf_add_longint(PDF pdf, longinteger n)
+{
+ if (pdf->cave > 0)
+ pdf_out(pdf, ' ');
+ pdf_print_int(pdf, n);
+ pdf->cave = 1;
+}
+
+void pdf_add_string(PDF pdf, const char *s)
+{
+ if (pdf->cave > 0)
+ pdf_out(pdf, ' ');
+ pdf_print_str(pdf, s);
+ pdf->cave = 1;
+}
+
+void pdf_add_name(PDF pdf, const char *name)
+{
+ pdf_out(pdf, '/');
+ pdf_puts(pdf, name);
+ pdf->cave = 1;
+}
+
+void pdf_add_ref(PDF pdf, int num)
+{
+ if (pdf->cave > 0)
+ pdf_out(pdf, ' ');
+ pdf_print_int(pdf, num);
+ pdf_puts(pdf, " 0 R");
+ pdf->cave = 1;
+}
+
+@ add stream length and filter entries to a stream dictionary,
+remember file position for seek
+@c
+void pdf_dict_add_streaminfo(PDF pdf)
+{
+ assert(pdf->buf == pdf->os->buf[PDFOUT_BUF]);
+ pdf_add_name(pdf, "Length");
+ pdf->stream_length_offset = pdf_offset(pdf) + 1;
+ pdf->seek_write_length = true; /* fill in length at |pdf_end_stream| call */
+ pdf_puts(pdf, " x "); /* space for 10 decimal digits */
+ pdf->cave = 1;
+ if (pdf->compress_level > 0) {
+ pdf_dict_add_name(pdf, "Filter", "FlateDecode");
+ pdf->stream_deflate = true;
}
}
-@ begin a new PDF object
+@ begin a PDF array
@c
-int pdf_new_obj(PDF pdf, int t, int i, int pdf_os_level)
+void pdf_begin_array(PDF pdf)
{
- int k = pdf_create_obj(pdf, t, i);
- pdf_begin_obj(pdf, k, pdf_os_level);
- return k;
+ pdf_out(pdf, '[');
+ pdf->cave = 0;
+}
+
+@ end a PDF array
+@c
+void pdf_end_array(PDF pdf)
+{
+ pdf_out(pdf, ']');
+ pdf->cave = 0;
}
-@ end a PDF object
+@ begin a PDF object
+@c
+void pdf_begin_obj(PDF pdf, int i, int pdf_os_threshold)
+{
+ os_struct *os = pdf->os;
+ ensure_output_state(pdf, ST_HEADER_WRITTEN);
+ pdf_prepare_obj(pdf, i, pdf_os_threshold);
+ assert(pdf->buf == os->buf[os->curbuf]);
+ switch (os->curbuf) {
+ case PDFOUT_BUF:
+ pdf_printf(pdf, "%d 0 obj\n", (int) i);
+ break;
+ case LUASTM_BUF:
+ assert(0);
+ break;
+ case OBJSTM_BUF:
+ if (pdf->compress_level == 0)
+ pdf_printf(pdf, "%% %d 0 obj\n", (int) i); /* debugging help */
+ break;
+ default:
+ assert(0);
+ }
+ pdf->cave = 0;
+}
+
+@ end a PDF object
@c
void pdf_end_obj(PDF pdf)
{
- if (pdf->os_mode) {
- if (pdf->os_idx == pdf_os_max_objs - 1)
+ os_struct *os = pdf->os;
+ assert(pdf->buf == os->buf[os->curbuf]);
+ switch (os->curbuf) {
+ case PDFOUT_BUF:
+ pdf_puts(pdf, "\nendobj\n"); /* end a PDF object */
+ break;
+ case LUASTM_BUF:
+ assert(0);
+ break;
+ case OBJSTM_BUF:
+ os->idx++; /* = number of objects collected so far in ObjStm */
+ os->o_ctr++; /* only for statistics */
+ if (os->idx == PDF_OS_MAX_OBJS)
pdf_os_write_objstream(pdf);
- } else {
- pdf_puts(pdf, "endobj\n"); /* end a PDF object */
+ else
+ pdf_out(pdf, '\n'); /* Adobe Reader seems to need this */
+ break;
+ default:
+ assert(0);
}
}
@@ -1271,7 +1407,7 @@ void pdf_end_obj(PDF pdf)
control characters are octal encoded.
This assumes that the string does not contain any already escaped
characters!
-
+
@c
char *convertStringToPDFString(const char *in, int len)
{
@@ -1311,7 +1447,7 @@ char *convertStringToPDFString(const char *in, int len)
@ Converts any string given in in in an allowed PDF string which is
hexadecimal encoded;
|sizeof(out)| should be at least $|lin|*2+1$.
-
+
@c
static void convertStringToHexString(const char *in, char *out, int lin)
{
@@ -1362,7 +1498,7 @@ static void convertStringToHexString(const char *in, char *out, int lin)
implementation using just the first two items.
@c
-static void print_ID(PDF pdf, const char *file_name)
+static void print_ID(PDF pdf)
{
time_t t;
size_t size;
@@ -1393,12 +1529,16 @@ static void print_ID(PDF pdf, const char *file_name)
#endif
md5_append(&state, (const md5_byte_t *) pwd, (int) strlen(pwd));
md5_append(&state, (const md5_byte_t *) "/", 1);
- md5_append(&state, (const md5_byte_t *) file_name, (int) strlen(file_name));
+ md5_append(&state, (const md5_byte_t *) pdf->file_name,
+ (int) strlen(pdf->file_name));
/* finish md5 */
md5_finish(&state, digest);
/* write the IDs */
convertStringToHexString((char *) digest, id, 16);
- pdf_printf(pdf, "/ID [<%s> <%s>]", id, id);
+ pdf_add_name(pdf, "ID");
+ pdf_begin_array(pdf);
+ pdf_printf(pdf, "<%s> <%s>", id, id);
+ pdf_end_array(pdf);
}
@ Print the /CreationDate entry.
@@ -1516,20 +1656,6 @@ void init_start_time(PDF pdf)
}
@ @c
-static void print_creation_date(PDF pdf)
-{
- init_start_time(pdf);
- pdf_printf(pdf, "/CreationDate (%s)\n", pdf->start_time_str);
-}
-
-@ @c
-static void print_mod_date(PDF pdf)
-{
- init_start_time(pdf);
- pdf_printf(pdf, "/ModDate (%s)\n", pdf->start_time_str);
-}
-
-@ @c
char *getcreationdate(PDF pdf)
{
assert(pdf);
@@ -1549,67 +1675,6 @@ void remove_pdffile(PDF pdf)
}
@ @c
-static void realloc_fb(PDF pdf)
-{
- if (pdf->fb_array == NULL) {
- pdf->fb_limit = SMALL_ARRAY_SIZE;
- pdf->fb_array = xtalloc(pdf->fb_limit, char);
- pdf->fb_ptr = pdf->fb_array;
- } else if ((size_t) (pdf->fb_ptr - pdf->fb_array + 1) > pdf->fb_limit) {
- size_t last_ptr_index = (size_t) (pdf->fb_ptr - pdf->fb_array);
- pdf->fb_limit *= 2;
- if ((size_t) (pdf->fb_ptr - pdf->fb_array + 1) > pdf->fb_limit)
- pdf->fb_limit = (size_t) (pdf->fb_ptr - pdf->fb_array + 1);
- xretalloc(pdf->fb_array, pdf->fb_limit, char);
- pdf->fb_ptr = pdf->fb_array + last_ptr_index;
- }
-}
-
-@ @c
-int fb_offset(PDF pdf)
-{
- return (int) (pdf->fb_ptr - pdf->fb_array);
-}
-
-@ @c
-void fb_seek(PDF pdf, int offset)
-{
- pdf->fb_ptr = pdf->fb_array + offset;
-}
-
-@ @c
-void fb_putchar(PDF pdf, eight_bits b)
-{
- if ((size_t) (pdf->fb_ptr - pdf->fb_array + 1) > pdf->fb_limit)
- realloc_fb(pdf);
- *(pdf->fb_ptr)++ = (char) b;
-}
-
-@ @c
-void fb_flush(PDF pdf)
-{
- char *p;
- int n;
- for (p = pdf->fb_array; p < pdf->fb_ptr;) {
- n = pdf->buf_size - pdf->ptr;
- if (pdf->fb_ptr - p < n)
- n = (int) (pdf->fb_ptr - p);
- memcpy(pdf->buf + pdf->ptr, p, (unsigned) n);
- pdf->ptr += n;
- if (pdf->ptr == pdf->buf_size)
- pdf_flush(pdf);
- p += n;
- }
- pdf->fb_ptr = pdf->fb_array;
-}
-
-@ @c
-void fb_free(PDF pdf)
-{
- xfree(pdf->fb_array);
-}
-
-@ @c
void pdf_error(const char *t, const char *p)
{
normalize_selector();
@@ -1646,7 +1711,7 @@ void pdf_warning(const char *t, const char *p, boolean prepend_nl,
history = warning_issued;
}
-@ Use |check_o_mode()| in the backend-specific "Implement..." chunks
+@ Use |check_o_mode()| in the backend-specific "Implement..." chunks
@c
void check_o_mode(PDF pdf, const char *s, int o_mode_bitpattern, boolean strict)
@@ -1746,64 +1811,81 @@ char *get_resname_prefix(PDF pdf)
void pdf_begin_page(PDF pdf)
{
+ pdffloat f;
scaled form_margin = 0; /* was one_bp until SVN4066 */
ensure_output_state(pdf, ST_HEADER_WRITTEN);
init_pdf_pagecalculations(pdf);
-
if (pdf->page_resources == NULL) {
pdf->page_resources = xtalloc(1, pdf_resource_struct);
pdf->page_resources->resources_tree = NULL;
}
- pdf->page_resources->last_resources = pdf_new_objnum(pdf);
+ pdf->page_resources->last_resources =
+ pdf_create_obj(pdf, obj_type_others, 0);
reset_page_resources(pdf);
if (global_shipping_mode == SHIPPING_PAGE) {
- pdf->last_page = get_obj(pdf, obj_type_page, total_pages + 1, 0);
+ pdf->last_page = pdf_get_obj(pdf, obj_type_page, total_pages + 1, 0);
set_obj_aux(pdf, pdf->last_page, 1); /* mark that this page has been created */
- pdf->last_stream = pdf_new_dict(pdf, obj_type_pagestream, 0, 0);
+ pdf->last_stream = pdf_create_obj(pdf, obj_type_pagestream, 0);
+ pdf_begin_obj(pdf, pdf->last_stream, OBJSTM_NEVER);
pdf->last_thread = null;
+ pdf_begin_dict(pdf);
pdflua_begin_page(pdf);
} else {
assert(global_shipping_mode == SHIPPING_FORM);
- pdf_begin_dict(pdf, pdf_cur_form, 0);
+ pdf_begin_obj(pdf, pdf_cur_form, OBJSTM_NEVER);
pdf->last_stream = pdf_cur_form;
/* Write out Form stream header */
- pdf_puts(pdf, "/Type /XObject\n");
- pdf_puts(pdf, "/Subtype /Form\n");
+ pdf_begin_dict(pdf);
+ pdf_dict_add_name(pdf, "Type", "XObject");
+ pdf_dict_add_name(pdf, "Subtype", "Form");
if (pdf_xform_attr != null)
- pdf_print_toks_ln(pdf, pdf_xform_attr);
+ pdf_print_toks(pdf, pdf_xform_attr);
if (obj_xform_attr(pdf, pdf_cur_form) != null) {
- pdf_print_toks_ln(pdf, obj_xform_attr(pdf, pdf_cur_form));
+ pdf_print_toks(pdf, obj_xform_attr(pdf, pdf_cur_form));
delete_token_ref(obj_xform_attr(pdf, pdf_cur_form));
set_obj_xform_attr(pdf, pdf_cur_form, null);
}
- pdf_puts(pdf, "/BBox [");
- pdf_print_bp(pdf, -form_margin);
- pdf_out(pdf, ' ');
- pdf_print_bp(pdf, -form_margin);
- pdf_out(pdf, ' ');
- pdf_print_bp(pdf, cur_page_size.h + form_margin);
- pdf_out(pdf, ' ');
- pdf_print_bp(pdf, cur_page_size.v + form_margin);
- pdf_puts(pdf, "]\n");
- pdf_puts(pdf, "/FormType 1\n");
- pdf_puts(pdf, "/Matrix [1 0 0 1 0 0]\n");
- pdf_indirect_ln(pdf, "Resources", pdf->page_resources->last_resources);
+ pdf_add_name(pdf, "BBox");
+ pdf_begin_array(pdf);
+ pdf_add_bp(pdf, -form_margin);
+ pdf_add_bp(pdf, -form_margin);
+ pdf_add_bp(pdf, pdf->page_size.h + form_margin);
+ pdf_add_bp(pdf, pdf->page_size.v + form_margin);
+ pdf_end_array(pdf);
+ pdf_dict_add_int(pdf, "FormType", 1);
+ pdf_add_name(pdf, "Matrix");
+ pdf_begin_array(pdf);
+ pdf_add_int(pdf, 1);
+ pdf_add_int(pdf, 0);
+ pdf_add_int(pdf, 0);
+ pdf_add_int(pdf, 1);
+ pdf_add_int(pdf, 0);
+ pdf_add_int(pdf, 0);
+ pdf_end_array(pdf);
+ pdf_dict_add_ref(pdf, "Resources", pdf->page_resources->last_resources);
}
/* Start stream of page/form contents */
+ pdf_dict_add_streaminfo(pdf);
+ pdf_end_dict(pdf);
+ pdf->os->trigger_luastm = false; /* if it's true, the page stream goes through Lua */
pdf_begin_stream(pdf);
if (global_shipping_mode == SHIPPING_PAGE) {
/* Adjust transformation matrix for the magnification ratio */
if (mag != 1000) {
- pdf_print_real(pdf, mag, 3);
+ setpdffloat(f, mag, 3);
+ print_pdffloat(pdf, f);
pdf_puts(pdf, " 0 0 ");
- pdf_print_real(pdf, mag, 3);
+ print_pdffloat(pdf, f);
pdf_puts(pdf, " 0 0 cm\n");
}
}
- pdf_shipout_begin();
+ pos_stack_used = 0; /* start with empty stack */
+ if (global_shipping_mode == SHIPPING_PAGE) {
+ colorstackpagestart();
+ }
if (global_shipping_mode == SHIPPING_PAGE)
pdf_out_colorstack_startpage(pdf);
}
@@ -1813,13 +1895,17 @@ void print_pdf_table_string(PDF pdf, const char *s)
{
size_t len;
const char *ls;
- lua_getglobal(Luas, "pdf"); /* t ... */
+ lua_getglobal(Luas, "pdf"); /* t ... */
lua_pushstring(Luas, s); /* s t ... */
lua_gettable(Luas, -2); /* s? t ... */
if (lua_isstring(Luas, -1)) { /* s t ... */
ls = lua_tolstring(Luas, -1, &len);
- pdf_out_block(pdf, ls, len);
- pdf_out(pdf, '\n');
+ if (len > 0) {
+ if (pdf->cave == 1)
+ pdf_out(pdf, ' ');
+ pdf_out_block(pdf, ls, len);
+ pdf->cave = 1;
+ }
}
lua_pop(Luas, 2); /* ... */
}
@@ -1830,84 +1916,92 @@ void print_pdf_table_string(PDF pdf, const char *s)
void pdf_end_page(PDF pdf)
{
+ char s[64], *p;
int j, annots = 0, beads = 0;
pdf_resource_struct *res_p = pdf->page_resources;
pdf_resource_struct local_page_resources;
pdf_object_list *annot_list, *bead_list, *link_list, *ol, *ol1;
- scaledpos save_cur_page_size; /* to save |cur_page_size| during flushing pending forms */
+ scaledpos save_cur_page_size; /* to save |pdf->page_size| during flushing pending forms */
shipping_mode_e save_shipping_mode;
int procset = PROCSET_PDF;
/* Finish stream of page/form contents */
pdf_goto_pagemode(pdf);
- pdf_shipout_end();
+ if (pos_stack_used > 0) {
+ pdftex_fail("%u unmatched \\pdfsave after %s shipout",
+ (unsigned int) pos_stack_used,
+ ((global_shipping_mode ==
+ SHIPPING_PAGE) ? "page" : "form"));
+ }
pdf_end_stream(pdf);
+ pdf_end_obj(pdf);
if (global_shipping_mode == SHIPPING_PAGE) {
pdf->last_pages = pdf_do_page_divert(pdf, pdf->last_page, 0);
/* Write out /Page object */
- pdf_begin_dict(pdf, pdf->last_page, 1);
- pdf_puts(pdf, "/Type /Page\n");
- pdf_indirect_ln(pdf, "Contents", pdf->last_stream);
- pdf_indirect_ln(pdf, "Resources", res_p->last_resources);
- pdf_puts(pdf, "/MediaBox [0 0 ");
- pdf_print_mag_bp(pdf, cur_page_size.h);
- pdf_out(pdf, ' ');
- pdf_print_mag_bp(pdf, cur_page_size.v);
- pdf_puts(pdf, "]\n");
+ pdf_begin_obj(pdf, pdf->last_page, OBJSTM_ALWAYS);
+ pdf_begin_dict(pdf);
+ pdf_dict_add_name(pdf, "Type", "Page");
+ pdf_dict_add_ref(pdf, "Contents", pdf->last_stream);
+ pdf_dict_add_ref(pdf, "Resources", res_p->last_resources);
+ pdf_add_name(pdf, "MediaBox");
+ pdf_begin_array(pdf);
+ pdf_add_int(pdf, 0);
+ pdf_add_int(pdf, 0);
+ pdf_add_mag_bp(pdf, pdf->page_size.h);
+ pdf_add_mag_bp(pdf, pdf->page_size.v);
+ pdf_end_array(pdf);
if (pdf_page_attr != null)
- pdf_print_toks_ln(pdf, pdf_page_attr);
+ pdf_print_toks(pdf, pdf_page_attr);
print_pdf_table_string(pdf, "pageattributes");
- pdf_indirect_ln(pdf, "Parent", pdf->last_pages);
+ pdf_dict_add_ref(pdf, "Parent", pdf->last_pages);
if (pdf->img_page_group_val != 0) {
assert(pdf->img_page_group_val > 0);
- pdf_printf(pdf, "/Group %d 0 R\n", pdf->img_page_group_val);
+ pdf_dict_add_ref(pdf, "Group", pdf->img_page_group_val);
}
annot_list = get_page_resources_list(pdf, obj_type_annot);
link_list = get_page_resources_list(pdf, obj_type_link);
if (annot_list != NULL || link_list != NULL) {
annots = pdf_create_obj(pdf, obj_type_annots, 0);
- pdf_indirect_ln(pdf, "Annots", annots);
+ pdf_dict_add_ref(pdf, "Annots", annots);
}
bead_list = get_page_resources_list(pdf, obj_type_bead);
if (bead_list != NULL) {
beads = pdf_create_obj(pdf, obj_type_beads, 0);
- pdf_indirect_ln(pdf, "B", beads);
+ pdf_dict_add_ref(pdf, "B", beads);
}
pdf_end_dict(pdf);
+ pdf_end_obj(pdf);
pdflua_end_page(pdf, annots, beads);
pdf->img_page_group_val = 0;
/* Generate array of annotations or beads in page */
if (annot_list != NULL || link_list != NULL) {
- pdf_begin_obj(pdf, annots, 1);
- pdf_puts(pdf, "[");
+ pdf_begin_obj(pdf, annots, OBJSTM_ALWAYS);
+ pdf_begin_array(pdf);
while (annot_list != NULL) {
assert(annot_list->info > 0);
- pdf_print_int(pdf, annot_list->info);
- pdf_puts(pdf, " 0 R ");
+ pdf_add_ref(pdf, annot_list->info);
annot_list = annot_list->link;
}
while (link_list != NULL) {
- pdf_print_int(pdf, link_list->info);
- pdf_puts(pdf, " 0 R ");
+ pdf_add_ref(pdf, link_list->info);
link_list = link_list->link;
}
- pdf_puts(pdf, "]\n");
+ pdf_end_array(pdf);
pdf_end_obj(pdf);
}
if (bead_list != NULL) {
- pdf_begin_dict(pdf, beads, 1);
- pdf_puts(pdf, "[");
+ pdf_begin_obj(pdf, beads, OBJSTM_ALWAYS);
+ pdf_begin_array(pdf);
while (bead_list != NULL) {
- pdf_print_int(pdf, bead_list->info);
- pdf_printf(pdf, " 0 R ");
+ pdf_add_ref(pdf, bead_list->info);
bead_list = bead_list->link;
}
- pdf_printf(pdf, "]\n");
- pdf_end_dict(pdf);
+ pdf_end_array(pdf);
+ pdf_end_obj(pdf);
}
}
@@ -1923,19 +2017,19 @@ void pdf_end_page(PDF pdf)
/* Write out pending forms */
/* When flushing pending forms we need to save and restore resource lists
which are also used by page shipping.
- Saving and restoring |cur_page_size| is needed for proper
+ Saving and restoring |pdf->page_size| is needed for proper
writing out pending PDF marks. */
ol = get_page_resources_list(pdf, obj_type_xform);
while (ol != NULL) {
if (!is_obj_written(pdf, ol->info)) {
pdf_cur_form = ol->info;
- save_cur_page_size = cur_page_size;
+ save_cur_page_size = pdf->page_size;
save_shipping_mode = global_shipping_mode;
pdf->page_resources = &local_page_resources;
local_page_resources.resources_tree = NULL;
ship_out(pdf, obj_xform_box(pdf, pdf_cur_form), SHIPPING_FORM);
/* Restore page size and page resources */
- cur_page_size = save_cur_page_size;
+ pdf->page_size = save_cur_page_size;
global_shipping_mode = save_shipping_mode;
destroy_page_resources_tree(pdf);
pdf->page_resources = res_p;
@@ -1958,11 +2052,13 @@ void pdf_end_page(PDF pdf)
while (ol != NULL) {
if (ol->info > 0 && obj_type(pdf, ol->info) == obj_type_annot) {
j = obj_annot_ptr(pdf, ol->info); /* |j| points to |pdf_annot_node| */
- pdf_begin_dict(pdf, ol->info, 1);
- pdf_puts(pdf, "/Type /Annot\n");
- pdf_print_toks_ln(pdf, pdf_annot_data(j));
+ pdf_begin_obj(pdf, ol->info, OBJSTM_ALWAYS);
+ pdf_begin_dict(pdf);
+ pdf_dict_add_name(pdf, "Type", "Annot");
+ pdf_print_toks(pdf, pdf_annot_data(j));
pdf_rectangle(pdf, j);
pdf_end_dict(pdf);
+ pdf_end_obj(pdf);
}
ol = ol->link;
}
@@ -1971,17 +2067,19 @@ void pdf_end_page(PDF pdf)
if ((ol = get_page_resources_list(pdf, obj_type_link)) != NULL) {
while (ol != NULL) {
j = obj_annot_ptr(pdf, ol->info);
- pdf_begin_dict(pdf, ol->info, 1);
- pdf_puts(pdf, "/Type /Annot\n");
+ pdf_begin_obj(pdf, ol->info, OBJSTM_ALWAYS);
+ pdf_begin_dict(pdf);
+ pdf_dict_add_name(pdf, "Type", "Annot");
if (pdf_action_type(pdf_link_action(j)) != pdf_action_user)
- pdf_puts(pdf, "/Subtype /Link\n");
+ pdf_dict_add_name(pdf, "Subtype", "Link");
if (pdf_link_attr(j) != null)
- pdf_print_toks_ln(pdf, pdf_link_attr(j));
+ pdf_print_toks(pdf, pdf_link_attr(j));
pdf_rectangle(pdf, j);
if (pdf_action_type(pdf_link_action(j)) != pdf_action_user)
pdf_puts(pdf, "/A ");
write_action(pdf, pdf_link_action(j));
pdf_end_dict(pdf);
+ pdf_end_obj(pdf);
ol = ol->link;
}
/* Flush |pdf_start_link_node|'s created by |append_link| */
@@ -2003,17 +2101,18 @@ void pdf_end_page(PDF pdf)
}
/* Write out resources dictionary */
- pdf_begin_dict(pdf, res_p->last_resources, 1);
+ pdf_begin_obj(pdf, res_p->last_resources, OBJSTM_ALWAYS);
+ pdf_begin_dict(pdf);
/* Print additional resources */
if (global_shipping_mode == SHIPPING_PAGE) {
if (pdf_page_resources != null)
- pdf_print_toks_ln(pdf, pdf_page_resources);
+ pdf_print_toks(pdf, pdf_page_resources);
print_pdf_table_string(pdf, "pageresources");
} else {
if (pdf_xform_resources != null)
- pdf_print_toks_ln(pdf, pdf_xform_resources);
+ pdf_print_toks(pdf, pdf_xform_resources);
if (obj_xform_resources(pdf, pdf_cur_form) != null) {
- pdf_print_toks_ln(pdf, obj_xform_resources(pdf, pdf_cur_form));
+ pdf_print_toks(pdf, obj_xform_resources(pdf, pdf_cur_form));
delete_token_ref(obj_xform_resources(pdf, pdf_cur_form));
set_obj_xform_resources(pdf, pdf_cur_form, null);
}
@@ -2021,18 +2120,18 @@ void pdf_end_page(PDF pdf)
/* Generate font resources */
if ((ol = get_page_resources_list(pdf, obj_type_font)) != NULL) {
- pdf_puts(pdf, "/Font << ");
+ pdf_add_name(pdf, "Font");
+ pdf_begin_dict(pdf);
while (ol != NULL) {
assert(ol->info > 0); /* always base font: an object number */
- pdf_puts(pdf, "/F");
- pdf_print_int(pdf, obj_info(pdf, ol->info));
- pdf_print_resname_prefix(pdf);
- pdf_out(pdf, ' ');
- pdf_print_int(pdf, ol->info);
- pdf_puts(pdf, " 0 R ");
+ p = s;
+ p += snprintf(p, 20, "F%i", obj_info(pdf, ol->info));
+ if (pdf->resname_prefix != NULL)
+ p += snprintf(p, 20, "%s", pdf->resname_prefix);
+ pdf_dict_add_ref(pdf, s, ol->info);
ol = ol->link;
}
- pdf_puts(pdf, ">>\n");
+ pdf_end_dict(pdf);
procset |= PROCSET_TEXT;
}
@@ -2040,47 +2139,47 @@ void pdf_end_page(PDF pdf)
ol = get_page_resources_list(pdf, obj_type_xform);
ol1 = get_page_resources_list(pdf, obj_type_ximage);
if (ol != NULL || ol1 != NULL) {
- pdf_puts(pdf, "/XObject << ");
+ pdf_add_name(pdf, "XObject");
+ pdf_begin_dict(pdf);
while (ol != NULL) {
- pdf_printf(pdf, "/Fm");
- pdf_print_int(pdf, obj_info(pdf, ol->info));
- pdf_print_resname_prefix(pdf);
- pdf_out(pdf, ' ');
- pdf_print_int(pdf, ol->info);
- pdf_puts(pdf, " 0 R ");
+ p = s;
+ p += snprintf(p, 20, "Fm%i", obj_info(pdf, ol->info));
+ if (pdf->resname_prefix != NULL)
+ p += snprintf(p, 20, "%s", pdf->resname_prefix);
+ pdf_dict_add_ref(pdf, s, ol->info);
ol = ol->link;
}
while (ol1 != null) {
- pdf_puts(pdf, "/Im");
- pdf_print_int(pdf, obj_data_ptr(pdf, ol1->info));
- pdf_print_resname_prefix(pdf);
- pdf_out(pdf, ' ');
- pdf_print_int(pdf, ol1->info);
- pdf_puts(pdf, " 0 R ");
+ p = s;
+ p += snprintf(p, 20, "Im%i", obj_info(pdf, ol1->info));
+ if (pdf->resname_prefix != NULL)
+ p += snprintf(p, 20, "%s", pdf->resname_prefix);
+ pdf_dict_add_ref(pdf, s, ol1->info);
procset |= img_procset(idict_array[obj_data_ptr(pdf, ol1->info)]);
ol1 = ol1->link;
}
- pdf_puts(pdf, ">>\n");
+ pdf_end_dict(pdf);
}
/* Generate ProcSet */
- pdf_puts(pdf, "/ProcSet [");
+ pdf_add_name(pdf, "ProcSet");
+ pdf_begin_array(pdf);
if ((procset & PROCSET_PDF) != 0)
- pdf_puts(pdf, " /PDF");
+ pdf_add_name(pdf, "PDF");
if ((procset & PROCSET_TEXT) != 0)
- pdf_puts(pdf, " /Text");
+ pdf_add_name(pdf, "Text");
if ((procset & PROCSET_IMAGE_B) != 0)
- pdf_puts(pdf, " /ImageB");
+ pdf_add_name(pdf, "ImageB");
if ((procset & PROCSET_IMAGE_C) != 0)
- pdf_puts(pdf, " /ImageC");
+ pdf_add_name(pdf, "ImageC");
if ((procset & PROCSET_IMAGE_I) != 0)
- pdf_puts(pdf, " /ImageI");
- pdf_puts(pdf, " ]\n");
-
+ pdf_add_name(pdf, "ImageI");
+ pdf_end_array(pdf);
pdf_end_dict(pdf);
+ pdf_end_obj(pdf);
}
-@* Finishing the PDF output file.
+@* Finishing the PDF output file.
@ Destinations that have been referenced but don't exists have
|obj_dest_ptr=null|. Leaving them undefined might cause troubles for
@@ -2105,10 +2204,12 @@ static void check_nonexisting_destinations(PDF pdf)
(" has been referenced but does not exist, replaced by a fixed one");
print_ln();
print_ln();
- pdf_begin_obj(pdf, k, 1);
- pdf_out(pdf, '[');
- pdf_print_int(pdf, pdf->last_page);
- pdf_puts(pdf, " 0 R /Fit]\n");
+
+ pdf_begin_obj(pdf, k, OBJSTM_ALWAYS);
+ pdf_begin_array(pdf);
+ pdf_add_ref(pdf, pdf->last_page);
+ pdf_add_name(pdf, "Fit");
+ pdf_end_array(pdf);
pdf_end_obj(pdf);
}
}
@@ -2145,19 +2246,21 @@ static boolean substr_of_str(const char *s, const char *t)
return true;
}
-static int pdf_print_info(PDF pdf, int luatex_version,
- str_number luatex_revision)
+static int pdf_print_info(PDF pdf, int luatexversion,
+ str_number luatexrevision)
{ /* print info object */
boolean creator_given, producer_given, creationdate_given, moddate_given,
trapped_given;
char *s = NULL;
int k, len = 0;
- k = pdf_new_dict(pdf, obj_type_info, 0, 3); /* keep Info readable unless explicitely forced */
+ k = pdf_create_obj(pdf, obj_type_info, 0);
+ pdf_begin_obj(pdf, k, 3); /* keep Info readable unless explicitely forced */
creator_given = false;
producer_given = false;
creationdate_given = false;
moddate_given = false;
trapped_given = false;
+ pdf_begin_dict(pdf);
if (pdf_info_toks != 0) {
s = tokenlist_to_cstring(pdf_info_toks, true, &len);
creator_given = substr_of_str("/Creator", s);
@@ -2168,36 +2271,41 @@ static int pdf_print_info(PDF pdf, int luatex_version,
}
if (!producer_given) {
/* Print the Producer key */
- pdf_puts(pdf, "/Producer (LuaTeX-");
- pdf_print_int(pdf, luatex_version / 100);
+ pdf_add_name(pdf, "Producer");
+ pdf_puts(pdf, " (LuaTeX-");
+ pdf_print_int(pdf, luatexversion / 100);
pdf_out(pdf, '.');
- pdf_print_int(pdf, luatex_version % 100);
+ pdf_print_int(pdf, luatexversion % 100);
pdf_out(pdf, '.');
- pdf_print(pdf, luatex_revision);
- pdf_puts(pdf, ")\n");
+ pdf_print(pdf, luatexrevision);
+ pdf_out(pdf, ')');
}
if (pdf_info_toks != null) {
if (len > 0) {
+ pdf_out(pdf, '\n');
pdf_puts(pdf, s);
- pdf_print_nl(pdf);
+ pdf_out(pdf, '\n');
xfree(s);
}
delete_token_ref(pdf_info_toks);
pdf_info_toks = null;
}
if (!creator_given)
- pdf_str_entry_ln(pdf, "Creator", "TeX");
+ pdf_dict_add_string(pdf, "Creator", "TeX");
if (!creationdate_given) {
- print_creation_date(pdf);
+ init_start_time(pdf);
+ pdf_dict_add_string(pdf, "CreationDate", pdf->start_time_str);
}
if (!moddate_given) {
- print_mod_date(pdf);
+ init_start_time(pdf);
+ pdf_dict_add_string(pdf, "ModDate", pdf->start_time_str);
}
if (!trapped_given) {
- pdf_puts(pdf, "/Trapped /False\n");
+ pdf_dict_add_name(pdf, "Trapped", "False");
}
- pdf_str_entry_ln(pdf, "PTEX.Fullbanner", pdftex_banner);
+ pdf_dict_add_string(pdf, "PTEX.Fullbanner", pdftex_banner);
pdf_end_dict(pdf);
+ pdf_end_obj(pdf);
return k;
}
@@ -2219,9 +2327,8 @@ static void build_free_object_list(PDF pdf)
are already written completely to PDF output file.
@c
-void finish_pdf_file(PDF pdf, int luatex_version, str_number luatex_revision)
+void finish_pdf_file(PDF pdf, int luatexversion, str_number luatexrevision)
{
- boolean res;
int i, j, k;
int root, info, xref_stm = 0, outlines, threads, names_tree;
size_t xref_offset_width;
@@ -2233,7 +2340,7 @@ void finish_pdf_file(PDF pdf, int luatex_version, str_number luatex_revision)
tprint_nl("No pages of output.");
print_ln();
} else if (callback_id > 0) {
- res = run_callback(callback_id, "->");
+ run_callback(callback_id, "->");
}
if (pdf->gone > 0)
garbage_warning();
@@ -2242,7 +2349,7 @@ void finish_pdf_file(PDF pdf, int luatex_version, str_number luatex_revision)
pdf_flush(pdf); /* to make sure that the output file name has been already created */
flush_jbig2_page0_objects(pdf); /* flush page 0 objects from JBIG2 images, if any */
if (callback_id1 > 0)
- res = run_callback(callback_id1, "->");
+ run_callback(callback_id1, "->");
check_nonexisting_pages(pdf);
check_nonexisting_destinations(pdf);
@@ -2280,7 +2387,7 @@ void finish_pdf_file(PDF pdf, int luatex_version, str_number luatex_revision)
pdf->gen_tounicode = pdf_gen_tounicode;
k = pdf->head_tab[obj_type_font];
while (k != 0) {
- f = obj_info(pdf, k);
+ int f = obj_info(pdf, k);
assert(pdf_font_num(f) > 0);
assert(pdf_font_num(f) == k);
do_pdf_font(pdf, f);
@@ -2305,16 +2412,15 @@ void finish_pdf_file(PDF pdf, int luatex_version, str_number luatex_revision)
/* Output article threads */
if (pdf->head_tab[obj_type_thread] != 0) {
- threads = pdf_new_obj(pdf, obj_type_others, 0, 1);
- pdf_out(pdf, '[');
+ threads = pdf_create_obj(pdf, obj_type_others, 0);
+ pdf_begin_obj(pdf, threads, OBJSTM_ALWAYS);
+ pdf_begin_array(pdf);
k = pdf->head_tab[obj_type_thread];
while (k != 0) {
- pdf_print_int(pdf, k);
- pdf_puts(pdf, " 0 R ");
+ pdf_add_ref(pdf, k);
k = obj_link(pdf, k);
}
- pdf_remove_last_space(pdf);
- pdf_puts(pdf, "]\n");
+ pdf_end_array(pdf);
pdf_end_obj(pdf);
k = pdf->head_tab[obj_type_thread];
while (k != 0) {
@@ -2326,34 +2432,38 @@ void finish_pdf_file(PDF pdf, int luatex_version, str_number luatex_revision)
}
/* Output the /Catalog object */
- root = pdf_new_dict(pdf, obj_type_catalog, 0, 1);
- pdf_puts(pdf, "/Type /Catalog\n");
- pdf_indirect_ln(pdf, "Pages", pdf->last_pages);
+ root = pdf_create_obj(pdf, obj_type_catalog, 0);
+ pdf_begin_obj(pdf, root, OBJSTM_ALWAYS);
+ pdf_begin_dict(pdf);
+ pdf_dict_add_name(pdf, "Type", "Catalog");
+ pdf_dict_add_ref(pdf, "Pages", pdf->last_pages);
if (threads != 0)
- pdf_indirect_ln(pdf, "Threads", threads);
+ pdf_dict_add_ref(pdf, "Threads", threads);
if (outlines != 0)
- pdf_indirect_ln(pdf, "Outlines", outlines);
+ pdf_dict_add_ref(pdf, "Outlines", outlines);
if (names_tree != 0)
- pdf_indirect_ln(pdf, "Names", names_tree);
+ pdf_dict_add_ref(pdf, "Names", names_tree);
if (pdf_catalog_toks != null) {
- pdf_print_toks_ln(pdf, pdf_catalog_toks);
+ pdf_print_toks(pdf, pdf_catalog_toks);
delete_token_ref(pdf_catalog_toks);
pdf_catalog_toks = null;
}
if (pdf_catalog_openaction != 0)
- pdf_indirect_ln(pdf, "OpenAction", pdf_catalog_openaction);
+ pdf_dict_add_ref(pdf, "OpenAction", pdf_catalog_openaction);
pdf_end_dict(pdf);
+ pdf_end_obj(pdf);
/* last candidate for object stream */
- info = pdf_print_info(pdf, luatex_version, luatex_revision); /* final object for pdf->os_enable == false */
+ info = pdf_print_info(pdf, luatexversion, luatexrevision); /* final object for pdf->os_enable == false */
if (pdf->os_enable) {
- pdf_os_switch(pdf, true);
+ pdf_buffer_select(pdf, OBJSTM_BUF);
pdf_os_write_objstream(pdf);
pdf_flush(pdf);
- pdf_os_switch(pdf, false);
+ pdf_buffer_select(pdf, PDFOUT_BUF);
/* Output the cross-reference stream dictionary */
- xref_stm = pdf_new_dict(pdf, obj_type_others, 0, 0); /* final object for pdf->os_enable == true */
+ xref_stm = pdf_create_obj(pdf, obj_type_others, 0);
+ pdf_begin_obj(pdf, xref_stm, OBJSTM_NEVER); /* final object for pdf->os_enable == true */
if ((obj_offset(pdf, pdf->obj_ptr) / 256) > 16777215)
xref_offset_width = 5;
else if (obj_offset(pdf, pdf->obj_ptr) > 16777215)
@@ -2364,30 +2474,37 @@ void finish_pdf_file(PDF pdf, int luatex_version, str_number luatex_revision)
xref_offset_width = 2;
/* Build a linked list of free objects */
build_free_object_list(pdf);
- pdf_puts(pdf, "/Type /XRef\n");
- pdf_puts(pdf, "/Index [0 ");
- pdf_print_int(pdf, pdf->obj_ptr + 1);
- pdf_puts(pdf, "]\n");
- pdf_int_entry_ln(pdf, "Size", pdf->obj_ptr + 1);
- pdf_puts(pdf, "/W [1 ");
- pdf_print_int(pdf, (int) xref_offset_width);
- pdf_puts(pdf, " 1]\n");
- pdf_indirect_ln(pdf, "Root", root);
- pdf_indirect_ln(pdf, "Info", info);
+ pdf_begin_dict(pdf);
+ pdf_dict_add_name(pdf, "Type", "XRef");
+ pdf_add_name(pdf, "Index");
+ pdf_begin_array(pdf);
+ pdf_add_int(pdf, 0);
+ pdf_add_int(pdf, pdf->obj_ptr + 1);
+ pdf_end_array(pdf);
+ pdf_dict_add_int(pdf, "Size", pdf->obj_ptr + 1);
+ pdf_add_name(pdf, "W");
+ pdf_begin_array(pdf);
+ pdf_add_int(pdf, 1);
+ pdf_add_int(pdf, (int) xref_offset_width);
+ pdf_add_int(pdf, 1);
+ pdf_end_array(pdf);
+ pdf_dict_add_ref(pdf, "Root", root);
+ pdf_dict_add_ref(pdf, "Info", info);
if (pdf_trailer_toks != null) {
- pdf_print_toks_ln(pdf, pdf_trailer_toks);
+ pdf_print_toks(pdf, pdf_trailer_toks);
delete_token_ref(pdf_trailer_toks);
pdf_trailer_toks = null;
}
- print_ID(pdf, pdf->file_name);
- pdf_print_nl(pdf);
+ print_ID(pdf);
+ pdf_dict_add_streaminfo(pdf);
+ pdf_end_dict(pdf);
pdf_begin_stream(pdf);
for (k = 0; k <= pdf->obj_ptr; k++) {
if (!is_obj_written(pdf, k)) { /* a free object */
pdf_out(pdf, 0);
pdf_out_bytes(pdf, obj_link(pdf, k), xref_offset_width);
pdf_out(pdf, 255);
- } else if (obj_os_idx(pdf, k) == -1) { /* object not in object stream */
+ } else if (obj_os_idx(pdf, k) == PDF_OS_MAX_OBJS) { /* object not in object stream */
pdf_out(pdf, 1);
pdf_out_bytes(pdf, obj_offset(pdf, k),
xref_offset_width);
@@ -2400,6 +2517,7 @@ void finish_pdf_file(PDF pdf, int luatex_version, str_number luatex_revision)
}
}
pdf_end_stream(pdf);
+ pdf_end_obj(pdf);
/* TODO: generate a debug version of the crossref */
pdf_flush(pdf);
@@ -2429,26 +2547,29 @@ void finish_pdf_file(PDF pdf, int luatex_version, str_number luatex_revision)
/* Output the trailer */
if (!pdf->os_enable) {
pdf_puts(pdf, "trailer\n");
- pdf_puts(pdf, "<< ");
- pdf_int_entry_ln(pdf, "Size", pdf->obj_ptr + 1);
- pdf_indirect_ln(pdf, "Root", root);
- pdf_indirect_ln(pdf, "Info", info);
+ pdf_begin_dict(pdf);
+ pdf_dict_add_int(pdf, "Size", pdf->obj_ptr + 1);
+ pdf_dict_add_ref(pdf, "Root", root);
+ pdf_dict_add_ref(pdf, "Info", info);
if (pdf_trailer_toks != null) {
- pdf_print_toks_ln(pdf, pdf_trailer_toks);
+ pdf_print_toks(pdf, pdf_trailer_toks);
delete_token_ref(pdf_trailer_toks);
pdf_trailer_toks = null;
}
- print_ID(pdf, pdf->file_name);
- pdf_puts(pdf, " >>\n");
+ print_ID(pdf);
+ pdf_end_dict(pdf);
+ pdf_out(pdf, '\n');
}
pdf_puts(pdf, "startxref\n");
+ pdf->cave = 0;
if (pdf->os_enable)
- pdf_print_int_ln(pdf, obj_offset(pdf, xref_stm));
+ pdf_add_longint(pdf, (longinteger) obj_offset(pdf, xref_stm));
else
- pdf_print_int_ln(pdf, pdf_saved_offset(pdf));
- pdf_puts(pdf, "%%EOF\n");
+ pdf_add_longint(pdf, (longinteger) pdf->save_offset);
+ pdf_puts(pdf, "\n%%EOF\n");
pdf_flush(pdf);
+
if (callback_id == 0) {
tprint_nl("Output written on ");
tprint(pdf->file_name);
@@ -2462,7 +2583,7 @@ void finish_pdf_file(PDF pdf, int luatex_version, str_number luatex_revision)
tprint(" bytes).");
print_ln();
} else if (callback_id > 0) {
- res = run_callback(callback_id, "->");
+ run_callback(callback_id, "->");
}
}
libpdffinish(pdf);
@@ -2475,17 +2596,16 @@ void finish_pdf_file(PDF pdf, int luatex_version, str_number luatex_revision)
}
if (callback_id == 0) {
- if (log_opened) {
+ if (log_opened_global) {
fprintf(log_file,
"\nPDF statistics: %d PDF objects out of %d (max. %d)\n",
(int) pdf->obj_ptr, (int) pdf->obj_tab_size,
(int) sup_obj_tab_size);
- if (pdf->os_cntr > 0) {
+ if (pdf->os->ostm_ctr > 0) {
fprintf(log_file,
" %d compressed objects within %d object stream%s\n",
- (int) ((pdf->os_cntr - 1) * pdf_os_max_objs +
- pdf->os_idx + 1), (int) pdf->os_cntr,
- (pdf->os_cntr > 1 ? "s" : ""));
+ (int) pdf->os->o_ctr, (int) pdf->os->ostm_ctr,
+ (pdf->os->ostm_ctr > 1 ? "s" : ""));
}
fprintf(log_file, " %d named destinations out of %d (max. %d)\n",
(int) pdf->dest_names_ptr, (int) pdf->dest_names_size,
@@ -2510,7 +2630,8 @@ void scan_pdfcatalog(PDF pdf)
} else {
check_o_mode(pdf, "\\pdfcatalog", 1 << OMODE_PDF, true);
p = scan_action(pdf);
- pdf_catalog_openaction = pdf_new_obj(pdf, obj_type_others, 0, 1);
+ pdf_catalog_openaction = pdf_create_obj(pdf, obj_type_others, 0);
+ pdf_begin_obj(pdf, pdf_catalog_openaction, OBJSTM_ALWAYS);
write_action(pdf, p);
pdf_end_obj(pdf);
delete_action_ref(p);