diff options
Diffstat (limited to 'Build')
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", §ionmock[1].integer)) - sectionmock[1].integer = 0; - sectionfirst = §ionmock[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); |