summaryrefslogtreecommitdiff
path: root/Build/source/texk/web2c/luatexdir
diff options
context:
space:
mode:
authorLuigi Scarso <luigi.scarso@gmail.com>2019-11-08 09:36:30 +0000
committerLuigi Scarso <luigi.scarso@gmail.com>2019-11-08 09:36:30 +0000
commit034a409094cd443345893b589c78c74da42de3bf (patch)
tree4aa1863fd733bac3fb532e9a7c856140b6f0c88b /Build/source/texk/web2c/luatexdir
parente83bb7136c59c830a0a2a83e1526aa7ed3030bc3 (diff)
sync with luatex local svn repo.
git-svn-id: svn://tug.org/texlive/trunk@52692 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Build/source/texk/web2c/luatexdir')
-rw-r--r--Build/source/texk/web2c/luatexdir/ChangeLog14
-rw-r--r--Build/source/texk/web2c/luatexdir/font/luafont.c5
-rw-r--r--Build/source/texk/web2c/luatexdir/font/mapfile.c1
-rw-r--r--Build/source/texk/web2c/luatexdir/font/mapfile.h21
-rw-r--r--Build/source/texk/web2c/luatexdir/font/texfont.c98
-rw-r--r--Build/source/texk/web2c/luatexdir/font/texfont.h126
-rw-r--r--Build/source/texk/web2c/luatexdir/font/writefont.c1
-rw-r--r--Build/source/texk/web2c/luatexdir/font/writetype0.c8
-rw-r--r--Build/source/texk/web2c/luatexdir/font/writetype2.c3
-rw-r--r--Build/source/texk/web2c/luatexdir/lua/lpdfscannerlib.cc1041
-rw-r--r--Build/source/texk/web2c/luatexdir/lua/luatex-api.h7
-rw-r--r--Build/source/texk/web2c/luatexdir/luapplib/ppconf.h3
-rw-r--r--Build/source/texk/web2c/luatexdir/luapplib/ppload.c.orig2555
-rw-r--r--Build/source/texk/web2c/luatexdir/luatex.c4
-rw-r--r--Build/source/texk/web2c/luatexdir/luatex_svnversion.h2
-rw-r--r--Build/source/texk/web2c/luatexdir/tex/dumpdata.c2
-rw-r--r--Build/source/texk/web2c/luatexdir/tex/linebreak.c18
17 files changed, 173 insertions, 3736 deletions
diff --git a/Build/source/texk/web2c/luatexdir/ChangeLog b/Build/source/texk/web2c/luatexdir/ChangeLog
index fadf29dcd9c..318b0b29df9 100644
--- a/Build/source/texk/web2c/luatexdir/ChangeLog
+++ b/Build/source/texk/web2c/luatexdir/ChangeLog
@@ -1,3 +1,17 @@
+2019-11-08 Luigi Scarso <luigi.scarso@gmail.com>
+ * record a few more files (in kpse enabled mode) (HH)
+
+
+2019-11-05 Luigi Scarso <luigi.scarso@gmail.com>
+ * fixed calculation of if (abs(fit_class - fitness(r)) > 1)
+ in lineabreak.c (thanks to M. Krüger). This produced different
+ results in Windows and Linux.
+
+
+2019-10-31 Luigi Scarso <luigi.scarso@gmail.com>
+ * subfont key in font table (to identify subfint in ttc) plus
+ some cleanup (HH)
+
2019-10-28 Luigi Scarso <luigi.scarso@gmail.com>
* New callback lua.getcodepage() for diagnostic purposes.
diff --git a/Build/source/texk/web2c/luatexdir/font/luafont.c b/Build/source/texk/web2c/luatexdir/font/luafont.c
index 62edb175812..14efbf8a794 100644
--- a/Build/source/texk/web2c/luatexdir/font/luafont.c
+++ b/Build/source/texk/web2c/luatexdir/font/luafont.c
@@ -478,6 +478,7 @@ int font_to_lua(lua_State * L, int f)
dump_intfield(L,width,font_width(f));
dump_intfield(L,direction,font_natural_dir(f));
dump_intfield(L,encodingbytes,font_encodingbytes(f));
+ dump_intfield(L,subfont,font_subfont(f));
dump_booleanfield(L,oldmath,font_oldmath(f));
dump_intfield(L,tounicode,font_tounicode(f));
/*tex The next one is read only: */
@@ -500,7 +501,7 @@ int font_to_lua(lua_State * L, int f)
write_lua_math_parameters(L, f);
/*tex Characters: */
lua_push_string_by_name(L,characters);
- lua_createtable(L, font_tables[f]->charinfo_size, 0);
+ lua_createtable(L, charinfo_size(f), 0);
if (has_left_boundary(f)) {
co = get_charinfo(f, left_boundarychar);
lua_push_string_by_name(L,left_boundary);
@@ -1554,6 +1555,8 @@ int font_from_lua(lua_State * L, int f)
if (font_encodingbytes(f) == 0 && (font_format(f) == opentype_format || font_format(f) == truetype_format)) {
set_font_encodingbytes(f, 2);
}
+ i = lua_numeric_field_by_index(L,lua_key_index(subfont), 0);
+ set_font_subfont(f,i);
/*tex Now fetch the base fonts, if needed. */
count_hash_items(L, fonts, n);
if (n > 0) {
diff --git a/Build/source/texk/web2c/luatexdir/font/mapfile.c b/Build/source/texk/web2c/luatexdir/font/mapfile.c
index 077ffd691ab..7b661640403 100644
--- a/Build/source/texk/web2c/luatexdir/font/mapfile.c
+++ b/Build/source/texk/web2c/luatexdir/font/mapfile.c
@@ -80,6 +80,7 @@ fm_entry *new_fm_entry(void)
fm->fd_flags = FD_FLAGS_NOT_SET_IN_MAPLINE;
fm->ff_name = NULL;
fm->encname = NULL;
+ fm->subfont = 0;
fm->type = 0;
fm->slant = 0;
fm->extend = 1000;
diff --git a/Build/source/texk/web2c/luatexdir/font/mapfile.h b/Build/source/texk/web2c/luatexdir/font/mapfile.h
index e3e0e613add..2b2f3cbf1a8 100644
--- a/Build/source/texk/web2c/luatexdir/font/mapfile.h
+++ b/Build/source/texk/web2c/luatexdir/font/mapfile.h
@@ -81,19 +81,20 @@ typedef enum { MAPFILE, MAPLINE } maptype;
typedef struct {
/* parameters scanned from the map file: */
- char *tfm_name; /* TFM file name (1st field in map line) */
- char *ps_name; /* PostScript name (optional 2nd field in map line) */
- int fd_flags; /* font descriptor /Flags (PDF Ref. section 5.7.1) */
- int slant; /* SlantFont */
- int extend; /* ExtendFont */
- char *encname; /* encoding file name */
- char *ff_name; /* font file name */
- unsigned short type; /* various flags */
+ char *tfm_name; /* TFM file name (1st field in map line) */
+ char *ps_name; /* PostScript name (optional 2nd field in map line) */
+ int fd_flags; /* font descriptor /Flags (PDF Ref. section 5.7.1) */
+ int slant; /* SlantFont */
+ int extend; /* ExtendFont */
+ char *encname; /* encoding file name */
+ int subfont; /* specific index in a ttc file */
+ char *ff_name; /* font file name */
+ unsigned short type; /* various flags */
} fm_entry;
typedef struct {
- char *ff_name; /* base name of font file */
- char *ff_path; /* full path to font file */
+ char *ff_name; /* base name of font file */
+ char *ff_path; /* full path to font file */
} ff_entry;
/**********************************************************************/
diff --git a/Build/source/texk/web2c/luatexdir/font/texfont.c b/Build/source/texk/web2c/luatexdir/font/texfont.c
index 332a8a3446e..0134243d929 100644
--- a/Build/source/texk/web2c/luatexdir/font/texfont.c
+++ b/Build/source/texk/web2c/luatexdir/font/texfont.c
@@ -125,6 +125,8 @@ int new_font(void)
set_font_bc(id, 1);
set_font_writingmode(id, 0);
set_font_identity(id, 0);
+ /* set_font_encoding_bytes(id,1) */ /* ? */
+ set_font_subfont(id, 0);
set_hyphen_char(id, '-');
set_skew_char(id, -1);
/*tex vertical */
@@ -141,45 +143,44 @@ int new_font(void)
set_font_param(id, k, 0);
}
/*tex character info zero is reserved for |notdef|. The stack size 1, default item value 0. */
- font_tables[id]->characters = new_sa_tree(1, 1, sa_value);
+ font_tables[id]->_characters = new_sa_tree(1, 1, sa_value);
ci = xcalloc(1, sizeof(charinfo));
set_charinfo_name(ci, xstrdup(".notdef"));
- font_tables[id]->charinfo = ci;
- font_tables[id]->charinfo_size = 1;
- font_tables[id]->charinfo_cache = NULL;
+ font_tables[id]->_charinfo = ci;
+ font_tables[id]->_charinfo_size = 1;
return id;
}
void font_malloc_charinfo(internal_font_number f, int num)
{
- int glyph = font_tables[f]->charinfo_size;
+ int glyph = font_tables[f]->_charinfo_size;
font_bytes += (int) (num * (int) sizeof(charinfo));
- do_realloc(font_tables[f]->charinfo, (unsigned) (glyph + num), charinfo);
- memset(&(font_tables[f]->charinfo[glyph]), 0, (size_t) (num * (int) sizeof(charinfo)));
- font_tables[f]->charinfo_size += num;
+ do_realloc(font_tables[f]->_charinfo, (unsigned) (glyph + num), charinfo);
+ memset(&(font_tables[f]->_charinfo[glyph]), 0, (size_t) (num * (int) sizeof(charinfo)));
+ font_tables[f]->_charinfo_size += num;
}
-#define find_charinfo_id(f,c) (get_sa_item(font_tables[f]->characters,c).int_value)
+#define find_charinfo_id(f,c) (get_sa_item(font_tables[f]->_characters,c).int_value)
charinfo *get_charinfo(internal_font_number f, int c)
{
int glyph;
charinfo *ci;
if (proper_char_index(c)) {
- glyph = get_sa_item(font_tables[f]->characters, c).int_value;
+ glyph = get_sa_item(font_tables[f]->_characters, c).int_value;
if (!glyph) {
sa_tree_item sa_value = { 0 };
- int tglyph = ++font_tables[f]->charinfo_count;
- if (tglyph >= font_tables[f]->charinfo_size) {
+ int tglyph = ++font_tables[f]->_charinfo_count;
+ if (tglyph >= font_tables[f]->_charinfo_size) {
font_malloc_charinfo(f, 256);
}
- font_tables[f]->charinfo[tglyph].ef = 1000;
+ font_tables[f]->_charinfo[tglyph].ef = 1000;
sa_value.int_value = tglyph;
/*tex 1 means global */
- set_sa_item(font_tables[f]->characters, c, sa_value, 1);
+ set_sa_item(font_tables[f]->_characters, c, sa_value, 1);
glyph = tglyph;
}
- return &(font_tables[f]->charinfo[glyph]);
+ return &(font_tables[f]->_charinfo[glyph]);
} else if (c == left_boundarychar) {
if (left_boundary(f) == NULL) {
ci = xcalloc(1, sizeof(charinfo));
@@ -195,16 +196,16 @@ charinfo *get_charinfo(internal_font_number f, int c)
}
return right_boundary(f);
}
- return &(font_tables[f]->charinfo[0]);
+ return &(font_tables[f]->_charinfo[0]);
}
static void set_charinfo(internal_font_number f, int c, charinfo * ci)
{
int glyph;
if (proper_char_index(c)) {
- glyph = get_sa_item(font_tables[f]->characters, c).int_value;
+ glyph = get_sa_item(font_tables[f]->_characters, c).int_value;
if (glyph) {
- font_tables[f]->charinfo[glyph] = *ci;
+ font_tables[f]->_charinfo[glyph] = *ci;
} else {
normal_error("font","character insertion failed");
}
@@ -319,13 +320,13 @@ charinfo *char_info(internal_font_number f, int c)
return 0;
if (proper_char_index(c)) {
register int glyph = (int) find_charinfo_id(f, c);
- return &(font_tables[f]->charinfo[glyph]);
+ return &(font_tables[f]->_charinfo[glyph]);
} else if (c == left_boundarychar && left_boundary(f) != NULL) {
return left_boundary(f);
} else if (c == right_boundarychar && right_boundary(f) != NULL) {
return right_boundary(f);
}
- return &(font_tables[f]->charinfo[0]);
+ return &(font_tables[f]->_charinfo[0]);
}
scaled_whd get_charinfo_whd(internal_font_number f, int c)
@@ -1073,15 +1074,15 @@ int copy_font(int f)
charinfo *ci;
int k = new_font();
{
- ci = font_tables[k]->charinfo;
- ci_cnt = font_tables[k]->charinfo_count;
- ci_size = font_tables[k]->charinfo_size;
+ ci = font_tables[k]->_charinfo;
+ ci_cnt = font_tables[k]->_charinfo_count;
+ ci_size = font_tables[k]->_charinfo_size;
memcpy(font_tables[k], font_tables[f], sizeof(texfont));
- font_tables[k]->charinfo = ci;
- font_tables[k]->charinfo_count = ci_cnt;
- font_tables[k]->charinfo_size = ci_size;
+ font_tables[k]->_charinfo = ci;
+ font_tables[k]->_charinfo_count = ci_cnt;
+ font_tables[k]->_charinfo_size = ci_size;
}
- font_malloc_charinfo(k, font_tables[f]->charinfo_count);
+ font_malloc_charinfo(k, font_tables[f]->_charinfo_count);
set_font_cache_id(k, 0);
set_font_used(k, 0);
set_font_touched(k, 0);
@@ -1110,6 +1111,8 @@ int copy_font(int f)
set_font_cidregistry(k, xstrdup(font_cidregistry(f)));
if (font_cidordering(f) != NULL)
set_font_cidordering(k, xstrdup(font_cidordering(f)));
+ set_font_encodingbytes(k,font_encodingbytes(f));
+ set_font_subfont(k,font_subfont(f));
i = (int) (sizeof(*param_base(f)) * (unsigned) (font_params(f)+1));
font_bytes += i;
param_base(k) = xmalloc((unsigned) (i+1));
@@ -1121,9 +1124,9 @@ int copy_font(int f)
math_param_base(k) = xmalloc((unsigned) i);
memcpy(math_param_base(k), math_param_base(f), (size_t) i);
}
- for (i = 0; i <= font_tables[f]->charinfo_count; i++) {
- ci = copy_charinfo(&font_tables[f]->charinfo[i]);
- font_tables[k]->charinfo[i] = *ci;
+ for (i = 0; i <= font_tables[f]->_charinfo_count; i++) {
+ ci = copy_charinfo(&font_tables[f]->_charinfo[i]);
+ font_tables[k]->_charinfo[i] = *ci;
}
if (left_boundary(f) != NULL) {
ci = copy_charinfo(left_boundary(f));
@@ -1134,7 +1137,7 @@ int copy_font(int f)
set_charinfo(k, right_boundarychar, ci);
}
/*tex Not updated yet: */
- font_tables[k]->charinfo_count = font_tables[f]->charinfo_count;
+ font_tables[k]->_charinfo_count = font_tables[f]->_charinfo_count;
return k;
}
@@ -1167,9 +1170,9 @@ void delete_font(int f)
}
}
/*tex free |notdef| */
- set_charinfo_name(font_tables[f]->charinfo + 0, NULL);
- free(font_tables[f]->charinfo);
- destroy_sa_tree(font_tables[f]->characters);
+ set_charinfo_name(font_tables[f]->_charinfo + 0, NULL);
+ free(font_tables[f]->_charinfo);
+ destroy_sa_tree(font_tables[f]->_characters);
free(param_base(f));
if (math_param_base(f) != NULL)
free(math_param_base(f));
@@ -1339,17 +1342,17 @@ void set_no_ligatures(internal_font_number f)
{
int c;
charinfo *co;
- if (font_tables[f]->ligatures_disabled)
+ if (font_tables[f]->_ligatures_disabled)
return;
co = char_info(f, left_boundarychar);
set_charinfo_ligatures(co, NULL);
co = char_info(f, right_boundarychar);
set_charinfo_ligatures(co, NULL);
- for (c = 0; c < font_tables[f]->charinfo_count; c++) {
- co = font_tables[f]->charinfo + c;
+ for (c = 0; c < font_tables[f]->_charinfo_count; c++) {
+ co = font_tables[f]->_charinfo + c;
set_charinfo_ligatures(co, NULL);
}
- font_tables[f]->ligatures_disabled = 1;
+ font_tables[f]->_ligatures_disabled = 1;
}
liginfo get_ligature(internal_font_number f, int lc, int rc)
@@ -1496,14 +1499,15 @@ static void dump_font_entry(texfont * f)
dump_int(f->_font_touched);
dump_int(f->_font_cache_id);
dump_int(f->_font_encodingbytes);
+ dump_int(f->_font_subfont);
dump_int(f->_font_oldmath);
dump_int(f->_font_slant);
dump_int(f->_font_extend);
dump_int(f->_font_squeeze);
dump_int(f->_font_mode);
dump_int(f->_font_width);
- dump_int(f->font_max_shrink);
- dump_int(f->font_max_stretch);
+ dump_int(f->_font_max_shrink);
+ dump_int(f->_font_max_stretch);
dump_int(f->_font_step);
dump_int(f->_font_tounicode);
dump_int(f->_font_type);
@@ -1518,7 +1522,7 @@ static void dump_font_entry(texfont * f)
dump_int(f->_font_natural_dir);
dump_int(f->_font_params);
dump_int(f->_font_math_params);
- dump_int(f->ligatures_disabled);
+ dump_int(f->_ligatures_disabled);
dump_int(f->_pdf_font_num);
dump_int(f->_pdf_font_attr);
}
@@ -1527,7 +1531,6 @@ void dump_font(int f)
{
int i, x;
set_font_used(f, 0);
- font_tables[f]->charinfo_cache = NULL;
dump_font_entry(font_tables[f]);
dump_string(font_name(f));
dump_string(font_area(f));
@@ -1669,14 +1672,15 @@ static void undump_font_entry(texfont * f)
undump_int(x); f->_font_touched = (char)x;
undump_int(x); f->_font_cache_id = x;
undump_int(x); f->_font_encodingbytes = (char)x;
+ undump_int(x); f->_font_subfont = x;
undump_int(x); f->_font_oldmath = x;
undump_int(x); f->_font_slant = x;
undump_int(x); f->_font_extend = x;
undump_int(x); f->_font_squeeze = x;
undump_int(x); f->_font_mode = x;
undump_int(x); f->_font_width = x;
- undump_int(x); f->font_max_shrink = x;
- undump_int(x); f->font_max_stretch = x;
+ undump_int(x); f->_font_max_shrink = x;
+ undump_int(x); f->_font_max_stretch = x;
undump_int(x); f->_font_step = x;
undump_int(x); f->_font_tounicode = (char)x;
undump_int(x); f->_font_type = x;
@@ -1691,7 +1695,7 @@ static void undump_font_entry(texfont * f)
undump_int(x); f->_font_natural_dir = x;
undump_int(x); f->_font_params = x;
undump_int(x); f->_font_math_params = x;
- undump_int(x); f->ligatures_disabled = x;
+ undump_int(x); f->_ligatures_disabled = x;
undump_int(x); f->_pdf_font_num = x;
undump_int(x); f->_pdf_font_attr = x;
}
@@ -1729,10 +1733,10 @@ void undump_font(int f)
undump_things(*math_param_base(f), (font_math_params(f) + 1));
}
/*tex stack size 1, default item value 0 */
- font_tables[f]->characters = new_sa_tree(1, 1, sa_value);
+ font_tables[f]->_characters = new_sa_tree(1, 1, sa_value);
ci = xcalloc(1, sizeof(charinfo));
set_charinfo_name(ci, xstrdup(".notdef"));
- font_tables[f]->charinfo = ci;
+ font_tables[f]->_charinfo = ci;
undump_int(x);
if (x) {
/*tex left boundary */
diff --git a/Build/source/texk/web2c/luatexdir/font/texfont.h b/Build/source/texk/web2c/luatexdir/font/texfont.h
index 2622b7a14ed..7c27d09565c 100644
--- a/Build/source/texk/web2c/luatexdir/font/texfont.h
+++ b/Build/source/texk/web2c/luatexdir/font/texfont.h
@@ -129,67 +129,60 @@ extern extinfo *new_variant(int glyph, int startconnect, int endconnect, int adv
extern scaled_whd get_charinfo_whd(internal_font_number f, int c);
typedef struct texfont {
- int _font_size;
- int _font_dsize;
- int _font_units_per_em;
- char *_font_name;
- char *_font_area;
- char *_font_filename;
- char *_font_fullname;
- char *_font_psname;
- char *_font_encodingname;
- char *_font_cidregistry;
- char *_font_cidordering;
- int _font_cidversion;
- int _font_cidsupplement;
-
- int _font_ec;
- unsigned _font_checksum; /* internal information */
- char _font_used; /* internal information */
- char _font_touched; /* internal information */
- int _font_cache_id; /* internal information */
- char _font_encodingbytes; /* 1 or 2 bytes */
- boolean _font_oldmath; /* default to false when MathConstants seen */
- int _font_slant; /* a slant in ppt */
- int _font_extend; /* an extension in ppt, or 1000 */
- int _font_squeeze; /* an extension in ppt, or 1000 */
- int _font_width;
- int _font_mode;
- int font_max_shrink;
- int font_max_stretch;
- int _font_step; /* amount of one step of expansion */
-
- char _font_tounicode; /* 1 if info is present */
- fm_entry *_font_map;
- int _font_type;
- int _font_format;
- int _font_writingmode;
- int _font_identity;
- int _font_embedding;
- int _font_streamprovider;
- int _font_bc;
- int _hyphen_char;
- int _skew_char;
- int _font_natural_dir;
-
- charinfo *_left_boundary;
- charinfo *_right_boundary;
-
- int _font_params;
- scaled *_param_base;
-
- int _font_math_params;
- scaled *_math_param_base;
-
- sa_tree characters;
- int charinfo_count;
- int charinfo_size;
- charinfo *charinfo;
- int *charinfo_cache;
- int ligatures_disabled;
-
- int _pdf_font_num; /* maps to a PDF resource ID */
- str_number _pdf_font_attr; /* pointer to additional attributes */
+ int _font_size;
+ int _font_dsize;
+ int _font_units_per_em;
+ char *_font_name;
+ char *_font_area;
+ char *_font_filename;
+ char *_font_fullname;
+ char *_font_psname;
+ char *_font_encodingname;
+ char *_font_cidregistry;
+ char *_font_cidordering;
+ int _font_cidversion;
+ int _font_cidsupplement;
+ int _font_ec;
+ unsigned _font_checksum; /* internal information */
+ char _font_used; /* internal information */
+ char _font_touched; /* internal information */
+ int _font_cache_id; /* internal information */
+ char _font_encodingbytes; /* 1 or 2 bytes */
+ int _font_subfont;
+ boolean _font_oldmath; /* default to false when MathConstants seen */
+ int _font_slant; /* a slant in ppt */
+ int _font_extend; /* an extension in ppt, or 1000 */
+ int _font_squeeze; /* an extension in ppt, or 1000 */
+ int _font_width;
+ int _font_mode;
+ int _font_max_shrink;
+ int _font_max_stretch;
+ int _font_step; /* amount of one step of expansion */
+ char _font_tounicode; /* 1 if info is present */
+ fm_entry *_font_map;
+ int _font_type;
+ int _font_format;
+ int _font_writingmode;
+ int _font_identity;
+ int _font_embedding;
+ int _font_streamprovider;
+ int _font_bc;
+ int _hyphen_char;
+ int _skew_char;
+ int _font_natural_dir;
+ charinfo *_left_boundary;
+ charinfo *_right_boundary;
+ int _font_params;
+ scaled *_param_base;
+ int _font_math_params;
+ scaled *_math_param_base;
+ sa_tree _characters;
+ int _charinfo_count;
+ int _charinfo_size;
+ charinfo *_charinfo;
+ int _ligatures_disabled;
+ int _pdf_font_num; /* maps to a PDF resource ID */
+ str_number _pdf_font_attr; /* pointer to additional attributes */
} texfont;
typedef enum {
@@ -330,6 +323,9 @@ boolean cmp_font_area(int, str_number);
# define font_encodingbytes(a) font_tables[a]->_font_encodingbytes
# define set_font_encodingbytes(a,b) font_encodingbytes(a) = b
+# define font_subfont(a) font_tables[a]->_font_subfont
+# define set_font_subfont(a,b) font_subfont(a) = b
+
# define font_streamprovider(a) font_tables[a]->_font_streamprovider
# define set_font_streamprovider(a,b) font_streamprovider(a) = b
@@ -358,10 +354,10 @@ boolean cmp_font_area(int, str_number);
# define font_stretch(a) font_tables[a]->_font_stretch
# define set_font_stretch(a,b) font_stretch(a) = b
-# define font_max_shrink(a) font_tables[a]->font_max_shrink
+# define font_max_shrink(a) font_tables[a]->_font_max_shrink
# define set_font_max_shrink(a,b) font_max_shrink(a) = b
-# define font_max_stretch(a) font_tables[a]->font_max_stretch
+# define font_max_stretch(a) font_tables[a]->_font_max_stretch
# define set_font_max_stretch(a,b) font_max_stretch(a) = b
# define font_step(a) font_tables[a]->_font_step
@@ -385,6 +381,8 @@ boolean cmp_font_area(int, str_number);
# define pdf_font_attr(a) font_tables[a]->_pdf_font_attr
# define set_pdf_font_attr(a,b) pdf_font_attr(a) = b
+# define charinfo_size(a) font_tables[a]->_charinfo_size
+
# define left_boundarychar -1
# define right_boundarychar -2
# define non_boundarychar -3
@@ -467,7 +465,7 @@ extern charinfo *char_info(internal_font_number f, int c);
glyph id, not one of the two special boundary objects.
*/
-# define quick_char_exists(f,c) (get_sa_item(font_tables[f]->characters,c).int_value)
+# define quick_char_exists(f,c) (get_sa_item(font_tables[f]->_characters,c).int_value)
extern void set_charinfo_width(charinfo * ci, scaled val);
extern void set_charinfo_height(charinfo * ci, scaled val);
diff --git a/Build/source/texk/web2c/luatexdir/font/writefont.c b/Build/source/texk/web2c/luatexdir/font/writefont.c
index 5d902c954a9..b367fa2bf85 100644
--- a/Build/source/texk/web2c/luatexdir/font/writefont.c
+++ b/Build/source/texk/web2c/luatexdir/font/writefont.c
@@ -814,6 +814,7 @@ void do_pdf_font(PDF pdf, internal_font_number f)
}
/*tex Needed for the CIDSystemInfo: */
fm->encname = font_encodingname(f);
+ fm->subfont = font_subfont(f);
fm->slant = font_slant(f);
set_slantset(fm);
fm->extend = font_extend(f);
diff --git a/Build/source/texk/web2c/luatexdir/font/writetype0.c b/Build/source/texk/web2c/luatexdir/font/writetype0.c
index 7a81d58c992..d7e74113226 100644
--- a/Build/source/texk/web2c/luatexdir/font/writetype0.c
+++ b/Build/source/texk/web2c/luatexdir/font/writetype0.c
@@ -48,8 +48,7 @@ void writetype0(PDF pdf, fd_entry * fd)
assert(is_included(fd_cur->fm));
ttf_curbyte = 0;
ttf_size = 0;
- cur_file_name =
- luatex_find_file(fd_cur->fm->ff_name, find_opentype_file_callback);
+ cur_file_name = luatex_find_file(fd_cur->fm->ff_name, find_opentype_file_callback);
if (cur_file_name == NULL) {
cur_file_name =
luatex_find_file(fd_cur->fm->ff_name, find_truetype_file_callback);
@@ -75,18 +74,15 @@ void writetype0(PDF pdf, fd_entry * fd)
fd_cur->ff_found = true;
sfont = sfnt_open(ttf_buffer, ttf_size);
if (sfont->type == SFNT_TYPE_TTC)
- i = ff_get_ttc_index(fd->fm->ff_name, fd->fm->ps_name);
-
+ i = fd->fm->subfont > 0 ? (fd->fm->subfont - 1): ff_get_ttc_index(fd->fm->ff_name, fd->fm->ps_name);
if (is_subsetted(fd_cur->fm)) {
report_start_file(filetype_subset, cur_file_name);
} else {
report_start_file(filetype_font, cur_file_name);
}
-
if (sfont->type == SFNT_TYPE_TTC) otc_read_tabdir(i);
else ttf_read_tabdir();
sfnt_close(sfont);
-
/*tex Read font parameters: */
if (ttf_name_lookup("head", false) != NULL)
ttf_read_head();
diff --git a/Build/source/texk/web2c/luatexdir/font/writetype2.c b/Build/source/texk/web2c/luatexdir/font/writetype2.c
index 49193579b7e..5ba1e8ec3d5 100644
--- a/Build/source/texk/web2c/luatexdir/font/writetype2.c
+++ b/Build/source/texk/web2c/luatexdir/font/writetype2.c
@@ -237,7 +237,7 @@ boolean make_tt_subset(PDF pdf, fd_entry * fd, unsigned char *buff, int buflen)
cidtogidmap = NULL;
sfont = sfnt_open(buff, buflen);
if (sfont->type == SFNT_TYPE_TTC) {
- i = ff_get_ttc_index(fd->fm->ff_name, fd->fm->ps_name);
+ i = fd->fm->subfont > 0 ? (fd->fm->subfont - 1) : ff_get_ttc_index(fd->fm->ff_name, fd->fm->ps_name);
error = sfnt_read_table_directory(sfont, ttc_read_offset(sfont, (int) i, fd));
} else {
error = sfnt_read_table_directory(sfont, 0);
@@ -306,6 +306,7 @@ boolean make_tt_subset(PDF pdf, fd_entry * fd, unsigned char *buff, int buflen)
fontfile = sfnt_create_FontFile_stream(sfont);
/*tex The |cidgidmap|: */
if (cidtogidmap != NULL) {
+ /* never seen when ndef NO_GHOSTSCRIPT_BUG */
cidtogid_obj = (unsigned long) pdf_create_obj(pdf, obj_type_others, 0);
pdf_begin_obj(pdf, (int) cidtogid_obj, OBJSTM_NEVER);
pdf_begin_dict(pdf);
diff --git a/Build/source/texk/web2c/luatexdir/lua/lpdfscannerlib.cc b/Build/source/texk/web2c/luatexdir/lua/lpdfscannerlib.cc
deleted file mode 100644
index 56452b2ff39..00000000000
--- a/Build/source/texk/web2c/luatexdir/lua/lpdfscannerlib.cc
+++ /dev/null
@@ -1,1041 +0,0 @@
-/* lpdfscannerlib.c
-
- Copyright 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/>. */
-
-/* converted example in manual:
-
-local operatortable = { }
-
-operatortable.Do = function(scanner,info)
- local resources = info.resources
- if resources then
- local val = scanner:pop()
- local name = val[2]
- local xobject = pdfe.dictionarytotable(resources.XObject[2])
- print(info.space .. "Uses XObject " .. name)
- local kind,
- entry = unpack(xobject[name])
- local dict
- if kind == 10 then -- reference
- kind,
- entry,
- dict = pdfe.getfromreference(entry)
- end
- if kind == 9 then -- stream
- dict = pdfe.dictionarytotable(dict)
- local resources = dict.Resources
- if resources then
- local newinfo = {
- space = info.space .. " " ,
- resources = Resources[2],
- }
- pdfscanner.scan(entry, operatortable, newinfo)
- end
- end
- end
-end
-
-local function Analyze(filename)
- local doc = pdfe.open(filename)
- if doc then
- local pagenum = 1
- local n = 1 -- pdfe.getnofpages(doc)
- for i=1,n do
- local page = pdfe.getpage(doc,i)
- local kind,
- data = pdfe.getfromdictionarybyname(page,"Resources")
- if kind == 10 then -- reference
- kind, data = pdfe.getfromreference(data)
- end
- data = pdfe.dictionarytotable(data)
- local info = {
- space = " " ,
- resources = data,
- }
- print("Page " .. i)
- kind, data = pdfe.getfromdictionarybyname(page,"Contents")
- if kind == 10 then -- reference
- kind, data = pdfe.getfromreference(data)
- end
- pdfscanner.scan(data,operatortable,info)
- end
- end
-end
-
-Analyze("e:/tmp/oeps.pdf")
-
-*/
-
-# include <stdlib.h>
-# include <stdio.h>
-# include <stdarg.h>
-# include <string.h>
-# include <assert.h>
-# include <math.h>
-
-extern "C" {
-# include <lua.h>
-# include <lauxlib.h>
-# include <lualib.h>
-
-# include "luapplib/pplib.h"
-}
-
-# include <lua/luatex-api.h>
-
-
-#define SCANNER "pdfscanner"
-
-#define MAXOPERANDS 1000
-
-typedef enum {
- pdf_integer = 1,
- pdf_real,
- pdf_boolean,
- pdf_name,
- pdf_operator,
- pdf_string,
- pdf_startarray,
- pdf_stoparray,
- pdf_startdict,
- pdf_stopdict,
-} pdf_token_type ;
-
-typedef struct Token {
- pdf_token_type type;
- double value;
- char *string;
-} Token;
-
-typedef struct ObjectList {
- struct ObjectList *next;
- ppstream *stream;
-} ObjectList;
-
-typedef struct scannerdata {
- int _ininlineimage;
- int _nextoperand;
- Token ** _operandstack;
- ppstream * _stream;
- ObjectList * _streams;
- const char *buffer;
- size_t position;
- size_t size;
-} scannerdata;
-
-#define PDFE_METATABLE_ARRAY "luatex.pdfe.array"
-#define PDFE_METATABLE_STREAM "luatex.pdfe.stream"
-
-typedef struct {
- void *d;
- void *pd; // reference to PdfDocument, or NULL
- unsigned long pc; // counter to detect PDFDoc change
-} udstruct;
-
-static void clear_operand_stack (scannerdata *self, int from);
-static Token *_parseToken (scannerdata *self, int c);
-static void push_token (lua_State *L, scannerdata *self);
-
-static void *priv_xmalloc (size_t size)
-{
- void *new_mem = (void *)malloc(size);
- if (new_mem == NULL) {
- fprintf(stderr, "fatal: memory exhausted (priv_xmalloc of %lu bytes).\n", (unsigned long)size);
- exit(1);
- }
- return new_mem;
-}
-
-static void *priv_xrealloc (void *old_ptr, size_t size)
-{
- void *new_mem = (void *)realloc(old_ptr, size);
- if (new_mem == NULL) {
- fprintf(stderr,"fatal: memory exhausted (realloc of %lu bytes).\n", (unsigned long)size);
- exit(EXIT_FAILURE);
- }
- return new_mem;
-}
-
-#define xreallocarray(ptr,type,size) ((type*)priv_xrealloc(ptr,(size+1)*sizeof(type)))
-
-#define INITBUFSIZE 64
-
-#define define_buffer(a) \
- char *a = (char *)priv_xmalloc (INITBUFSIZE); \
- int a##_size = INITBUFSIZE; \
- int a##index = 0; \
- memset (a,0,INITBUFSIZE)
-
-#define check_overflow(a, wsize) do { \
- if (wsize >= a##_size) { \
- int nsize = a##_size + a##_size / 4; \
- a = (char *) xreallocarray(a, char, (unsigned) nsize); \
- memset (a+a##_size, 0, a##_size / 4); \
- a##_size = nsize; \
- } \
-} while (0)
-
-
-static scannerdata * scanner_push(lua_State * L)
-{
- scannerdata *a = (scannerdata *)lua_newuserdata(L, sizeof(scannerdata));
- luaL_getmetatable(L, SCANNER);
- lua_setmetatable(L, -2);
- return a;
-}
-
-static scannerdata *scanner_check (lua_State *L, int index)
-{
- scannerdata *bar;
- luaL_checktype(L, index, LUA_TUSERDATA);
- bar = (scannerdata *)luaL_checkudata(L, index, SCANNER);
- if (bar == NULL)
- luaL_argerror(L, index, SCANNER " expected");
- return bar;
-}
-
-static void free_token (Token *token)
-{
- if (token->string) {
- free(token->string);
- }
- free(token);
-}
-
-static void clear_operand_stack (scannerdata *self, int from)
-{
- int i = self->_nextoperand-1;
- while (i>=from) {
- if (self->_operandstack[i]) {
- free_token(self->_operandstack[i]);
- self->_operandstack[i] = NULL;
- }
- i--;
- }
- self->_nextoperand = from;
-}
-
-static void push_operand (scannerdata *self, Token *token)
-{
- if (self->_nextoperand+1> MAXOPERANDS) {
- fprintf(stderr, "out of operand stack space");
- exit(1);
- }
- self->_operandstack[self->_nextoperand++] = token;
-}
-
-static Token * new_operand (pdf_token_type c)
-{
- Token *token = (Token *)priv_xmalloc(sizeof(Token));
- memset (token, 0, sizeof(Token));
- token->type = c;
- return token;
-}
-
-static void _nextStream (scannerdata *self)
-{
- if (self->buffer != NULL) {
- ppstream_done(self->_stream);
- }
- ObjectList *rover = self->_streams;
- self->_stream = rover->stream;
- self->buffer = (const char*) ppstream_all(self->_stream,&self->size,1);
- self->position = 0;
- self->_streams = rover->next;
- free(rover);
-}
-
-static int streamGetChar (scannerdata *self)
-{
- int i = EOF ;
- if (self->position < self->size) {
- const char c = self->buffer[self->position];
- ++self->position;
- i = (int) c;
- }
- if (i<0 && self->_streams) {
- _nextStream(self);
- i = streamGetChar(self);
- }
- return i;
-}
-
-static int streamLookChar (scannerdata *self)
-{
- int i = EOF ;
- if (self->position < self->size) {
- const char c = self->buffer[self->position];
- /* ++self->position; */
- i = (int) c;
- }
- if (i<0 && self->_streams) {
- _nextStream(self);
- i = streamGetChar(self);
- }
- return i;
-}
-
-static void streamReset (scannerdata *self)
-{
- self->buffer = (const char*) ppstream_all(self->_stream,&self->size,1);
- self->position = 0;
-}
-
-static void streamClose (scannerdata *self) {
- ppstream_done(self->_stream);
- self->buffer = NULL;
- self->_stream = NULL;
-}
-
-/* end of stream interface */
-
-static Token * _parseSpace (scannerdata *self)
-{
- return _parseToken (self,streamGetChar(self));
-}
-
-static Token * _parseString (scannerdata *self, int c)
-{
- define_buffer(found);
- int level = 1;
- while (1) {
- c = streamGetChar(self);
- if (c == '(') {
- level = level + 1 ;
- } else if (c == ')') {
- level = level - 1 ;
- if (level < 1) break;
- } else if (c == '\\') {
- int next = streamGetChar(self);
- if (next == '(' || next == ')' || next == '\\') {
- c = next;
- } else if (next == '\n' || next == '\r') {
- c = '\0';
- } else if (next == 'n') {
- c = '\n';
- } else if (next == 'r') {
- c = '\r';
- } else if (next == 't') {
- c = '\t';
- } else if (next == 'b') {
- c = '\b';
- } else if (next == 'f') {
- c = '\f';
- } else if (next >= '0' && next <= '7') {
- next = next - '0';
- int next2 = streamLookChar(self);
- if (next2 >= '0' && next2 <= '7') {
- next2 = streamGetChar(self);
- next2 = next2 - '0';
- int next3 = streamLookChar(self);
- if (next3 >= '0' && next3 <= '7') {
- next3 = streamGetChar(self);
- next3 = next3 - '0';
- c = (next*64+next2*8+next3);
- } else {
- c = (next*8+next2);
- }
- } else {
- c = next;
- }
- } else {
- c = next;
- }
- }
- check_overflow(found,foundindex);
- if (c>=0) {
- found[foundindex++] = c;
- }
- }
- Token *token = new_operand(pdf_string);
- token->value = foundindex;
- token->string = found;
- return token;
-}
-
-static Token * _parseNumber (scannerdata *self, int c)
-{
- double value = 0;
- pdf_token_type type = pdf_integer;
- int isfraction = 0;
- int isnegative = 0;
- int i = 0;
- if (c == '-') {
- isnegative = 1;
- c = streamGetChar(self);
- }
- if (c == '.') {
- type = pdf_real;
- isfraction = 1;
- } else {
- value = c - '0';
- }
- c = streamLookChar(self);
- if ((c>= '0'&& c<= '9') || c == '.') {
- c = streamGetChar(self);
- while (1) {
- if (c == '.') {
- type = pdf_real;
- isfraction = 1;
- } else {
- i = c - '0';
- if (isfraction>0) {
- value = value + (i/(pow(10.0,isfraction)));
- isfraction = isfraction + 1;
- } else {
- value = (value * 10) + i;
- }
- }
- c = streamLookChar(self);
- if (! ((c>= '0' && c<= '9') || c == '.'))
- break ;
- c = streamGetChar(self);
- }
- }
- if (isnegative) {
- value = -value;
- }
- Token *token = new_operand(type);
- token->value = value;
- return token;
-}
-
-static Token *_parseName (scannerdata *self, int c)
-{
- define_buffer(found);
- c = streamGetChar(self);
- while (1) {
- check_overflow(found,foundindex);
- found[foundindex++] = c;
- c = streamLookChar(self);
- if (c == ' ' || c == '\n' || c == '\r' || c == '\t' ||
- c == '/' || c == '[' || c == '(' || c == '<') break ;
- c = streamGetChar(self);
- }
- Token *token = new_operand(pdf_name);
- token->string = found;
- token->value = strlen(found);
- return token;
-}
-
-#define hexdigit(c) \
- (c>= '0' && c<= '9') ? (c - '0') : ((c>= 'A' && c<= 'F') ? (c - 'A' + 10) : (c - 'a' + 10))
-
-static Token *_parseHexstring (scannerdata *self, int c)
-{
- int isodd = 1;
- int hexval = 0;
- define_buffer(found);
- while (c != '>') {
- if ((c>= '0' && c<= '9') || (c>= 'A' && c<= 'F') || (c>= 'a' && c<= 'f')) {
- if (isodd==1) {
- int v = hexdigit(c);
- hexval = 16 * v;
- } else {
- hexval += hexdigit(c);
- check_overflow(found,foundindex);
- found[foundindex++] = hexval;
- }
- isodd = (isodd==1 ? 0 : 1);
- }
- c = streamGetChar(self);
- }
- Token *token = new_operand(pdf_string);
- token->value = foundindex;
- token->string = found;
- return token;
-}
-
-#define pdf_isspace(a) (a == '\0' || a == ' ' || a == '\n' || a == '\r' || a == '\t' || a == '\v')
-
-// -- this is rather horrible
-
-static Token *_parseInlineImage (scannerdata *self, int c)
-{
- define_buffer(found);
- if (c == ' ') { // first space can be ignored
- c = streamGetChar(self);
- }
- check_overflow(found, foundindex);
- found[foundindex++] = c;
- while (1) {
- c = streamLookChar(self);
- if (c == 'E' && (found[foundindex-1] == '\n' || found[foundindex-1] == '\r')) {
- c = streamGetChar(self);
- check_overflow(found, foundindex);
- found[foundindex++] = c;
- c = streamLookChar(self);
- if (c == 'I') {
- c = streamGetChar(self);
- check_overflow(found, foundindex);
- found[foundindex++] = c;
- c = streamLookChar(self);
- if (pdf_isspace(c)) {
- found[--foundindex] = '\0'; /* I */
- found[--foundindex] = '\0'; /* E */
- /* remove end-of-line before EI */
- if (found[foundindex-1] == '\n') {
- found[--foundindex] = '\0';
- }
- if (found[foundindex-1] == '\r') {
- found[--foundindex] = '\0';
- }
- break;
- } else {
- c = streamGetChar(self);
- check_overflow(found, foundindex);
- found[foundindex++] = c;
- }
- } else {
- c = streamGetChar(self);
- check_overflow(found, foundindex);
- found[foundindex++] = c;
- }
- } else {
- c = streamGetChar(self);
- check_overflow(found, foundindex);
- found[foundindex++] = c;
- }
- }
- Token *token = new_operand(pdf_string);
- token->value = foundindex;
- token->string = found;
- return token;
-}
-
-static Token *_parseOperator (scannerdata *self, int c)
-{
- define_buffer(found);
- while (1) {
- check_overflow(found, foundindex);
- found[foundindex++] = c;
- c = streamLookChar(self);
- if ((c<0) || (c == ' ' || c == '\n' || c == '\r' || c == '\t' ||
- c == '/' || c == '[' || c == '(' || c == '<'))
- break ;
- c = streamGetChar(self);
- }
- // print (found)
- if (strcmp(found, "ID") == 0) {
- self->_ininlineimage = 1;
- }
- if (strcmp(found,"false") == 0) {
- Token *token = new_operand(pdf_boolean);
- token->value = 0;
- free(found);
- return token;
- } else if (strcmp(found,"true") == 0) {
- Token *token = new_operand(pdf_boolean);
- token->value = 1.0;
- free(found);
- return token;
- } else {
- Token *token = new_operand(pdf_operator);
- token->string = found;
- return token;
- }
-}
-
-
-static Token * _parseComment (scannerdata *self, int c)
-{
- do {
- c = streamGetChar(self);
- } while (c != '\n' && c != '\r' && c != -1);
- return _parseToken(self,streamGetChar(self));
-}
-
-static Token *_parseLt (scannerdata *self, int c)
-{
- c = streamGetChar(self);
- if (c == '<') {
- return new_operand(pdf_startdict);
- } else {
- return _parseHexstring(self,c);
- }
-}
-
-static Token * _parseGt (scannerdata *self, int c)
-{
- c = streamGetChar(self);
- if (c== '>') {
- return new_operand(pdf_stopdict);
- } else {
- fprintf(stderr,"stray > in stream");
- return NULL;
- }
-}
-
-static Token *_parseError (int c)
-{
- fprintf(stderr, "stray %c [%d] in stream", c, c);
- return NULL;
-}
-
-static Token *_parseStartarray ()
-{
- return new_operand (pdf_startarray);
-}
-
-static Token *_parseStoparray ()
-{
- return new_operand (pdf_stoparray);
-}
-
-
-static Token *_parseToken (scannerdata *self, int c)
-{
- if (self->_ininlineimage==1) {
- self->_ininlineimage = 2;
- return _parseInlineImage(self,c);
- } else if (self->_ininlineimage==2) {
- self->_ininlineimage = 0;
- Token *token = new_operand(pdf_operator);
- token->string = strdup("EI");
- return token;
- }
- if (c<0)
- return NULL ;
- switch (c) {
- case '(':
- return _parseString(self,c);
- break;
- case ')':
- return _parseError(c);
- break;
- case '[':
- return _parseStartarray();
- break;
- case ']':
- return _parseStoparray();
- break;
- case '/':
- return _parseName(self,c);
- break;
- case '<':
- return _parseLt(self,c);
- break;
- case '>':
- return _parseGt(self,c);
- break;
- case '%':
- return _parseComment(self,c);
- break;
- case ' ':
- case '\r':
- case '\n':
- case '\t':
- return _parseSpace(self);
- break;
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- case '-':
- case '.':
- return _parseNumber(self,c);
- break;
- default:
- if (c<=127) {
- return _parseOperator(self,c);
- } else {
- return _parseError(c);
- }
- }
-}
-
-static int scanner_scan(lua_State * L)
-{
- Token *token;
- scannerdata *self;
- if (lua_gettop(L) != 3) {
- return 0;
- }
- luaL_checktype(L, 2, LUA_TTABLE);
- luaL_checktype(L, 3, LUA_TTABLE);
- self = scanner_push(L);
- memset(self,0,sizeof(scannerdata));
- self->_operandstack = (Token **)priv_xmalloc (MAXOPERANDS * sizeof (Token));
- memset (self->_operandstack,0,(MAXOPERANDS * sizeof (Token)));
- // 4 = self
- if (lua_type(L,1)== LUA_TTABLE) {
- udstruct *uin;
- void *ud;
- int i = 1;
- while (1) {
- lua_rawgeti(L,1,i);
- if (lua_type(L,-1)== LUA_TUSERDATA) {
- ud = luaL_checkudata(L, -1, PDFE_METATABLE_STREAM);
- if (ud != NULL) {
- uin = (udstruct *) ud;
- ObjectList *rover = self->_streams;
- ObjectList *item = (ObjectList *)priv_xmalloc (sizeof(ObjectList));
- item->stream = ((ppstream *) uin->d);
- item->next = NULL;
- if (!rover) {
- rover = item;
- self->_streams = rover;
- } else {
- while (rover->next)
- rover = rover->next;
- rover->next = item;
- }
- }
- } else {
- ObjectList *rover = self->_streams;
- self->_stream = rover->stream;
- self->_streams = rover->next;
- free(rover);
- lua_pop(L,1);
- break;
- }
- lua_pop(L,1);
- i++;
- }
- } else {
- udstruct *uin;
- void *ud;
- luaL_checktype(L, 1, LUA_TUSERDATA);
- ud = luaL_checkudata(L, 1, PDFE_METATABLE_STREAM);
- if (ud != NULL) {
- uin = (udstruct *) ud;
- self->_stream = ((ppstream *) uin->d);
- } else {
- ud = luaL_checkudata(L, 1, PDFE_METATABLE_ARRAY);
- if (ud != NULL) {
- uin = (udstruct *) ud;
- pparray * array = (pparray *) uin->d;
- int count = array->size;
- int i;
- for (i=0;i<count;i++) {
- ppobj *obj = pparray_at(array,i);
- if (obj->type == PPSTREAM) {
- ObjectList *rover = self->_streams;
- ObjectList *item = (ObjectList *)priv_xmalloc (sizeof(ObjectList));
- item->stream = obj->stream;
- item->next = NULL;
- if (!rover) {
- rover = item;
- self->_streams = rover;
- } else {
- while (rover->next)
- rover = rover->next;
- rover->next = item;
- }
- }
- }
- ObjectList *rover = self->_streams;
- self->_stream = rover->stream;
- self->_streams = rover->next;
- }
- }
- }
- streamReset(self);
- token = _parseToken(self,streamGetChar(self));
- while (token) {
- if (token->type == pdf_operator) {
- lua_pushstring(L, token->string);
- free_token(token);
- lua_rawget(L,2); // operator table
- if (lua_isfunction(L,-1)) {
- lua_pushvalue(L,4);
- lua_pushvalue(L,3);
- (void)lua_call(L,2,0);
- } else {
- lua_pop(L,1); // nil
- }
- clear_operand_stack(self,0);
- } else {
- push_operand(self, token);
- }
- if (!self->_stream) {
- break;
- }
- token = _parseToken(self,streamGetChar(self));
- }
- /* wrap up */
- if (self->_stream) {
- streamClose(self);
- }
- clear_operand_stack(self,0);
- free(self->_operandstack);
- return 0;
-}
-
-static int scanner_done(lua_State * L)
-{
- int c;
- scannerdata *self = scanner_check(L,1);
- while ((c=streamGetChar(self))>=0) ;
- return 0;
-}
-
-// here are the stack popping functions, and their helpers
-
-static void operandstack_backup (scannerdata *self) {
- int i = self->_nextoperand-1;
- int balance = 0;
- int backupstart = 0;
- int backupstop = self->_operandstack[i]->type;
- if (backupstop == pdf_stopdict) {
- backupstart = pdf_startdict;
- } else if (backupstop == pdf_stoparray) {
- backupstart = pdf_startarray;
- } else {
- return;
- }
- for (;i>=0;i--) {
- if (self->_operandstack[i]->type == backupstop) {
- balance++;
- } else if (self->_operandstack[i]->type == backupstart) {
- balance--;
- }
- if (balance==0) {
- break;
- }
- }
- self->_nextoperand = i+1;
-}
-
-static void push_array (lua_State *L, scannerdata *self)
-{
- int balance = 1; // nesting tracking
- int index = 1; // lua array index
- Token *token = self->_operandstack[self->_nextoperand++];
- lua_newtable(L);
- while (token) {
- if (token->type == pdf_stoparray)
- balance --;
- if (token->type == pdf_startarray)
- balance ++;
- if (!balance) {
- break;
- } else {
- push_token(L,self);
- lua_rawseti(L,-2, index++);
- }
- token = self->_operandstack[self->_nextoperand++];
- }
-}
-
-
-static void push_dict (lua_State *L, scannerdata *self)
-{
- int balance = 1; // nesting tracking
- int needskey = 1; // toggle between lua value and lua key
- Token *token = self->_operandstack[self->_nextoperand++];
- lua_newtable(L);
- while (token) {
- if (token->type == pdf_stopdict)
- balance --;
- if (token->type == pdf_startdict)
- balance ++;
- if (!balance) {
- break;
- } else if (needskey) {
- lua_pushlstring(L, token->string, token->value);
- needskey = 0;
- } else {
- push_token(L,self);
- needskey = 1;
- lua_rawset(L,-3);
- }
- token = self->_operandstack[self->_nextoperand++];
- }
-}
-
-const char *typenames[pdf_stopdict+1] = {
- "unknown", "integer", "real", "boolean", "name", "operator",
- "string", "array", "array", "dict", "dict"
-};
-
-static void push_token (lua_State *L, scannerdata *self)
-{
- Token *token = self->_operandstack[self->_nextoperand-1];
- lua_createtable(L,2,0);
- lua_pushstring (L, typenames[token->type]);
- lua_rawseti(L,-2,1);
- if (token->type == pdf_string || token->type == pdf_name) {
- lua_pushlstring(L, token->string, token->value);
- } else if (token->type == pdf_real || token->type == pdf_integer) {
- lua_pushnumber(L, token->value); /* integer or float */
- } else if (token->type == pdf_boolean) {
- lua_pushboolean(L, (int)token->value);
- } else if (token->type == pdf_startarray) {
- push_array(L, self);
- } else if (token->type == pdf_startdict) {
- push_dict(L, self);
- } else {
- lua_pushnil(L);
- }
- lua_rawseti(L,-2, 2);
-}
-
-static int scanner_popsingular (lua_State * L, int token_type) {
- int clear = 0; // how much of the operand stack needs deleting
- scannerdata *self = scanner_check(L,1);
- if (self->_nextoperand==0) {
- return 0;
- }
- clear = self->_nextoperand-1;
- Token *token = self->_operandstack[self->_nextoperand-1];
- if (token ==NULL || (token->type != token_type )) {
- return 0;
- }
- // the simple cases can be written out directly, but dicts and
- // arrays are better done via the recursive function
- if (token_type == pdf_stoparray || token_type == pdf_stopdict) {
- operandstack_backup(self);
- clear = self->_nextoperand-1;
- push_token(L, self);
- lua_rawgeti(L,-1,2);
- } else if (token_type == pdf_real || token_type == pdf_integer) {
- lua_pushnumber(L, token->value); /* integer or float */
- } else if (token_type == pdf_boolean) {
- lua_pushboolean(L,(int)token->value);
- } else if (token_type == pdf_name || token_type == pdf_string) {
- lua_pushlstring(L, token->string, token->value);
- } else {
- return 0;
- }
- clear_operand_stack(self,clear);
- return 1;
-}
-
-static int scanner_popanything (lua_State * L) {
- int clear = 0; // how much of the operand stack needs deleting
- scannerdata *self = scanner_check(L,1);
- if (self->_nextoperand==0) {
- return 0;
- }
- clear = self->_nextoperand-1;
- Token *token = self->_operandstack[self->_nextoperand-1];
- if (token ==NULL) {
- return 0;
- }
- int token_type = token->type;
- // the simple cases can be written out directly, but dicts and
- // arrays are better done via the recursive function
- if (token_type == pdf_stoparray || token_type == pdf_stopdict) {
- operandstack_backup(self);
- clear = self->_nextoperand-1;
- push_token(L, self);
- } else {
- push_token(L, self);
- }
- clear_operand_stack(self,clear);
- return 1;
-}
-
-
-static int scanner_popnumber(lua_State * L)
-{
- if(scanner_popsingular(L,pdf_real))
- return 1;
- if (scanner_popsingular(L,pdf_integer))
- return 1;
- lua_pushnil(L);
- return 1;
-}
-
-static int scanner_popboolean(lua_State * L)
-{
- if(scanner_popsingular(L,pdf_boolean))
- return 1;
- lua_pushnil(L);
- return 1;
-}
-
-static int scanner_popstring(lua_State * L)
-{
- if (scanner_popsingular(L,pdf_string))
- return 1;
- lua_pushnil(L);
- return 1;
-}
-
-static int scanner_popname(lua_State * L)
-{
- if (scanner_popsingular(L,pdf_name))
- return 1;
- lua_pushnil(L);
- return 1;
-}
-
-static int scanner_poparray(lua_State * L)
-{
- if (scanner_popsingular(L,pdf_stoparray))
- return 1;
- lua_pushnil(L);
- return 1;
-}
-
-static int scanner_popdictionary(lua_State * L)
-{
- if (scanner_popsingular(L,pdf_stopdict))
- return 1;
- lua_pushnil(L);
- return 1;
-}
-
-static int scanner_popany(lua_State * L)
-{
- if (scanner_popanything(L))
- return 1;
- lua_pushnil(L);
- return 1;
-}
-
-static const luaL_Reg scannerlib_meta[] = {
- {0, 0}
-};
-
-static const struct luaL_Reg scannerlib_m[] = {
- {"done", scanner_done},
- {"popNumber", scanner_popnumber},
- {"popName", scanner_popname},
- {"popString", scanner_popstring},
- {"popArray", scanner_poparray},
- {"popDict", scanner_popdictionary},
- {"popBool", scanner_popboolean},
- {"pop", scanner_popany},
- {NULL, NULL} /* sentinel */
-};
-
-static const luaL_Reg scannerlib[] = {
- {"scan", scanner_scan},
- {NULL, NULL}
-};
-
-LUALIB_API int luaopen_pdfscanner(lua_State * L)
-{
- luaL_newmetatable(L, SCANNER);
- luaL_openlib(L, 0, scannerlib_meta, 0);
- lua_pushvalue(L, -1);
- lua_setfield(L, -2, "__index");
- luaL_openlib(L, NULL, scannerlib_m, 0);
- luaL_openlib(L, "pdfscanner", scannerlib, 0);
- return 1;
-}
-
diff --git a/Build/source/texk/web2c/luatexdir/lua/luatex-api.h b/Build/source/texk/web2c/luatexdir/lua/luatex-api.h
index 9525cecd26d..bebf088af99 100644
--- a/Build/source/texk/web2c/luatexdir/lua/luatex-api.h
+++ b/Build/source/texk/web2c/luatexdir/lua/luatex-api.h
@@ -50,9 +50,9 @@ extern void fix_o_mode(void);
# include "lualib.h"
#ifdef LuajitTeX
# include "luajit.h"
-#endif
+#endif
-/* Names */
+/* Names */
#ifndef LUATEX_HARFBUZZ_ENABLED
#ifdef LuajitTeX
# define MyName "LuajitTeX"
@@ -1139,6 +1139,7 @@ make_lua_key(stretch_order);\
make_lua_key(string);\
make_lua_key(style);\
make_lua_key(sub);\
+make_lua_key(subfont);\
make_lua_key(sub_box);\
make_lua_key(sub_mark);\
make_lua_key(sub_mlist);\
@@ -1832,6 +1833,7 @@ init_lua_key(stretch_order);\
init_lua_key(string);\
init_lua_key(style);\
init_lua_key(sub);\
+init_lua_key(subfont);\
init_lua_key(sub_box);\
init_lua_key(sub_mark);\
init_lua_key(sub_mlist);\
@@ -2600,6 +2602,7 @@ use_lua_key(stretch_order);
use_lua_key(string);
use_lua_key(style);
use_lua_key(sub);
+use_lua_key(subfont);
use_lua_key(sub_box);
use_lua_key(sub_mark);
use_lua_key(sub_mlist);
diff --git a/Build/source/texk/web2c/luatexdir/luapplib/ppconf.h b/Build/source/texk/web2c/luatexdir/luapplib/ppconf.h
index a0f9c807d79..be0683c8551 100644
--- a/Build/source/texk/web2c/luatexdir/luapplib/ppconf.h
+++ b/Build/source/texk/web2c/luatexdir/luapplib/ppconf.h
@@ -9,6 +9,9 @@
# define ARM_COMPLIANT 0
#endif
+/* we impose this */
+/*#define ARM_COMPLIANT 1*/
+
/*
Aux flags:
PPDLL -- indicates a part of a shared library
diff --git a/Build/source/texk/web2c/luatexdir/luapplib/ppload.c.orig b/Build/source/texk/web2c/luatexdir/luapplib/ppload.c.orig
deleted file mode 100644
index fda726656ab..00000000000
--- a/Build/source/texk/web2c/luatexdir/luapplib/ppload.c.orig
+++ /dev/null
@@ -1,2555 +0,0 @@
-
-#include <utilbasexx.h>
-
-#include "pplib.h"
-
-const char * ppobj_kind[] = { "none", "null", "bool", "integer", "number", "name", "string", "array", "dict", "stream", "ref" };
-
-#define ignored_char(c) (c == 0x20 || c == 0x0A || c == 0x0D || c == 0x09 || c == 0x00)
-#define newline_char(c) (c == 0x0A || c == 0x0D)
-#define IGNORED_CHAR_CASE 0x20: case 0x0A: case 0x0D: case 0x09: case 0x00
-#define NEWLINE_CHAR_CASE 0x0A: case 0x0D
-#define DIGIT_CHAR_CASE '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9'
-#define OCTAL_CHAR_CASE '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7'
-
-#define MAX_INT_DIGITS 32
-
-#define PP_LENGTH_UNKNOWN ((size_t)-1)
-
-static const char * ppref_str (ppuint refnumber, ppuint refversion)
-{
- static char buffer[MAX_INT_DIGITS + 1 + MAX_INT_DIGITS + 1 + 1 + 1];
-#if defined(MSVC64)|| defined(MINGW64)
- sprintf(buffer, PPUINTF " " PPUINTF " R", refnumber, refversion);
-#else
- sprintf(buffer, PPUINTF " " PPUINTF " R", (unsigned long)(refnumber), (unsigned long)(refversion));
-#endif
- return buffer;
-}
-
-/* name */
-
-// pdf name delimiters: 0..32, ()<>[]{}/%
-// # treated specially
-// .+- are valid part of name; keep in mind names such as -| | |- .notdef ABCDEF+Font etc.
-const char ppname_byte_lookup[] = {
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 1, 1, '#', 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
-};
-
-#define PPNAME_INIT (8+1)
-
-#define ppname_flush(O, ghost, siz, flgs) \
- (iof_put(O, '\0'), \
- ghost = (_ppname *)ppheap_flush(O, &siz), \
- ghost->flags = flgs, \
- ghost->size = siz - sizeof(_ppname) - 1, \
- (ppname)(ghost + 1))
-
-#define ppname_flush_with_ego(O, ghost, siz, flgs) \
- (iof_put(O, '\0'), \
- iof_ensure(O, sizeof(ppname *)), \
- O->pos += sizeof(ppname *), \
- ghost = (_ppname *)ppheap_flush(O, &siz), \
- ghost->flags = flgs, \
- ghost->size = siz - sizeof(_ppname) - 1 - sizeof(ppname *), \
- (ppname)(ghost + 1))
-
-#define ppname_set_alter_ego(name, ghost, ego) (*((ppname *)(name + (ghost)->size + 1)) = ego)
-#define ppname_get_alter_ego(name) (*((ppname *)(name + ppname_size(name) + 1)))
-
-static ppname ppscan_name (iof *I, ppheap **pheap)
-{
- int c, decode;
- iof *O;
- _ppname *ghost1, *ghost2;
- ppname encoded, decoded;
- size_t size;
- const char *p, *e;
- uint8_t v1, v2;
- O = ppheap_buffer(pheap, sizeof(_ppname), PPNAME_INIT);
- for (decode = 0, c = iof_char(I); c >= 0 && ppname_byte_lookup[c]; c = iof_next(I))
- {
- if (c == '#')
- decode = 1;
- iof_put(O, c);
- }
- if (!decode)
- return ppname_flush(O, ghost1, size, 0);
- encoded = ppname_flush_with_ego(O, ghost1, size, 0|PPNAME_ENCODED);
- O = ppheap_buffer(pheap, sizeof(_ppname), PPNAME_INIT);
- for (p = encoded, e = encoded + ghost1->size; p < e; ++p)
- {
- if (*p == '#' && p + 2 < e ){
- v1 = base16_value(p[1]);
- v2 = base16_value(p[2]);
- iof_put(O, ((v1<<4)+v2));
- }else
- iof_put(O, *p);
- }
- decoded = ppname_flush_with_ego(O, ghost2, size, 0|PPNAME_DECODED);
- ppname_set_alter_ego(encoded, ghost1, decoded);
- ppname_set_alter_ego(decoded, ghost2, encoded);
- return encoded;
-}
-
-static ppname ppscan_exec (iof *I, ppheap **pheap, int first)
-{
- int c, decode;
- iof *O;
- _ppname *ghost1, *ghost2;
- ppname encoded, decoded;
- size_t size;
- const char *p, *e;
- uint8_t v1, v2;
-
- O = ppheap_buffer(pheap, sizeof(_ppname), PPNAME_INIT);
- iof_put(O, first);
- for (decode = 0, c = iof_char(I); c >= 0 && ppname_byte_lookup[c]; c = iof_next(I))
- {
- if (c == '#')
- decode = 1;
- iof_put(O, c);
- }
- if (!decode)
- return ppname_flush(O, ghost1, size, PPNAME_EXEC);
- encoded = ppname_flush_with_ego(O, ghost1, size, PPNAME_EXEC|PPNAME_ENCODED);
- O = ppheap_buffer(pheap, sizeof(_ppname), PPNAME_INIT);
- for (p = encoded, e = encoded + ghost1->size; p < e; ++p)
- {
- if (*p == '#' && p + 2 < e ){
- v1 = base16_value(p[1]);
- v2 = base16_value(p[2]);
- iof_put(O, ((v1<<4)+v2));
- }else
- iof_put(O, *p);
- }
- decoded = ppname_flush_with_ego(O, ghost2, size, PPNAME_EXEC|PPNAME_DECODED);
- ppname_set_alter_ego(encoded, ghost1, decoded);
- ppname_set_alter_ego(decoded, ghost2, encoded);
- return encoded;
-}
-
-static ppname ppexec_internal (const void *data, size_t size, ppheap **pheap)
-{ // used only for artificial 'EI' operator name
- iof *O;
- _ppname *ghost1;
-
- O = ppheap_buffer(pheap, sizeof(_ppname), size);
- iof_write(O, data, size);
- return ppname_flush(O, ghost1, size, PPNAME_EXEC);
-}
-
-ppname ppname_decoded (ppname name)
-{
- const _ppname *ghost;
- ghost = _ppname_ghost(name);
- return (ghost->flags & PPNAME_ENCODED) ? ppname_get_alter_ego(name) : name;
-}
-
-ppname ppname_encoded (ppname name)
-{
- const _ppname *ghost;
- ghost = _ppname_ghost(name);
- return (ghost->flags & PPNAME_DECODED) ? ppname_get_alter_ego(name) : name;
-}
-
-/* string */
-
-#define PPSTRING_INIT (16+1)
-
-#define ppstring_flush(O, ghost, siz, flgs) \
- (iof_put(O, '\0'), \
- ghost = (_ppstring *)ppheap_flush(O, &siz), \
- ghost->flags = flgs, \
- ghost->size = siz - sizeof(_ppstring) - 1, \
- (ppstring)(ghost + 1))
-
-#define ppstring_flush_with_ego(O, ghost, siz, flgs) \
- (iof_put(O, '\0'), \
- iof_ensure(O, sizeof(ppstring *)), \
- O->pos += sizeof(ppstring *), \
- ghost = (_ppstring *)ppheap_flush(O, &siz), \
- ghost->flags = flgs, \
- ghost->size = siz - sizeof(_ppstring) - 1 - sizeof(ppstring *), \
- (ppstring)(ghost + 1))
-
-#define ppstring_utf16be_bom(decoded) (decoded[0] == ((char)0xFE) && decoded[1] == ((char)0xFF) )
-#define ppstring_utf16le_bom(decoded) (decoded[0] == ((char)0xFF) && decoded[1] == ((char)0xFE))
-
-#define ppstring_check_bom(decoded, ghost) ((void)\
- (ghost->size >= 2 ? (ppstring_utf16be_bom(decoded) ? (ghost->flags |= PPSTRING_UTF16BE) : \
- (ppstring_utf16le_bom(decoded) ? (ghost->flags |= PPSTRING_UTF16LE) : 0)) : 0))
-
-#define ppstring_check_bom2(decoded, ghost1, ghost2) ((void)\
- (ghost2->size >= 2 ? (ppstring_utf16be_bom(decoded) ? ((ghost1->flags |= PPSTRING_UTF16BE), (ghost2->flags |= PPSTRING_UTF16BE)) : \
- (ppstring_utf16le_bom(decoded) ? ((ghost1->flags |= PPSTRING_UTF16LE), (ghost2->flags |= PPSTRING_UTF16LE)) : 0)) : 0))
-
-#define ppstring_set_alter_ego(string, ghost, ego) (*((ppstring *)(string + (ghost)->size + 1)) = ego)
-#define ppstring_get_alter_ego(string) (*((ppstring *)(string + ppstring_size(string) + 1)))
-
-static ppstring ppscan_string (iof *I, ppheap **pheap)
-{
- int c, decode, balance;
- iof *O;
- _ppstring *ghost1, *ghost2;
- uint8_t *p, *e;
- ppstring encoded, decoded;
- size_t size;
- O = ppheap_buffer(pheap, sizeof(_ppstring), PPSTRING_INIT);
- for (decode = 0, balance = 0, c = iof_char(I); c >= 0; )
- {
- switch (c)
- {
- case '\\':
- decode = 1; // unescaping later
- iof_put(O, '\\');
- if ((c = iof_next(I)) >= 0)
- {
- iof_put(O, c);
- c = iof_next(I);
- }
- break;
- case '(': // may be unescaped if balanced
- ++balance;
- iof_put(O, '(');
- c = iof_next(I);
- break;
- case ')':
- if (balance == 0)
- {
- c = IOFEOF;
- ++I->pos;
- break;
- }
- --balance;
- iof_put(O, ')');
- c = iof_next(I);
- break;
- default:
- iof_put(O, c);
- c = iof_next(I);
- }
- }
- if (!decode)
- {
- encoded = ppstring_flush(O, ghost1, size, 0);
- ppstring_check_bom(encoded, ghost1); // any bytes can be there
- return encoded;
- }
- encoded = ppstring_flush_with_ego(O, ghost1, size, 0|PPSTRING_ENCODED);
- O = ppheap_buffer(pheap, sizeof(_ppstring), PPSTRING_INIT);
- for (p = (uint8_t *)encoded, e = (uint8_t *)encoded + ghost1->size; p < e; ++p)
- {
- if (*p == '\\')
- {
- if (++p >= e)
- break;
- switch (*p)
- {
- case OCTAL_CHAR_CASE:
- c = *p - '0';
- if (++p < e && *p >= '0' && *p <= '7')
- {
- c = (c << 3) + *p - '0';
- if (++p < e && *p >= '0' && *p <= '7')
- c = (c << 3) + *p - '0';
- }
- iof_put(O, c);
- break;
- case 'n':
- iof_put(O, '\n');
- break;
- case 'r':
- iof_put(O, '\r');
- break;
- case 't':
- iof_put(O, '\t');
- break;
- case 'b':
- iof_put(O, '\b');
- break;
- case 'f':
- iof_put(O, '\f');
- break;
- case NEWLINE_CHAR_CASE: // not a part of the string, ignore (pdf spec page 55)
- break;
- case '(': case ')': case '\\':
- default: // for enything else backslash is ignored (pdf spec page 54)
- iof_put(O, *p);
- break;
- }
- }
- else
- iof_put(O, *p);
- }
- decoded = ppstring_flush_with_ego(O, ghost2, size, 0|PPSTRING_DECODED);
- ppstring_check_bom2(decoded, ghost1, ghost2);
- ppstring_set_alter_ego(encoded, ghost1, decoded);
- ppstring_set_alter_ego(decoded, ghost2, encoded);
- return encoded;
-}
-
-/* Hex string may contain white characters. If odd number of digits, the last assumed to be '0' */
-
-static ppstring ppscan_base16 (iof *I, ppheap **pheap)
-{
- int c, v1, v2;
- iof *O;
- _ppstring *ghost1, *ghost2;
- size_t size;
- ppstring encoded, decoded;
- uint8_t *p, *e;
-
- O = ppheap_buffer(pheap, sizeof(_ppstring), PPSTRING_INIT);
- for (c = iof_char(I); c >= 0 && (base16_digit(c) || ignored_char(c)); c = iof_next(I))
- iof_put(O, c);
- if (c == '>')
- ++I->pos;
- encoded = ppstring_flush_with_ego(O, ghost1, size, PPSTRING_BASE16|PPSTRING_ENCODED);
- O = ppheap_buffer(pheap, sizeof(_ppstring), (ghost1->size >> 1) + 1);
- for (p = (uint8_t *)encoded, e = (uint8_t *)encoded + ghost1->size; p < e; ++p)
- {
- if ((v1 = base16_value(*p)) < 0) // ignored
- continue;
- for (v2 = 0, ++p; p < e && (v2 = base16_value(*p)) < 0; ++p);
- iof_put(O, (v1<<4)|v2);
- }
- decoded = ppstring_flush_with_ego(O, ghost2, size, 0|PPSTRING_DECODED);
- ppstring_check_bom2(decoded, ghost1, ghost2);
- ppstring_set_alter_ego(encoded, ghost1, decoded);
- ppstring_set_alter_ego(decoded, ghost2, encoded);
- return encoded;
-}
-
-/* internal use only; binary string */
-
-static ppstring ppstring_buffer (iof *O, ppheap **pheap)
-{
- _ppstring *ghost1, *ghost2;
- ppstring encoded, decoded;
- uint8_t *p, *e;
- size_t size;
-
- decoded = ppstring_flush_with_ego(O, ghost2, size, 0|PPSTRING_DECODED);
- O = ppheap_buffer(pheap, sizeof(_ppstring), (ghost2->size << 1) + 1);
- for (p = (uint8_t *)decoded, e = (uint8_t *)decoded + ghost2->size; p < e; ++p)
- iof_set2(O, base16_uc_alphabet[(*p)>>4], base16_uc_alphabet[(*p)&15]);
- encoded = ppstring_flush_with_ego(O, ghost1, size, PPSTRING_BASE16|PPSTRING_ENCODED);
- ppstring_set_alter_ego(encoded, ghost1, decoded);
- ppstring_set_alter_ego(decoded, ghost2, encoded);
- return encoded;
-}
-
-ppstring ppstring_internal (const void *data, size_t size, ppheap **pheap)
-{ // so far used only for crypt key
- iof *O;
-
- O = ppheap_buffer(pheap, sizeof(_ppstring), size);
- iof_write(O, data, size);
- return ppstring_buffer(O, pheap);
-}
-
-/* PDF spec says nothing about base85 strings, but streams might be (afair no leading '<~' but present trailing '~>') */
-
-static ppstring ppscan_base85 (iof *I, ppheap **pheap)
-{ // bawse85 alphabet is 33.117, adobe also hires 'z' and 'y' for compression
- int c;
- iof *O, B;
- _ppstring *ghost1, *ghost2;
- size_t size;
- ppstring encoded, decoded;
- O = ppheap_buffer(pheap, sizeof(_ppstring), PPSTRING_INIT);
- for (c = iof_char(I); (c >= '!' && c <= 'u') || c == 'z' || c == 'y'; c = iof_next(I))
- iof_put(O, c);
- if (c == '~')
- if ((c = iof_next(I)) == '>')
- ++I->pos;
- encoded = ppstring_flush_with_ego(O, ghost1, size, PPSTRING_BASE85|PPSTRING_ENCODED);
- iof_string_reader(&B, encoded, ghost1->size);
- O = ppheap_buffer(pheap, sizeof(_ppstring), (ghost1->size * 5 / 4) + 1);
- base85_decode(&B, O);
- decoded = ppstring_flush_with_ego(O, ghost2, size, 0|PPSTRING_DECODED);
- ppstring_check_bom2(decoded, ghost1, ghost2);
- ppstring_set_alter_ego(encoded, ghost1, decoded);
- ppstring_set_alter_ego(decoded, ghost2, encoded);
- return encoded;
-}
-
-/*
-Encrypted strings. In case of encrypted strings, we first need to decode the string (saving original form hardly makes sense),
-then decrypt the string, and encode it again.
-*/
-
-const char ppstring_byte_escape[] = { /* -1 escaped with octal, >0 escaped with \\, 0 left intact*/
- -1,-1,-1,-1,-1,-1,-1,-1,'b','t','n',-1,'f','r',-1,-1,
- -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
- 0, 0, 0, 0, 0, 0, 0, 0,'(',')', 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'\\', 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
- -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
- -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
- -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
- -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
- -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
- -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
- -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
-};
-
-
-static ppstring ppscan_crypt_string (iof *I, ppcrypt *crypt, ppheap **pheap)
-{
- int c, b, balance, encode;
- iof *O;
- _ppstring *ghost1, *ghost2;
- ppstring encoded, decoded;
- uint8_t *p, *e;
- size_t size;
-
- O = ppheap_buffer(pheap, sizeof(_ppstring), PPSTRING_INIT);
- for (balance = 0, encode = 0, c = iof_char(I); c >= 0; )
- {
- switch (c)
- {
- case '\\':
- if ((c = iof_next(I)) < 0)
- break;
- encode = 1;
- switch (c)
- {
- case OCTAL_CHAR_CASE:
- b = c - '0';
- if ((c = iof_next(I)) >= 0 && c >= '0' && c <= '7')
- {
- b = (b << 3) + c - '0';
- if ((c = iof_next(I)) >= 0 && c >= '0' && c <= '7')
- {
- b = (b << 3) + c - '0';
- c = iof_next(I);
- }
- }
- iof_put(O, b);
- // c is set to the next char
- break;
- case 'n':
- iof_put(O, '\n');
- c = iof_next(I);
- break;
- case 'r':
- iof_put(O, '\r');
- c = iof_next(I);
- break;
- case 't':
- iof_put(O, '\t');
- c = iof_next(I);
- break;
- case 'b':
- iof_put(O, '\b');
- c = iof_next(I);
- break;
- case 'f':
- iof_put(O, '\f');
- c = iof_next(I);
- break;
- case NEWLINE_CHAR_CASE: // not a part of the string, ignore (pdf spec page 55)
- c = iof_next(I);
- break;
- case '(': case ')': case '\\':
- default: // for enything else backslash is ignored (pdf spec page 54)
- iof_put(O, c);
- c = iof_next(I);
- break;
- }
- break;
- case '(':
- ++balance;
- encode = 1;
- iof_put(O, '(');
- c = iof_next(I);
- break;
- case ')':
- if (balance == 0)
- {
- c = IOFEOF;
- ++I->pos;
- }
- else
- {
- --balance;
- //encode = 1;
- iof_put(O, ')');
- c = iof_next(I);
- }
- break;
- default:
- if (ppstring_byte_escape[c] != 0)
- encode = 1;
- iof_put(O, c);
- c = iof_next(I);
- }
- }
- /* decrypt the buffer in place, update size */
- if (ppstring_decrypt(crypt, O->buf, iof_size(O), O->buf, &size))
- O->pos = O->buf + size;
- /* make encoded counterpart */
- if (!encode)
- {
- decoded = ppstring_flush(O, ghost2, size, 0);
- ppstring_check_bom(decoded, ghost2);
- return decoded;
- }
- decoded = ppstring_flush_with_ego(O, ghost2, size, PPSTRING_DECODED);
- O = ppheap_buffer(pheap, sizeof(_ppstring), ghost2->size);
- for (p = (uint8_t *)decoded, e = (uint8_t *)decoded + ghost2->size; p < e; ++p)
- {
- switch ((b = ppstring_byte_escape[*p]))
- {
- case 0:
- iof_put(O, *p);
- break;
- case -1:
- iof_put4(O, '\\', (c >> 6) + '0', ((c >> 3) & 7) + '0', (c & 7) + '0');
- break;
- default:
- iof_put2(O, '\\', b);
- break;
- }
- }
- encoded = ppstring_flush_with_ego(O, ghost1, size, PPSTRING_ENCODED);
- ppstring_check_bom2(decoded, ghost1, ghost2);
- ppstring_set_alter_ego(encoded, ghost1, decoded);
- ppstring_set_alter_ego(decoded, ghost2, encoded);
- return encoded;
-}
-
-
-static ppstring ppscan_crypt_base16 (iof *I, ppcrypt *crypt, ppheap **pheap)
-{
- int c, v1, v2;
- iof *O;
- _ppstring *ghost1, *ghost2;
- ppstring encoded, decoded;
- uint8_t *p, *e;
- size_t size;
-
- O = ppheap_buffer(pheap, sizeof(_ppstring), PPSTRING_INIT);
- // base16_decode(I, O); // no info about the last char..
- for (c = iof_char(I); c != '>' && c >= 0; )
- {
- if ((v1 = base16_value(c)) < 0)
- {
- if (ignored_char(c))
- {
- c = iof_next(I);
- continue;
- }
- break;
- }
- do {
- c = iof_next(I);
- if ((v2 = base16_value(c)) >= 0)
- {
- c = iof_next(I);
- break;
- }
- if (!ignored_char(c)) // c == '>' || c < 0 or some crap
- {
- v2 = 0;
- break;
- }
- } while (1);
- iof_put(O, (v1 << 4)|v2);
- }
- if (c == '>')
- ++I->pos;
- /* decrypt the buffer in place, update size */
- if (ppstring_decrypt(crypt, O->buf, iof_size(O), O->buf, &size))
- O->pos = O->buf + size;
- decoded = ppstring_flush_with_ego(O, ghost2, size, PPSTRING_DECODED);
- /* recreate an encoded form */
- O = ppheap_buffer(pheap, sizeof(_ppstring), (ghost2->size << 1) + 1);
- for (p = (uint8_t *)decoded, e = (uint8_t *)decoded + ghost2->size; p < e; ++p)
- iof_set2(O, base16_uc_alphabet[(*p)>>4], base16_uc_alphabet[(*p)&15]);
- encoded = ppstring_flush_with_ego(O, ghost1, size, PPSTRING_BASE16|PPSTRING_ENCODED);
- ppstring_check_bom2(decoded, ghost1, ghost2);
- ppstring_set_alter_ego(encoded, ghost1, decoded);
- ppstring_set_alter_ego(decoded, ghost2, encoded);
- return encoded;
-}
-
-/* ppstring alter ego switcher */
-
-ppstring ppstring_decoded (ppstring string)
-{
- const _ppstring *ghost;
- ghost = _ppstring_ghost(string);
- return (ghost->flags & PPSTRING_ENCODED) ? ppstring_get_alter_ego(string) : string;
-}
-
-ppstring ppstring_encoded (ppstring string)
-{
- const _ppstring *ghost;
- ghost = _ppstring_ghost(string);
- return (ghost->flags & PPSTRING_DECODED) ? ppstring_get_alter_ego(string) : string;
-}
-
-/* scanner stack */
-
-#define PPSTACK_BUFFER 512
-
-static void ppstack_init (ppstack *stack, ppheap **pheap)
-{
- stack->buf = stack->pos = (ppobj *)pp_malloc(PPSTACK_BUFFER * sizeof(ppobj));
- stack->size = 0;
- stack->space = PPSTACK_BUFFER;
- stack->pheap = pheap;
-}
-
-#define ppstack_free_buffer(stack) (pp_free((stack)->buf))
-
-static void ppstack_resize (ppstack *stack)
-{
- ppobj *newbuffer;
- stack->space <<= 1;
- newbuffer = (ppobj *)pp_malloc(stack->space * sizeof(ppobj));
- memcpy(newbuffer, stack->buf, stack->size * sizeof(ppobj));
- ppstack_free_buffer(stack);
- stack->buf = newbuffer;
- stack->pos = newbuffer + stack->size;
-}
-
-#define ppstack_push(stack) ((void)((stack)->size < (stack)->space || (ppstack_resize(stack), 0)), ++(stack)->size, (stack)->pos++)
-#define ppstack_pop(stack, n) ((stack)->size -= (n), (stack)->pos -= (n))
-#define ppstack_at(stack, i) ((stack)->buf + i)
-#define ppstack_clear(stack) ((stack)->pos = (stack)->buf, (stack)->size = 0)
-
-/* scanner commons */
-
-#define ppscan_uint(I, u) iof_get_uintlw(I, u)
-#define ppread_uint(s, u) string_to_uintlw((const char *)(s), u)
-
-static ppobj * ppscan_numobj (iof *I, ppobj *obj, int negative)
-{
- ppint integer;
- ppnum number;
- int exponent;
- int c;
- c = iof_char(I);
- iof_scan_integer(I, c, integer);
- switch(c)
- {
- case '.':
- {
- number = (ppnum)integer;
- c = iof_next(I);
- iof_scan_fraction(I, c, number, exponent);
- double_negative_exp10(number, exponent);
- obj->type = PPNUM, obj->number = negative ? -number : number;
- break;
- }
- default:
- obj->type = PPINT, obj->integer = negative ? -integer : integer;
- break;
- }
- return obj;
-}
-
-static ppobj * ppscan_numobj_frac (iof *I, ppobj *obj, int negative)
-{
- ppnum number;
- int c, exponent;
-
- number = 0.0;
- c = iof_next(I);
- iof_scan_fraction(I, c, number, exponent);
- double_negative_exp10(number, exponent);
- obj->type = PPNUM, obj->number = negative ? -number : number;
- return obj;
-}
-
-static int ppscan_find (iof *I)
-{ // skips whitechars and comments
- int c;
- for (c = iof_char(I); ; c = iof_next(I))
- {
- switch (c)
- {
- case IGNORED_CHAR_CASE:
- break;
- case '%': {
- do {
- if ((c = iof_next(I)) < 0)
- return c;
- } while (!newline_char(c));
- break;
- }
- default:
- return c;
- }
- }
- return c; // never reached
-}
-
-static int ppscan_keyword (iof *I, const char *keyword, size_t size)
-{
- size_t i;
- int c;
- if (iof_left(I) >= size)
- {
- if (memcmp(I->pos, keyword, size) != 0)
- return 0;
- I->pos += size;
- return 1;
- }
- // sticky case, we can't go back
- for (i = 0, c = iof_char(I); i < size; ++i, ++keyword, c = iof_next(I))
- if (i != c)
- return 0;
- return 1;
-}
-
-#define ppscan_key(I, literal) ppscan_keyword(I, "" literal, sizeof(literal) - 1)
-
-/* objects parser */
-
-static ppref * ppref_unresolved (ppheap **pheap, ppuint refnumber, ppuint refversion)
-{
- ppref *ref = (ppref *)ppheap_take(pheap, sizeof(ppref));
- memset(ref, 0, sizeof(ppref));
- ref->object.type = PPNONE;
- ref->number = refnumber;
- ref->version = refversion;
- return ref;
-}
-
-#define PPMARK PPNONE
-
-static ppobj * ppscan_obj (iof *I, ppdoc *pdf, ppxref *xref)
-{
- int c;
- ppobj *obj;
- size_t mark, size;
- ppuint refnumber, refversion;
- ppref *ref;
- ppstack *stack;
- ppcrypt *crypt;
-
- stack = &pdf->stack;
- c = iof_char(I);
- switch (c)
- {
- case DIGIT_CHAR_CASE:
- return ppscan_numobj(I, ppstack_push(stack), 0);
- case '.':
- return ppscan_numobj_frac(I, ppstack_push(stack), 0);
- case '+':
- ++I->pos;
- return ppscan_numobj(I, ppstack_push(stack), 0);
- case '-':
- ++I->pos;
- return ppscan_numobj(I, ppstack_push(stack), 1);
- case '/':
- ++I->pos;
- obj = ppstack_push(stack);
- obj->type = PPNAME;
- obj->name = ppscan_name(I, &pdf->heap);
- return obj;
- case '(':
- ++I->pos;
- obj = ppstack_push(stack);
- obj->type = PPSTRING;
- if (ppcrypt_ref(pdf, crypt))
- obj->string = ppscan_crypt_string(I, crypt, &pdf->heap);
- else
- obj->string = ppscan_string(I, &pdf->heap);
- return obj;
- case '[':
- mark = stack->size;
- obj = ppstack_push(stack);
- obj->type = PPMARK; // ppscan_obj() checks types backward for 'R', so set the type immediatelly (reserved for PPARRAY)
- obj->any = NULL;
- ++I->pos;
- for (c = ppscan_find(I); c != ']'; c = ppscan_find(I))
- {
- if (ppscan_obj(I, pdf, xref) == NULL)
- { // callers assume that NULL returns means nothing pushed
- size = stack->size - mark; // pop items AND the obj reserved for array
- ppstack_pop(stack, size);
- return NULL;
- }
- }
- ++I->pos;
- size = stack->size - mark - 1;
- obj = ppstack_at(stack, mark); // stack might have been realocated
- obj->type = PPARRAY;
- obj->array = pparray_create(ppstack_at(stack, mark + 1), size, &pdf->heap);
- ppstack_pop(stack, size); // pop array items, leave the array on top
- return obj;
- case '<':
- if ((c = iof_next(I)) == '<')
- {
- mark = stack->size;
- obj = ppstack_push(stack);
- obj->type = PPMARK;
- obj->any = NULL;
- ++I->pos;
- for (c = ppscan_find(I); c != '>'; c = ppscan_find(I))
- {
- if (ppscan_obj(I, pdf, xref) == NULL)
- {
- size = stack->size - mark;
- ppstack_pop(stack, size);
- return NULL;
- }
- }
- if (iof_next(I) == '>')
- ++I->pos;
- size = stack->size - mark - 1;
- obj = ppstack_at(stack, mark);
- obj->type = PPDICT;
- obj->dict = ppdict_create(ppstack_at(stack, mark + 1), size, &pdf->heap);
- ppstack_pop(stack, size);
- return obj;
- }
- obj = ppstack_push(stack);
- obj->type = PPSTRING;
- if (ppcrypt_ref(pdf, crypt))
- obj->string = ppscan_crypt_base16(I, crypt, &pdf->heap);
- else
- obj->string = ppscan_base16(I, &pdf->heap);
- return obj;
- case 'R':
- if (stack->size >= 2 && stack->pos[-1].type == PPINT && stack->pos[-2].type == PPINT)
- {
- ++I->pos;
- obj = &stack->pos[-2];
- refnumber = (ppuint)obj->integer;
- ppstack_pop(stack, 1); // pop version number, retype obj to a reference
- if (xref == NULL || (ref = ppxref_find(xref, refnumber)) == NULL)
- { /* pdf spec page 64: unresolvable reference is not an error, should just be treated as a reference to null.
- we also need this to read trailer, where refs can't be resolved yet */
- refversion = (obj + 1)->integer;
- //if (xref != NULL)
- // loggerf("unresolved reference %s", ppref_str(refnumber, refversion));
- ref = ppref_unresolved(stack->pheap, refnumber, refversion);
- }
- obj->type = PPREF;
- obj->ref = ref;
- return obj;
- }
- break;
- case 't':
- if (iof_next(I) == 'r' && iof_next(I) == 'u' && iof_next(I) == 'e')
- {
- ++I->pos;
- obj = ppstack_push(stack);
- obj->type = PPBOOL;
- obj->integer = 1;
- return obj;
- }
- break;
- case 'f':
- if (iof_next(I) == 'a' && iof_next(I) == 'l' && iof_next(I) == 's' && iof_next(I) == 'e')
- {
- ++I->pos;
- obj = ppstack_push(stack);
- obj->type = PPBOOL;
- obj->integer = 0;
- return obj;
- }
- break;
- case 'n':
- if (iof_next(I) == 'u' && iof_next(I) == 'l' && iof_next(I) == 'l')
- {
- ++I->pos;
- obj = ppstack_push(stack);
- obj->type = PPNULL;
- obj->any = NULL;
- return obj;
- }
- break;
- }
- return NULL;
-}
-
-/*
-A variant for contents streams (aka postscript); wise of operators, blind to references.
-We are still PDF, so we don't care about postscript specific stuff such as radix numbers
-and scientific numbers notation. It takes ppstack * as context (no ppdoc *) to be able
-to run contents parser beyond the scope of ppdoc heap.
-*/
-
-static ppstring ppstring_inline (iof *I, ppdict *imagedict, ppheap **pheap);
-
-static ppobj * ppscan_psobj (iof *I, ppstack *stack)
-{
- int c;
- ppobj *obj, *op;
- size_t size, mark;
- ppname exec;
-
- c = iof_char(I);
- switch (c)
- {
- case DIGIT_CHAR_CASE:
- return ppscan_numobj(I, ppstack_push(stack), 0);
- case '.':
- return ppscan_numobj_frac(I, ppstack_push(stack), 0);
- case '+':
- c = iof_next(I);
- if (base10_digit(c)) // '+.abc' is probably an executable name, but we are not in postscript
- return ppscan_numobj(I, ppstack_push(stack), 0);
- else if (c == '.')
- return ppscan_numobj_frac(I, ppstack_push(stack), 0);
- obj = ppstack_push(stack);
- obj->type = PPNAME;
- obj->name = ppscan_exec(I, stack->pheap, '+');
- return obj;
- case '-':
- c = iof_next(I);
- if (base10_digit(c)) // ditto, we would handle type1 '-|' '|-' operators though
- return ppscan_numobj(I, ppstack_push(stack), 1);
- else if (c == '.')
- return ppscan_numobj_frac(I, ppstack_push(stack), 1);
- obj = ppstack_push(stack);
- obj->type = PPNAME;
- obj->name = ppscan_exec(I, stack->pheap, '-');
- return obj;
- case '/':
- ++I->pos;
- obj = ppstack_push(stack);
- obj->type = PPNAME;
- obj->name = ppscan_name(I, stack->pheap);
- return obj;
- case '(':
- ++I->pos;
- obj = ppstack_push(stack);
- obj->type = PPSTRING;
- obj->string = ppscan_string(I, stack->pheap);
- return obj;
- case '[':
- mark = stack->size;
- obj = ppstack_push(stack);
- obj->type = PPMARK;
- obj->any = NULL;
- ++I->pos;
- for (c = ppscan_find(I); c != ']'; c = ppscan_find(I))
- {
- if (ppscan_psobj(I, stack) == NULL)
- {
- size = stack->size - mark;
- ppstack_pop(stack, size);
- return NULL;
- }
- }
- ++I->pos;
- size = stack->size - mark - 1;
- obj = ppstack_at(stack, mark);
- obj->type = PPARRAY;
- obj->array = pparray_create(ppstack_at(stack, mark + 1), size, stack->pheap);
- ppstack_pop(stack, size);
- return obj;
- case '<':
- if ((c = iof_next(I)) == '<')
- {
- mark = stack->size;
- obj = ppstack_push(stack);
- obj->type = PPMARK;
- obj->any = NULL;
- ++I->pos;
- for (c = ppscan_find(I); c != '>'; c = ppscan_find(I))
- {
- if (ppscan_psobj(I, stack) == NULL)
- {
- size = stack->size - mark;
- ppstack_pop(stack, size);
- return NULL;
- }
- }
- if (iof_next(I) == '>')
- ++I->pos;
- size = stack->size - mark - 1;
- obj = ppstack_at(stack, mark);
- obj->type = PPDICT;
- obj->dict = ppdict_create(ppstack_at(stack, mark + 1), size, stack->pheap);
- ppstack_pop(stack, size);
- return obj;
- }
- obj = ppstack_push(stack);
- obj->type = PPSTRING;
- if (c == '~')
- ++I->pos, obj->string = ppscan_base85(I, stack->pheap);
- else
- obj->string = ppscan_base16(I, stack->pheap);
- return obj;
- default:
- if (c < 0 || !ppname_byte_lookup[c])
- break; // forbid empty names; dead loop otherwise
- ++I->pos;
- /* true false null practically don't occur in streams so it makes sense to assume that we get an operator name here.
- If it happen to be a keyword we could give back those several bytes to the heap but.. heap buffer is tricky enough. */
- exec = ppscan_exec(I, stack->pheap, c);
- obj = ppstack_push(stack);
- switch (exec[0])
- {
- case 't':
- if (exec[1] == 'r' && exec[2] == 'u' && exec[3] == 'e' && exec[4] == '\0')
- {
- obj->type = PPBOOL;
- obj->integer = 1;
- // todo: drop exec
- return obj;
- }
- break;
- case 'f':
- if (exec[1] == 'a' && exec[2] == 'l' && exec[3] == 's' && exec[4] == 'e' && exec[5] == '\0')
- {
- obj->type = PPBOOL;
- obj->integer = 0;
- // todo: drop exec
- return obj;
- }
- break;
- case 'n':
- if (exec[1] == 'u' && exec[2] == 'l' && exec[3] == 'l' && exec[4] == '\0')
- {
- obj->type = PPNULL;
- obj->any = NULL;
- // todo: drop exec
- return obj;
- }
- break;
- case 'B':
- /*
- Inline images break rules of operand/operator syntax, so 'BI/ID' operators need to be treated as special syntactic keywords.
-
- BI <keyval pairs> ID<whitechar?><imagedata><whitechar?>EI
-
- We treat the image as a single syntactic token; BI starts collecting a dict, ID is the beginning of the data. Effectively EI
- operator obtains two operands - dict and string. It is ok to put three items onto the stack, callers dont't assume there is just one.
- */
- if (exec[1] == 'I' && exec[2] == '\0')
- {
- ppdict *imagedict;
- /* key val pairs -> dict */
- mark = stack->size - 1;
- obj->type = PPMARK;
- obj->any = NULL;
- for (c = ppscan_find(I); ; c = ppscan_find(I))
- {
- if ((op = ppscan_psobj(I, stack)) == NULL)
- {
- size = stack->size - mark;
- ppstack_pop(stack, size);
- return NULL;
- }
- if (op->type == PPNAME && ppname_exec(op->name))
- {
- if (!ppname_is(op->name, "ID"))
- { // weird
- size = stack->size - mark;
- ppstack_pop(stack, size);
- return NULL;
- }
- break;
- }
- }
- size = stack->size - mark - 1;
- obj = ppstack_at(stack, mark);
- obj->type = PPDICT;
- obj->dict = imagedict = ppdict_create(ppstack_at(stack, mark + 1), size, stack->pheap);
- ppstack_pop(stack, size);
- /* put image data string */
- obj = ppstack_push(stack);
- obj->type = PPSTRING;
- obj->string = ppstring_inline(I, imagedict, stack->pheap);;
- /* put EI operator name */
- obj = ppstack_push(stack);
- obj->type = PPNAME;
- obj->name = ppexec_internal("EI", 2, stack->pheap);
- return obj;
- }
- }
- obj->type = PPNAME;
- obj->name = exec;
- return obj;
- }
- return NULL;
-}
-
-/*
-We try to get the exact inline image length from its dict params. If cannot predict the length, we have to scan the input until 'EI'.
-I've checked on may examples that it gives the same results but one can never be sure, as 'EI' might happen to be a part of the data.
-Stripping white char is also very heuristic; \0 is a white char in PDF and very likely to be a data byte.. weak method.
-*/
-
-static size_t inline_image_length (ppdict *dict)
-{
- ppuint w, h, bpc, colors;
- ppname cs;
-
- if (ppdict_get_uint(dict, "W", &w) && ppdict_get_uint(dict, "H", &h) && ppdict_get_uint(dict, "BPC", &bpc) && (cs = ppdict_get_name(dict, "CS")) != NULL)
- {
- if (ppname_is(cs, "DeviceGray"))
- colors = 1;
- else if (ppname_is(cs, "DeviceRGB"))
- colors = 3;
- else if (ppname_is(cs, "DeviceCMYK"))
- colors = 4;
- else
- return PP_LENGTH_UNKNOWN;
- return (w * h * bpc * colors + 7) >> 3;
- }
- return PP_LENGTH_UNKNOWN;
-}
-
-static ppstring ppstring_inline (iof *I, ppdict *imagedict, ppheap **pheap)
-{
- iof *O;
- int c, d, e;
- size_t length, leftin, leftout, bytes;
-
- O = ppheap_buffer(pheap, sizeof(_ppstring), PPSTRING_INIT);
- c = iof_char(I);
- if (ignored_char(c))
- c = iof_next(I);
-
- length = inline_image_length(imagedict);
- if (length != PP_LENGTH_UNKNOWN)
- {
- while (length > 0 && iof_readable(I) && iof_writable(O))
- {
- leftin = iof_left(I);
- leftout = iof_left(O);
- bytes = length;
- if (bytes > leftin) bytes = leftin;
- if (bytes > leftout) bytes = leftout;
- memcpy(O->pos, I->pos, bytes);
- I->pos += bytes;
- O->pos += bytes;
- length -= bytes;
- }
- // gobble EI
- if (ppscan_find(I) == 'E')
- if (iof_next(I) == 'I')
- ++I->pos;
- }
- else
- {
- while (c >= 0)
- {
- if (c == 'E')
- {
- d = iof_next(I);
- if (d == 'I')
- {
- e = iof_next(I);
- if (!ppname_byte_lookup[e])
- { /* strip one newline from the end and stop */
- if (O->pos - 2 >= O->buf) // sanity
- {
- c = *(O->pos - 1);
- if (ignored_char(c))
- {
- if (c == 0x0A && *(O->pos - 2) == 0x0D)
- O->pos -= 2;
- else
- O->pos -= 1;
- }
- }
- break;
- }
- iof_put2(O, c, d);
- c = e;
- }
- else
- {
- iof_put(O, c);
- c = d;
- }
- }
- else
- {
- iof_put(O, c);
- c = iof_next(I);
- }
- }
- }
- return ppstring_buffer(O, pheap);
-}
-
-/* input reader */
-
-/*
-PDF input is a pseudo file that either keeps FILE * or data. Reader iof * is a proxy to input
-that provides byte-by-byte interface. Our iof structure is capable to link iof_file *input,
-but t avoid redundant checks on IOF_DATA flag, here we link iof *I directly to FILE * or mem buffer.
-When reading from file we need an internal buffer, which should be kept rather small, as it is
-only used to parse xrefs and objects (no streams). We allocate the buffer from a private heap
-(not static) to avoid conflicts when processing >1 pdfs at once. Besides, the input buffer may be
-needed after loading the document, eg. to access references raw data.
-*/
-
-#define PPDOC_BUFFER 0xFFF // keep that small, it is only used to parse body objects
-
-static void ppdoc_reader_init (ppdoc *pdf, iof_file *input)
-{
- iof *I;
- pdf->input = *input;
- input = &pdf->input;
- input->refcount = 1;
- I = &pdf->reader;
- if (input->flags & IOF_DATA)
- {
- pdf->buffer = NULL; // input iof_file is the buffer
- iof_string_reader(I, NULL, 0); // gets IOF_DATA flag
- }
- else
- {
- pdf->buffer = (uint8_t *)ppheap_take(&pdf->heap, PPDOC_BUFFER);
- iof_setup_file_handle_reader(I, NULL, 0, iof_file_get_fh(input)); // gets IOF_FILE_HANDLE flag and FILE *
- I->space = PPDOC_BUFFER; // used on refill
- }
-}
-
-/*
-Whenever we need to read the input file, we fseek the to the given offset and fread to to the private buffer.
-The length we need is not always predictable, in which case PPDOC_BUFFER bytes are read (keep it small).
-I->buf = I->pos is set to the beginning, I->end set to the end (end is the first byte one shouldn't read).
-*/
-
-static iof * ppdoc_reader (ppdoc *pdf, size_t offset, size_t length)
-{
- iof_file *input;
- iof *I;
- input = &pdf->input;
- I = &pdf->reader;
- if (iof_file_seek(input, offset, SEEK_SET) != 0)
- return NULL;
- I->flags &= ~IOF_STOPPED;
- if (input->flags & IOF_DATA)
- {
- I->buf = I->pos = input->pos;
- I->end = (length == PP_LENGTH_UNKNOWN || I->pos + length >= input->end) ? input->end : (I->pos + length);
- }
- else
- {
- I->buf = I->pos = pdf->buffer; // ->buf is actually permanently equal pdf->buffer but we might need some tricks
- if (length == PP_LENGTH_UNKNOWN || length > PPDOC_BUFFER)
- length = PPDOC_BUFFER;
- length = fread(I->buf, 1, length, I->file);
- I->end = I->buf + length;
- }
- return I;
-}
-
-/* The position from the beginning of input
-- for data buffer: (pdf->input.pos - pdf->input.buf) + (I->pos - I->buf)
- I->buf == pdf->input.pos, so this resolves to (I->pos - pdf->input.buf), independent from I->buf
-- for file buffer: ftell(pdf->input.file) - (I->end - I->pos)
-*/
-
-#define ppdoc_reader_tell(pdf, I) ((size_t)(((pdf)->input.flags & IOF_DATA) ? ((I)->pos - (pdf)->input.buf) : (ftell(iof_file_get_fh(&(pdf)->input)) - ((I)->end - (I)->pos))))
-
-/* pdf */
-
-#define PPDOC_HEADER 10 // "%PDF-?.??\n"
-
-static int ppdoc_header (ppdoc *pdf, uint8_t header[PPDOC_HEADER])
-{
- size_t i;
- if (memcmp(header, "%PDF-", 5) != 0)
- return 0;
- for (i = 5; i < PPDOC_HEADER - 1 && !ignored_char(header[i]); ++i)
- pdf->version[i - 5] = header[i];
- pdf->version[i - 5] = '\0';
- return 1;
-}
-
-static int ppdoc_tail (ppdoc *pdf, iof_file *input, size_t *pxrefoffset)
-{
- int c;
- uint8_t tail[4*10], *p, back, tailbytes;
-
- if (iof_file_seek(input, 0, SEEK_END) != 0)
- return 0;
- pdf->filesize = (size_t)iof_file_tell(input);
- // simple heuristic to avoif fgetc() / fseek(-2) hiccup: keep seeking back by len(startxref) + 1 == 10
- // until a letter found (assuming liberal white characters and tail length)
- for (back = 1, tailbytes = 0; ; ++back)
- {
- if (iof_file_seek(input, -10, SEEK_CUR) != 0)
- return 0;
- tailbytes += 10;
- c = iof_file_getc(input);
- tailbytes -= 1;
- switch (c)
- {
- case IGNORED_CHAR_CASE:
- case DIGIT_CHAR_CASE:
- case '%': case 'E': case 'O': case 'F':
- if (back > 4) // 2 should be enough
- return 0;
- continue;
- case 's': case 't': case 'a': case 'r': case 'x': case 'e': case 'f':
- if (iof_file_read(tail, 1, tailbytes, input) != tailbytes)
- return 0;
- tail[tailbytes] = '\0';
- for (p = &tail[0]; ; ++p)
- {
- if (*p == '\0')
- return 0;
- if ((c = base10_value(*p)) >= 0)
- break;
- }
- ppread_uint(p, pxrefoffset);
- return 1;
- default:
- return 0;
- }
- }
- return 0;
-}
-
-/* xref/body */
-
-static int ppscan_start_entry (iof *I, ppref *ref)
-{
- ppuint u;
- ppscan_find(I); if (!ppscan_uint(I, &u) || u != ref->number) return 0;
- ppscan_find(I); if (!ppscan_uint(I, &u) || u != ref->version) return 0;
- ppscan_find(I); if (!ppscan_key(I, "obj")) return 0;
- ppscan_find(I);
- return 1;
-}
-
-static int ppscan_skip_entry (iof *I)
-{
- size_t u;
- ppscan_find(I); if (!ppscan_uint(I, &u)) return 0;
- ppscan_find(I); if (!ppscan_uint(I, &u)) return 0;
- ppscan_find(I); if (!ppscan_key(I, "obj")) return 0;
- ppscan_find(I);
- return 1;
-}
-
-static int ppscan_start_stream (iof *I, ppdoc *pdf, size_t *streamoffset)
-{
- int c;
- ppscan_find(I);
- if (ppscan_key(I, "stream"))
- { // skip 1 or 2 whites (here we shouldn't just gobble all blanks)
- c = iof_char(I);
- if (ignored_char(c))
- {
- c = iof_next(I);
- if (ignored_char(c))
- ++I->pos;
- }
- *streamoffset = ppdoc_reader_tell(pdf, I);
- return 1;
- }
- return 0;
-}
-
-static ppxref * ppxref_load (ppdoc *pdf, size_t xrefoffset);
-static ppxref * ppxref_load_chain (ppdoc *pdf, ppxref *xref);
-
-/* Parsing xref table
-
- 1 10 // first ref number and refs count
- 0000000000 00000 n // 10-digits offset, 5 digits version, type identifier
- 0000000000 00000 n // n states for normal I guess
- 0000000000 00000 f // f states for free (not used)
- ...
-
-Free entries seem to be a relic of ancient times, completelly useless for us. To avoid parsing xref table twice,
-we waste some space on free entries by allocating one plane of refs for each section. Later on we slice sections,
-so that effectively free entries are not involved in map.
-
-Subsequent refs gets number, version and offset. Other fields initialized when parsing PDF body.
-
-Having xref table loaded, we sort sections for future binary search (xref with objects count == 0 is considered invalid).
-
-Then we have to deal with the trailer dict. In general, to load objects and resolve references we need a complete chain
-of xrefs (not only the top). To load the previous xref, we need its offset, which is given in trailer. So we have to
-parse the trailer ignoring references, which might be unresolvable at this point (objects parser makes a dummy check
-for xref != NULL on refs resolving ppscan_obj(), which irritates me but I don't want a separate parser for trailer..).
-The same applies to xref streams, in which we have parse the trailer not having xref map at all. So the procedure is:
-
- - load xref map, initialize references, make it ready to search
- - parse trailer ignoring references
- - get /Prev xref offset and load older xref (linked list via ->prev)
- - sort all refs in all xrefs by offset
- - parse refs in order resolving references in contained objects
- - fix trailer references
-
-First created xref becomes a pdf->xref (top xref). We link that early to control offsets already read (insane loops?).
-*/
-
-// Every xref table item "0000000000 00000 n" is said to be terminated with 2-byte EOL but we don't like relying on whites.
-#define xref_item_length (10+1+5+1+1)
-
-static ppxref * ppxref_load_table (iof *I, ppdoc *pdf, size_t xrefoffset)
-{
- ppxref *xref;
- ppxsec *xrefsection;
- ppref *ref;
- ppuint first, count, refindex;
- uint8_t buffer[xref_item_length + 1];
- const char *p;
- const ppobj *obj;
-
- buffer[xref_item_length] = '\0';
- xref = ppxref_create(pdf, 0, xrefoffset);
- if (pdf->xref == NULL) pdf->xref = xref;
- for (ppscan_find(I); ppscan_uint(I, &first); ppscan_find(I))
- {
- ppscan_find(I);
- if (!ppscan_uint(I, &count))
- return NULL;
- if (count == 0) // weird
- continue;
- xref->count += count;
- xrefsection = NULL;
- ref = (ppref *)ppheap_take(&pdf->heap, count * sizeof(ppref));
- for (refindex = 0; refindex < count; ++refindex, ++ref)
- {
- ref->xref = xref;
- ref->number = first + refindex;
- ppscan_find(I);
- iof_read(I, buffer, xref_item_length);
- switch (buffer[xref_item_length - 1])
- {
- case 'n':
- if (xrefsection == NULL)
- {
- xrefsection = ppxref_push_section(xref, &pdf->heap);
- xrefsection->first = ref->number;
- xrefsection->refs = ref;
- }
- xrefsection->last = ref->number;
- for (p = (const char *)buffer; *p == '0'; ++p);
- p = ppread_uint(p, &ref->offset);
- for ( ; *p == ' ' || *p == '0'; ++p);
- p = ppread_uint(p, &ref->version);
- ref->object.type = PPNONE; // init for sanity
- ref->object.any = NULL;
- ref->length = 0;
- break;
- case 'f':
- default:
- --ref;
- xrefsection = NULL;
- --xref->count;
- }
- }
- }
- /* sort section */
- if (!ppxref_sort(xref))
- ; // case of xref->size == 0 handled by ppxref_load_chain()
- /* get trailer ignoring refs */
- if (!ppscan_key(I, "trailer"))
- return NULL;
- ppscan_find(I);
- if ((obj = ppscan_obj(I, pdf, NULL)) == NULL)
- return NULL;
- ppstack_pop(&pdf->stack, 1);
- if (obj->type != PPDICT)
- return NULL;
- xref->trailer = *obj;
- return ppxref_load_chain(pdf, xref);
-}
-
-/* Parsing xref stream
-First we load the trailer, ignoring references. Dict defines sections and fields lengths:
-
- /Size % max ref number plus 1
- /Index [ first count first count ... ] % a pair of numbers for every section, defaults to [0 Size]
- /W [w1 w2 w3] % fields lengths, 0 states for omitted field
-
-xref stream data is a continuous stream of binary number triplets. First number is a type:
-
- 0 - free entry (as 'f' in xref table)
- 1 - normal entry, followed by offset an version (as 'n' in xref table)
- 2 - compressed entry, followed by parent object stream number and entry index
-
-0 and 1 are handled as 'n' and 'f' entries in xref table. For type 2 we normally initialize
-ref->number and ref->version (the later is implicitly 0). ref->offset is set to 0 (invalid offset),
-which is recognized by objects loader.
-*/
-
-#define XREF_STREAM_MAX_FIELD 4
-
-static ppxref * ppxref_load_stream (iof *I, ppdoc *pdf, size_t xrefoffset)
-{
- ppxref *xref;
- ppxsec *xrefsection;
- ppref *ref;
- ppobj *obj;
- ppstream *xrefstream;
- size_t streamoffset;
- ppuint w1, w2, w3, w, bufferbytes;
- uint8_t buffer[3 * XREF_STREAM_MAX_FIELD], *b;
- ppuint first, count, f1, f2, f3;
- pparray *fieldwidths, *sectionindices;
- ppobj sectionmock[2], *sectionfirst, *sectioncount;
- size_t sections, sectionindex, refindex;
-
- if (!ppscan_skip_entry(I))
- return NULL;
- if ((obj = ppscan_obj(I, pdf, NULL)) == NULL)
- return NULL;
- ppstack_pop(&pdf->stack, 1);
- if (obj->type != PPDICT || !ppscan_start_stream(I, pdf, &streamoffset))
- return NULL;
- xrefstream = ppstream_create(pdf, obj->dict, streamoffset);
- /* All normal streams go through ppstream_info(), but it makes no sense for trailer stream (no crypt allowed, no refs yet).
- So we just record the length and informative flag. Here we have to expect that /Length and /Filter are not indirects. */
- if (!ppdict_get_uint(obj->dict, "Length", &xrefstream->length))
- return NULL;
- if (ppdict_get_obj(obj->dict, "Filter") != NULL)
- xrefstream->flags |= PPSTREAM_COMPRESSED;
- if ((fieldwidths = ppdict_get_array(xrefstream->dict, "W")) != NULL)
- {
- if (!pparray_get_uint(fieldwidths, 0, &w1)) w1 = 0;
- if (!pparray_get_uint(fieldwidths, 1, &w2)) w2 = 0;
- if (!pparray_get_uint(fieldwidths, 2, &w3)) w3 = 0;
- }
- else
- w1 = w2 = w3 = 0;
- if (w1 > XREF_STREAM_MAX_FIELD || w2 > XREF_STREAM_MAX_FIELD || w3 > XREF_STREAM_MAX_FIELD)
- return NULL;
- bufferbytes = w1 + w2 + w3;
- if ((sectionindices = ppdict_get_array(xrefstream->dict, "Index")) != NULL)
- {
- sections = sectionindices->size >> 1;
- sectionfirst = sectionindices->data;
- }
- else
- {
- sections = 1;
- sectionmock[0].type = PPINT;
- sectionmock[0].integer = 0;
- sectionmock[1].type = PPINT;
- if (!ppdict_get_int(xrefstream->dict, "Size", &sectionmock[1].integer))
- sectionmock[1].integer = 0;
- sectionfirst = &sectionmock[0];
- }
- if ((I = ppstream_read(xrefstream, 1, 0)) == NULL)
- return NULL; // we fseek() so original I is useless anyway
- xref = ppxref_create(pdf, sections, xrefoffset);
- if (pdf->xref == NULL) pdf->xref = xref;
- xref->trailer.type = PPSTREAM;
- xref->trailer.stream = xrefstream;
- for (sectionindex = 0; sectionindex < sections; ++sectionindex, sectionfirst += 2)
- {
- sectioncount = sectionfirst + 1;
- if (!ppobj_get_uint(sectionfirst, first) || !ppobj_get_uint(sectioncount, count))
- goto xref_stream_error;
- if (count == 0)
- continue;
- xref->count += count;
- xrefsection = NULL;
- ref = (ppref *)ppheap_take(&pdf->heap, count * sizeof(ppref));
- for (refindex = 0; refindex < count; ++refindex, ++ref)
- {
- ref->xref = xref;
- ref->number = first + refindex;
- if (iof_read(I, buffer, bufferbytes) != bufferbytes)
- goto xref_stream_error;
- b = buffer;
- if (w1 == 0)
- f1 = 1; // default type is 1
- else
- for (f1 = 0, w = 0; w < w1; f1 = (f1 << 8)|(*b), ++w, ++b);
- for (f2 = 0, w = 0; w < w2; f2 = (f2 << 8)|(*b), ++w, ++b);
- for (f3 = 0, w = 0; w < w3; f3 = (f3 << 8)|(*b), ++w, ++b);
- switch (f1)
- {
- case 0:
- //--ref;
- xrefsection = NULL;
- --xref->count;
- break;
- case 1:
- if (xrefsection == NULL)
- {
- xrefsection = ppxref_push_section(xref, &pdf->heap);
- xrefsection->first = ref->number;
- xrefsection->refs = ref;
- }
- xrefsection->last = ref->number;
- ref->offset = f2;
- ref->version = f3;
- ref->object.type = PPNONE;
- ref->object.any = NULL;
- ref->length = 0;
- break;
- case 2:
- if (xrefsection == NULL)
- {
- xrefsection = ppxref_push_section(xref, &pdf->heap);
- xrefsection->first = ref->number;
- xrefsection->refs = ref;
- }
- xrefsection->last = ref->number;
- ref->offset = 0; // f2 is parent objstm, f3 is index in parent, both useless
- ref->version = 0; // compressed objects has implicit version == 0
- ref->object.type = PPNONE;
- ref->object.any = NULL;
- ref->length = 0;
- break;
- default:
- goto xref_stream_error;
- }
- }
- }
- /* sort sections */
- if (!ppxref_sort(xref))
- ; // case of xref->size == 0 handled by ppxref_load_chain()
- /* close the stream _before_ loading prev xref */
- ppstream_done(xrefstream);
- /* load prev and return */
- return ppxref_load_chain(pdf, xref);
-xref_stream_error:
- ppstream_done(xrefstream);
- return NULL;
-}
-
-/*
-The following procedure loads xref /Prev, links xref->prev and typically returns xref.
-Some docs contain empty xref (one section with zero objects) that is actually a proxy
-to xref stream referred as /XRefStm (genuine concept of xrefs old/new style xrefs in
-the same doc). In case of 0-length xref we ignore the proxy and return the target xref
-(otherwise we would need annoying sanity check for xref->size > 0 on every ref search).
-*/
-
-static ppxref * ppxref_load_chain (ppdoc *pdf, ppxref *xref)
-{
- ppdict *trailer;
- ppuint xrefoffset;
- ppxref *prevxref, *nextxref;
-
- trailer = ppxref_trailer(xref);
- if (!ppdict_get_uint(trailer, "Prev", &xrefoffset)) // XRefStm is useless
- return xref; // missing /Prev is obviously ok
- for (nextxref = pdf->xref; nextxref != NULL; nextxref = nextxref->prev)
- if (nextxref->offset == xrefoffset) // insane
- return NULL;
- if ((prevxref = ppxref_load(pdf, (size_t)xrefoffset)) == NULL)
- return NULL;
- if (xref->size > 0)
- {
- xref->prev = prevxref;
- return xref;
- }
- if (pdf->xref == xref)
- pdf->xref = prevxref;
- return prevxref;
-}
-
-static ppxref * ppxref_load (ppdoc *pdf, size_t xrefoffset)
-{
- iof *I;
- if ((I = ppdoc_reader(pdf, xrefoffset, PP_LENGTH_UNKNOWN)) == NULL)
- return NULL;
- ppscan_find(I);
- if (ppscan_key(I, "xref"))
- return ppxref_load_table(I, pdf, xrefoffset);
- return ppxref_load_stream(I, pdf, xrefoffset);
- // iof_close(I) does nothing here
-}
-
-static void ppoffmap_sort (ppref **left, ppref **right)
-{
- ppref **l, **r, *t;
- ppuint pivot;
- l = left, r = right;
- pivot = (*(l + ((r - l) / 2)))->offset;
- do
- { // don't read from pointer!
- while ((*l)->offset < pivot) ++l;
- while ((*r)->offset > pivot) --r;
- if (l <= r)
- {
- t = *l;
- *l = *r;
- *r = t;
- ++l, --r;
- }
- } while (l <= r);
- if (left < r)
- ppoffmap_sort(left, r);
- if (l < right)
- ppoffmap_sort(l, right);
-}
-
-
-static void fix_trailer_references (ppdoc *pdf)
-{
- ppxref *xref;
- ppdict *trailer;
- ppname *pkey;
- ppobj *obj;
- ppref *ref;
- for (xref = pdf->xref; xref != NULL; xref = xref->prev)
- {
- if ((trailer = ppxref_trailer(xref)) == NULL)
- continue;
- for (ppdict_first(trailer, pkey, obj); *pkey != NULL; ppdict_next(pkey, obj))
- { // no need to go deeper in structs, all items in trailer except info and root must be direct refs
- if (obj->type != PPREF)
- continue;
- ref = obj->ref;
- if (ref->offset == 0) // unresolved?
- if ((ref = ppxref_find(xref, ref->number)) != NULL)
- obj->ref = ref; // at this moment the reference still points nothing, but should be the one with the proper offset
- }
- }
-}
-
-/*
-Here comes a procedure that loads all entries from all document bodies. We resolve references while
-parsing objects and to make resolving correct, we need a complete chain of xref maps, and a knowledge
-about possible linearized dict (first offset). So loading refs sorted by offsets makes sense (not sure
-if it matters nowadays but we also avoid fseek() by large offsets).
-
-Here is the proc:
-
- - create a list of all refs in all bodies
- - sort the list by offsets
- - for every ref from the sorted list:
- - estimate object length to avoid fread-ing more than necessary (not perfect but enough)
- - fseek() to the proper offset, fread() entry data or its part
- - parse the object with ppscan_obj(I, pdf, xref), where xref is not necessarily top pdf->xref
- - save the actual ref->length (not sure if we need that?)
- - make a stream if a dict is followed by "stream" keyword, also save the stream offset
- - free the list
-*/
-
-static int ppdoc_load_objstm (ppstream *stream, ppdoc *pdf, ppxref *xref);
-
-static void ppdoc_load_entries (ppdoc *pdf)
-{
- size_t objects, sectionindex, refnumber, offindex;
- ppnum linearized;
- ppref **offmap, **pref, *ref;
- ppxref *xref;
- ppxsec *xsec;
- ppobj *obj;
- ppname type;
- int redundant_indirection = 0;
- ppcrypt *crypt;
- ppstream *stream;
-
- if ((objects = (size_t)ppdoc_objects(pdf)) == 0) // can't happen
- return;
- pref = offmap = (ppref **)pp_malloc(objects * sizeof(ppref *));
- objects = 0; // recount refs with offset > 0
- for (xref = pdf->xref; xref != NULL; xref = xref->prev)
- for (sectionindex = 0, xsec = xref->sects; sectionindex < xref->size; ++sectionindex, ++xsec)
- for (refnumber = xsec->first, ref = xsec->refs; refnumber <= xsec->last; ++refnumber, ++ref)
- if (ref->offset > 0) // 0 means compressed or insane
- *pref++ = ref, ++objects;
- ppoffmap_sort(offmap, offmap + objects - 1);
-
- crypt = pdf->crypt;
- for (offindex = 0, pref = offmap; offindex < objects; )
- {
- ref = *pref;
- ++pref;
- ++offindex;
- if (ref->object.type != PPNONE) // might be preloaded already (/Encrypt dict, stream filter dicts, stream /Length..)
- continue;
- if (offindex < objects)
- ref->length = (*pref)->offset - ref->offset;
- else
- ref->length = pdf->filesize > ref->offset ? pdf->filesize - ref->offset : 0;
- if (crypt != NULL)
- {
- ppcrypt_start_ref(crypt, ref);
- obj = ppdoc_load_entry(pdf, ref);
- ppcrypt_end_ref(crypt);
- }
- else
- {
- obj = ppdoc_load_entry(pdf, ref);
- }
- switch (obj->type)
- {
- case PPDICT: /* Check if the object at first offset is linearized dict. We need that to resolve all references properly. */
- if (offindex == 1 && ppdict_get_num(obj->dict, "Linearized", &linearized)) // /Linearized value is a version number, default 1.0
- pdf->flags |= PPDOC_LINEARIZED;
- break;
- case PPREF:
- redundant_indirection = 1;
- break;
- default:
- break;
- }
- // if pdf->crypt crypt->ref = NULL
- }
-
- /* refs pointngs refs? cut. */
- if (redundant_indirection)
- {
- for (offindex = 0, pref = offmap; offindex < objects; ++offindex)
- {
- ref = *pref++;
- if (ref->object.type == PPREF)
- ref->object = ref->object.ref->object; // doing for all effectively cuts all insane chains
- }
- }
-
- /* now handle streams; update stream info (eg. /Length), load pdf 1.5 object streams
- we could do earlier but then we would need to struggle with indirects */
- for (offindex = 0, pref = offmap; offindex < objects; ++offindex)
- {
- ref = *pref++;
- obj = &ref->object;
- if (obj->type != PPSTREAM)
- continue;
- stream = obj->stream;
- if (crypt != NULL)
- {
- ppcrypt_start_ref(crypt, ref);
- ppstream_info(stream, pdf);
- ppcrypt_end_ref(crypt);
- }
- else
- {
- ppstream_info(stream, pdf);
- }
- if (ref->xref->trailer.type == PPSTREAM && (type = ppdict_get_name(stream->dict, "Type")) != NULL && ppname_is(type, "ObjStm")) // somewhat dummy..
- if (!ppdoc_load_objstm(stream, pdf, ref->xref))
- loggerf("invalid objects stream %s at offset " PPSIZEF, ppref_str(ref->number, ref->version), ref->offset);
- }
- pp_free(offmap);
-}
-
-ppobj * ppdoc_load_entry (ppdoc *pdf, ppref *ref)
-{
- iof *I;
- size_t length;
- ppxref *xref;
- ppobj *obj;
- ppstack *stack;
- size_t streamoffset;
- ppref *refref;
- ppuint refnumber, refversion;
-
- length = ref->length > 0 ? ref->length : PP_LENGTH_UNKNOWN; // estimated or unknown
- if ((I = ppdoc_reader(pdf, ref->offset, length)) == NULL || !ppscan_start_entry(I, ref))
- {
- loggerf("invalid %s offset " PPSIZEF, ppref_str(ref->number, ref->version), ref->offset);
- return &ref->object; // PPNONE
- }
- stack = &pdf->stack;
- xref = ref->xref; // to resolve indirects properly
- if ((obj = ppscan_obj(I, pdf, xref)) == NULL)
- {
- loggerf("invalid %s object at offset " PPSIZEF, ppref_str(ref->number, ref->version), ref->offset);
- return &ref->object; // PPNONE
- }
- ref->object = *obj;
- ppstack_pop(stack, 1);
- obj = &ref->object;
- ref->length = ppdoc_reader_tell(pdf, I) - ref->offset;
- if (obj->type == PPDICT)
- {
- if (ppscan_start_stream(I, pdf, &streamoffset))
- {
- obj->type = PPSTREAM;
- obj->stream = ppstream_create(pdf, obj->dict, streamoffset);
- }
- }
- else if (obj->type == PPINT)
- {
- ppscan_find(I);
- if (ppscan_uint(I, &refversion) && ppscan_find(I) == 'R')
- {
- refnumber = (ppuint)obj->integer;
- if ((refref = ppxref_find(xref, refnumber)) != NULL)
- {
- obj->type = PPREF;
- obj->ref = refref;
- }
- else
- {
- obj->type = PPNONE; // as ppref_unresolved()
- obj->any = NULL;
- }
- }
- }
- return obj;
-}
-
-/* Loading entries from object stream
-
- /N is the number of contained entries
- /First is the offset of the first item
-
-The stream consists of N pairs of numbers <objnum> <offset> <objnum> <offset> ...
-Offsets are ascending (relative to the first), but ref numbers order is arbitrary.
-PDF spec says there might be some additional data between objects, so we should obey offsets.
-Which means we should basically load the stream at once (may be needed anyway to grab the stream [...]).
-*/
-
-static int ppdoc_load_objstm (ppstream *stream, ppdoc *pdf, ppxref *xref)
-{
- ppdict *dict; // stream dict, actually still on stack
- ppref *ref;
- ppobj *obj;
- ppuint items, firstoffset, offset, objnum, i, invalid = 0;
- iof *I;
- uint8_t *firstdata, *indexdata;
- ppstack *stack;
-
- dict = stream->dict;
- if (!ppdict_rget_uint(dict, "N", &items) || !ppdict_rget_uint(dict, "First", &firstoffset))
- return 0;
- if ((I = ppstream_read(stream, 1, 1)) == NULL)
- return 0;
- firstdata = I->pos + firstoffset;
- if (firstdata >= I->end)
- goto invalid_objstm;
- stack = &pdf->stack;
- //if (pdf->crypt != NULL)
- // ppcrypt_end_ref(pdf->crypt); // objects are not encrypted, pdf->crypt->ref ensured NULL
- for (i = 0; i < items; ++i)
- {
- ppscan_find(I);
- if (!ppscan_uint(I, &objnum))
- goto invalid_objstm;
- ppscan_find(I);
- if (!ppscan_uint(I, &offset))
- goto invalid_objstm;
- if ((ref = ppxref_find_local(xref, objnum)) == NULL || ref->object.type != PPNONE)
- {
- loggerf("invalid compressed object number " PPUINTF " at position " PPUINTF, objnum, i);
- ++invalid;
- continue;
- }
- if (firstdata + offset >= I->end)
- {
- loggerf("invalid compressed object offset " PPUINTF " at position " PPUINTF, offset, i);
- ++invalid;
- continue;
- }
- indexdata = I->pos; // save position
- I->pos = firstdata + offset; // go to the object
- ppscan_find(I);
- if ((obj = ppscan_obj(I, pdf, xref)) != NULL)
- {
- ref->object = *obj;
- ppstack_pop(stack, 1);
- // nothing more needed, as obj can never be indirect ref or stream
- }
- else
- {
- ++invalid;
- loggerf("invalid compressed object %s at stream offset " PPUINTF, ppref_str(objnum, 0), offset);
- }
- I->pos = indexdata; // restore position and read next from index
- }
- ppstream_done(stream);
- return invalid == 0;
-invalid_objstm:
- ppstream_done(stream);
- return 0;
-}
-
-/* main PDF loader proc */
-
-ppcrypt_status ppdoc_crypt_pass (ppdoc *pdf, const void *userpass, size_t userpasslength, const void *ownerpass, size_t ownerpasslength)
-{
- switch (pdf->cryptstatus)
- {
- case PPCRYPT_NONE:
- case PPCRYPT_DONE:
- case PPCRYPT_FAIL:
- break;
- case PPCRYPT_PASS: // initial status or really needs password
- pdf->cryptstatus = ppdoc_crypt_init(pdf, userpass, userpasslength, ownerpass, ownerpasslength);
- switch (pdf->cryptstatus)
- {
- case PPCRYPT_NONE:
- case PPCRYPT_DONE:
- ppdoc_load_entries(pdf);
- break;
- case PPCRYPT_PASS: // user needs to check ppdoc_crypt_status() and recall ppdoc_crypt_pass() with the proper password
- case PPCRYPT_FAIL: // hopeless..
- break;
- }
- break;
- }
- return pdf->cryptstatus;
-}
-
-static ppdoc * ppdoc_read (ppdoc *pdf, iof_file *input)
-{
- uint8_t header[PPDOC_HEADER];
- size_t xrefoffset;
-
- input = &pdf->input;
- if (iof_file_read(header, 1, PPDOC_HEADER, input) != PPDOC_HEADER || !ppdoc_header(pdf, header))
- return NULL;
- if (!ppdoc_tail(pdf, input, &xrefoffset))
- return NULL;
- if (ppxref_load(pdf, xrefoffset) == NULL)
- return NULL;
- fix_trailer_references(pdf); // after loading xrefs but before accessing trailer refs (/Encrypt might be a reference)
- // check encryption, if any, try empty password
- switch (ppdoc_crypt_pass(pdf, "", 0, NULL, 0))
- {
- case PPCRYPT_NONE: // no encryption
- case PPCRYPT_DONE: // encryption with an empty password
- case PPCRYPT_PASS: // the user needs to check ppdoc_crypt_status() and call ppdoc_crypt_pass()
- break;
- case PPCRYPT_FAIL: // hopeless
- //loggerf("decryption failed");
- //return NULL;
- break;
- }
- return pdf;
-}
-
-static void ppdoc_pages_init (ppdoc *pdf);
-
-static ppdoc * ppdoc_create (iof_file *input)
-{
- ppdoc *pdf;
- ppheap *heap;
-
- heap = ppheap_new();
- pdf = (ppdoc *)ppheap_take(&heap, sizeof(ppdoc));
- pdf->flags = 0;
- pdf->heap = heap;
- pdf->xref = NULL;
- pdf->version[0] = '\0';
- pdf->crypt = NULL;
- pdf->cryptstatus = PPCRYPT_PASS; // force encryption check on ppdoc_read() -> ppdoc_crypt_pass()
- ppstack_init(&pdf->stack, &pdf->heap);
- ppdoc_reader_init(pdf, input);
- ppdoc_pages_init(pdf);
- if (ppdoc_read(pdf, &pdf->input) != NULL)
- return pdf;
- ppdoc_free(pdf);
- return NULL;
-}
-
-ppdoc * ppdoc_load (const char *filename)
-{
- FILE *file;
- iof_file input;
- if ((file = fopen(filename, "rb")) == NULL)
- return NULL;
- iof_file_init(&input, file);
- input.flags |= IOF_CLOSE_FILE;
- return ppdoc_create(&input);
-}
-
-ppdoc * ppdoc_mem (const void *data, size_t size)
-{
- iof_file input;
- iof_file_rdata_init(&input, data, size);
- input.flags |= IOF_BUFFER_ALLOC; // todo: 3 modes: borrow, take over, copy?
- return ppdoc_create(&input);
-}
-
-void ppdoc_free (ppdoc *pdf)
-{
- //iof_file_free(&pdf->input);
- iof_file_decref(&pdf->input);
- ppstack_free_buffer(&pdf->stack);
- ppheap_free(pdf->heap); // last!
-}
-
-ppcrypt_status ppdoc_crypt_status (ppdoc *pdf)
-{
- return pdf->cryptstatus;
-}
-
-ppint ppdoc_permissions (ppdoc *pdf)
-{
- return pdf->crypt != NULL ? pdf->crypt->permissions : (ppint)0xFFFFFFFFFFFFFFFF;
-}
-
-/* pages access */
-
-static pparray * pppage_node (ppdict *dict, ppuint *count, ppname *type)
-{
- ppname *pkey, key;
- ppobj *obj;
- pparray *kids = NULL;
- *count = 0;
- *type = NULL;
- for (ppdict_first(dict, pkey, obj); (key = *pkey) != NULL; ppdict_next(pkey, obj))
- {
- switch (key[0])
- {
- case 'T':
- if (ppname_is(key, "Type"))
- *type = ppobj_get_name(obj);
- break;
- case 'C':
- if (ppname_is(key, "Count"))
- ppobj_get_uint(obj, *count);
- break;
- case 'K':
- if (ppname_is(key, "Kids"))
- kids = ppobj_rget_array(obj);
- break;
- }
- }
- return kids;
-}
-
-#define ppname_is_page(type) (type != NULL && ppname_is(type, "Page"))
-
-ppuint ppdoc_page_count (ppdoc *pdf)
-{
- ppref *ref;
- ppname type;
- ppuint count;
- if ((ref = ppxref_pages(pdf->xref)) == NULL)
- return 0;
- if (pppage_node(ref->object.dict, &count, &type) == NULL)
- return ppname_is_page(type) ? 1 : 0; // acrobat and ghostscript accept documents with root /Pages entry being a reference to a sole /Page object
- return count;
-}
-
-ppref * ppdoc_page (ppdoc *pdf, ppuint index)
-{
- ppdict *dict;
- ppuint count;
- pparray *kids;
- size_t size, i;
- ppobj *r, *o;
- ppref *ref;
- ppname type;
-
-
- if ((ref = ppxref_pages(pdf->xref)) == NULL)
- return NULL;
- dict = ref->object.dict;
- if ((kids = pppage_node(dict, &count, &type)) != NULL)
- {
- if (index < 1 || index > count)
- return NULL;
- }
- else
- {
- return index == 1 && ppname_is_page(type) ? ref : NULL;
- }
-scan_array:
- if (index <= count / 2)
- { // probably shorter way from the beginning
- for (i = 0, size = kids->size, r = pparray_at(kids, 0); i < size; ++i, ++r)
- {
- if (r->type != PPREF)
- return NULL;
- o = &r->ref->object;
- if (o->type != PPDICT)
- return NULL;
- dict = o->dict;
- if ((kids = pppage_node(dict, &count, &type)) != NULL)
- {
- if (index <= count)
- goto scan_array;
- index -= count;
- continue;
- }
- if (index == 1 && ppname_is_page(type))
- return r->ref;
- --index;
- }
- }
- else if ((size = kids->size) > 0) // for safe (size-1)
- { // probably shorter way from the end
- index = count - index + 1;
- for (i = 0, r = pparray_at(kids, size - 1); i < size; ++i, --r)
- {
- if (r->type != PPREF)
- return NULL;
- o = &r->ref->object;
- if (o->type != PPDICT)
- return NULL;
- dict = o->dict;
- if ((kids = pppage_node(dict, &count, &type)) != NULL)
- {
- if (index <= count)
- goto scan_array;
- index -= count;
- continue;
- }
- if (index == 1 && ppname_is_page(type))
- return r->ref;
- --index;
- }
- }
- return NULL;
-}
-
-/*
-Through pages iterator. Iterating over pages tree just on the base of /Kids and /Parent keys
-is ineffective, as to get next pageref we need to take parent, find the pageref in /Kids,
-take next (or go upper).. Annoying. We use a dedicated stack for pages iterator. This could
-actually be done with pdf->stack, but some operations may clear it, so safer to keep it independent
-Besides, its depth is constant (set on first use), so no need for allocs.
-*/
-
-static void ppdoc_pages_init (ppdoc *pdf)
-{
- pppages *pages;
- pages = &pdf->pages;
- pages->root = pages->parent = pages->buffer;
- pages->depth = 0;
- pages->space = PPPAGES_STACK_DEPTH;
-}
-
-static ppkids * pppages_push (ppdoc *pdf, pparray *kids)
-{
- ppkids *newroot, *bounds;
- pppages *pages;
- pages = &pdf->pages;
- if (pages->depth == pages->space)
- {
- pages->space <<= 1;
- newroot = (ppkids *)ppheap_take(&pdf->heap, pages->space * sizeof(ppkids));
- memcpy(newroot, pages->root, pages->depth * sizeof(ppkids));
- pages->root = newroot;
- }
- bounds = pages->parent = &pages->root[pages->depth++];
- bounds->current = pparray_at(kids, 0);
- bounds->sentinel = pparray_at(kids, kids->size);
- return bounds;
-}
-
-#define pppages_pop(pages) (--((pages)->parent), --((pages)->depth))
-
-static ppref * ppdoc_pages_group_first (ppdoc *pdf, ppref *ref)
-{
- ppdict *dict;
- pparray *kids;
- ppuint count;
- ppname type;
-
- dict = ref->object.dict; // typecheck made by callers
- while ((kids = pppage_node(dict, &count, &type)) != NULL)
- {
- if ((ref = pparray_get_ref(kids, 0)) == NULL || ref->object.type != PPDICT)
- return NULL;
- pppages_push(pdf, kids);
- dict = ref->object.dict;
- }
- return ppname_is_page(type) ? ref : NULL;
-}
-
-ppref * ppdoc_first_page (ppdoc *pdf)
-{
- ppref *ref;
- pppages *pages;
- if ((ref = ppdoc_pages(pdf)) == NULL)
- return NULL;
- pages = &pdf->pages;
- pages->parent = pages->root;
- pages->depth = 0;
- return ppdoc_pages_group_first(pdf, ref);
-}
-
-ppref * ppdoc_next_page (ppdoc *pdf)
-{
- pppages *pages;
- ppkids *bounds;
- ppref *ref;
- ppobj *obj;
- pages = &pdf->pages;
- while (pages->depth > 0)
- {
- bounds = pages->parent;
- obj = ++bounds->current;
- if (obj < bounds->sentinel)
- {
- if (obj->type != PPREF)
- return NULL;
- ref = obj->ref;
- if (ref->object.type != PPDICT)
- return NULL;
- return ppdoc_pages_group_first(pdf, ref);
- }
- else
- { // no next node, go upper
- pppages_pop(pages);
- }
- }
- return NULL;
-}
-
-/* context */
-
-ppcontext * ppcontext_new (void)
-{
- ppheap *heap;
- ppcontext *context;
- heap = ppheap_new();
- context = (ppcontext *)pp_malloc(sizeof(ppcontext)); // not from priv heap, as we delete it on renew
- context->heap = heap;
- ppstack_init(&context->stack, &context->heap);
- return context;
-}
-
-void ppcontext_done (ppcontext *context)
-{
- ppheap_renew(context->heap);
- ppstack_clear(&context->stack);
-}
-
-void ppcontext_free (ppcontext *context)
-{
- ppstack_free_buffer(&context->stack);
- ppheap_free(context->heap);
- pp_free(context);
-}
-
-/* page contents streams */
-
-//#define ppcontents_first_stream(array) pparray_rget_stream(array, 0)
-
-static ppstream * ppcontents_first_stream (pparray *array)
-{
- size_t i;
- ppobj *obj;
- ppref *ref;
- for (pparray_first(array, i, obj); i < array->size; pparray_next(i, obj))
- if ((ref = ppobj_get_ref(obj)) != NULL && ref->object.type == PPSTREAM)
- return ref->object.stream;
- return NULL;
-}
-
-static ppstream * ppcontents_next_stream (pparray *array, ppstream *stream)
-{
- size_t i;
- ppobj *obj;
- ppref *ref;
- for (pparray_first(array, i, obj); i < array->size; pparray_next(i, obj))
- if ((ref = ppobj_get_ref(obj)) != NULL && ref->object.type == PPSTREAM && ref->object.stream == stream)
- if (++i < array->size && (ref = ppobj_get_ref(obj + 1)) != NULL && ref->object.type == PPSTREAM)
- return ref->object.stream;
- return NULL;
-}
-
-ppstream * ppcontents_first (ppdict *dict)
-{
- ppobj *contentsobj;
- if ((contentsobj = ppdict_rget_obj(dict, "Contents")) == NULL)
- return NULL;
- switch (contentsobj->type)
- {
- case PPARRAY:
- return ppcontents_first_stream(contentsobj->array);
- case PPSTREAM:
- return contentsobj->stream;
- default:
- break;
- }
- return NULL;
-}
-
-ppstream * ppcontents_next (ppdict *dict, ppstream *stream)
-{
- ppobj *contentsobj;
- if ((contentsobj = ppdict_rget_obj(dict, "Contents")) == NULL)
- return NULL;
- switch (contentsobj->type)
- {
- case PPARRAY:
- return ppcontents_next_stream(contentsobj->array, stream);
- case PPSTREAM:
- break;
- default:
- break;
- }
- return NULL;
-}
-
-static ppobj * ppcontents_op (iof *I, ppstack *stack, size_t *psize, ppname *pname)
-{
- ppobj *obj;
- ppstack_clear(stack);
- do {
- if (ppscan_find(I) < 0)
- return NULL;
- if ((obj = ppscan_psobj(I, stack)) == NULL)
- return NULL;
- } while (obj->type != PPNAME || !ppname_exec(obj->name));
- *pname = obj->name;
- *psize = stack->size - 1;
- return stack->buf;
-}
-
-ppobj * ppcontents_first_op (ppcontext *context, ppstream *stream, size_t *psize, ppname *pname)
-{
- iof *I;
- if ((I = ppstream_read(stream, 1, 0)) == NULL)
- return NULL;
- return ppcontents_op(I, &context->stack, psize, pname);
-}
-
-ppobj * ppcontents_next_op (ppcontext *context, ppstream *stream, size_t *psize, ppname *pname)
-{
- return ppcontents_op(ppstream_iof(stream), &context->stack, psize, pname);
-}
-
-ppobj * ppcontents_parse (ppcontext *context, ppstream *stream, size_t *psize)
-{
- iof *I;
- ppstack *stack;
- ppobj *obj;
- stack = &context->stack;
- ppstack_clear(stack);
- if ((I = ppstream_read(stream, 1, 0)) == NULL)
- return NULL;
- while (ppscan_find(I) >= 0)
- if ((obj = ppscan_psobj(I, stack)) == NULL)
- goto error;
- *psize = stack->size;
- ppstream_done(stream);
- return stack->buf;
-error:
- ppstream_done(stream);
- return NULL;
-}
-
-/* boxes */
-
-pprect * pparray_to_rect (pparray *array, pprect *rect)
-{
- ppobj *obj;
- if (array->size != 4)
- return NULL;
- obj = pparray_at(array, 0);
- if (!ppobj_get_num(obj, rect->lx)) return NULL;
- obj = pparray_at(array, 1);
- if (!ppobj_get_num(obj, rect->ly)) return NULL;
- obj = pparray_at(array, 2);
- if (!ppobj_get_num(obj, rect->rx)) return NULL;
- obj = pparray_at(array, 3);
- if (!ppobj_get_num(obj, rect->ry)) return NULL;
- return rect;
-}
-
-pprect * ppdict_get_rect (ppdict *dict, const char *name, pprect *rect)
-{
- pparray *array;
- return (array = ppdict_rget_array(dict, name)) != NULL ? pparray_to_rect(array, rect) : NULL;
-}
-
-pprect * ppdict_get_box (ppdict *dict, const char *name, pprect *rect)
-{
- do {
- if (ppdict_get_rect(dict, name, rect) != NULL)
- return rect;
- dict = ppdict_rget_dict(dict, "Parent");
- } while (dict != NULL);
- return NULL;
-}
-
-ppmatrix * pparray_to_matrix (pparray *array, ppmatrix *matrix)
-{
- ppobj *obj;
- if (array->size != 6)
- return NULL;
- obj = pparray_at(array, 0);
- if (!ppobj_get_num(obj, matrix->xx)) return NULL;
- obj = pparray_at(array, 1);
- if (!ppobj_get_num(obj, matrix->xy)) return NULL;
- obj = pparray_at(array, 2);
- if (!ppobj_get_num(obj, matrix->yx)) return NULL;
- obj = pparray_at(array, 3);
- if (!ppobj_get_num(obj, matrix->yy)) return NULL;
- obj = pparray_at(array, 4);
- if (!ppobj_get_num(obj, matrix->x)) return NULL;
- obj = pparray_at(array, 5);
- if (!ppobj_get_num(obj, matrix->y)) return NULL;
- return matrix;
-}
-
-ppmatrix * ppdict_get_matrix (ppdict *dict, const char *name, ppmatrix *matrix)
-{
- pparray *array;
- return (array = ppdict_rget_array(dict, name)) != NULL ? pparray_to_matrix(array, matrix) : NULL;
-}
-
-/* logger */
-
-void pplog_callback (pplogger_callback logger, void *alien)
-{
- logger_callback((logger_function)logger, alien);
-}
-
-int pplog_prefix (const char *prefix)
-{
- return logger_prefix(prefix);
-}
-
-/* version */
-
-const char * ppdoc_version_string (ppdoc *pdf)
-{
- return pdf->version;
-}
-
-int ppdoc_version_number (ppdoc *pdf, int *minor)
-{
- *minor = pdf->version[2] - '0';
- return pdf->version[0] - '0';
-}
-
-/* doc info */
-
-size_t ppdoc_file_size (ppdoc *pdf)
-{
- return pdf->filesize;
-}
-
-ppuint ppdoc_objects (ppdoc *pdf)
-{
- ppuint count;
- ppxref *xref;
- for (count = 0, xref = pdf->xref; xref != NULL; xref = xref->prev)
- count += xref->count;
- return count;
-}
-
-size_t ppdoc_memory (ppdoc *pdf, size_t *waste)
-{
- size_t used;
- ppheap *heap;
- used = 0, *waste = 0;
- for (heap = pdf->heap; heap != NULL; heap = heap->prev)
- {
- used += heap->space;
- *waste += heap->size;
- }
- return used;
-}
diff --git a/Build/source/texk/web2c/luatexdir/luatex.c b/Build/source/texk/web2c/luatexdir/luatex.c
index 61b8b95e171..e56779afcaa 100644
--- a/Build/source/texk/web2c/luatexdir/luatex.c
+++ b/Build/source/texk/web2c/luatexdir/luatex.c
@@ -33,8 +33,8 @@
*/
int luatex_version = 111;
-int luatex_revision = '1';
-const char *luatex_version_string = "1.11.1";
+int luatex_revision = '2';
+const char *luatex_version_string = "1.11.2";
const char *engine_name = my_name;
#include <kpathsea/c-ctype.h>
diff --git a/Build/source/texk/web2c/luatexdir/luatex_svnversion.h b/Build/source/texk/web2c/luatexdir/luatex_svnversion.h
index b7d2d9796fe..5f56f480678 100644
--- a/Build/source/texk/web2c/luatexdir/luatex_svnversion.h
+++ b/Build/source/texk/web2c/luatexdir/luatex_svnversion.h
@@ -1 +1 @@
-#define luatex_svn_revision 7215
+#define luatex_svn_revision 7223
diff --git a/Build/source/texk/web2c/luatexdir/tex/dumpdata.c b/Build/source/texk/web2c/luatexdir/tex/dumpdata.c
index 78835d00f6e..fdd586afaf7 100644
--- a/Build/source/texk/web2c/luatexdir/tex/dumpdata.c
+++ b/Build/source/texk/web2c/luatexdir/tex/dumpdata.c
@@ -32,7 +32,7 @@ with LuaTeX; if not, see <http://www.gnu.org/licenses/>.
*/
-#define FORMAT_ID (907+51)
+#define FORMAT_ID (907+52)
#if ((FORMAT_ID>=0) && (FORMAT_ID<=256))
#error Wrong value for FORMAT_ID.
#endif
diff --git a/Build/source/texk/web2c/luatexdir/tex/linebreak.c b/Build/source/texk/web2c/luatexdir/tex/linebreak.c
index d31a63236a8..3da4b1386a0 100644
--- a/Build/source/texk/web2c/luatexdir/tex/linebreak.c
+++ b/Build/source/texk/web2c/luatexdir/tex/linebreak.c
@@ -114,9 +114,9 @@ void line_break(boolean d, int line_break_context)
tail_append(new_penalty(inf_penalty,line_penalty));
} else {
halfword t = alink(cur_list.tail_field);
- flush_node(cur_list.tail_field);
- cur_list.tail_field = t;
- tail_append(new_penalty(inf_penalty,line_penalty));
+ flush_node(cur_list.tail_field);
+ cur_list.tail_field = t;
+ tail_append(new_penalty(inf_penalty,line_penalty));
}
final_par_glue = new_param_glue(par_fill_skip_code);
couple_nodes(cur_list.tail_field, final_par_glue);
@@ -1811,8 +1811,16 @@ static void ext_try_break(
else
d += final_hyphen_demerits;
}
- if (abs(fit_class - fitness(r)) > 1)
- d = d + adj_demerits;
+ /*tex
+
+ Direct calculation of the absolute value of ((|fit_class| - |fitness(r)|) > 1) where
+ |fitness(r)| is an unsigned integral type can lead to unexpected results if
+ |fitness(r)| is not an |int|, due to the rules of integer promotions.
+ It's better to use the equivalent expanded expression.
+ */
+ if ( (fit_class>(fitness(r)+1)) || (fitness(r)>(fit_class+1)) )
+ d = d + adj_demerits;
+
}
if (tracing_paragraphs > 0) {
print_feasible_break(cur_p, r, b, pi, d, artificial_demerits);