diff options
Diffstat (limited to 'Build/source/texk/dvipdfm-x/pdfobj.c')
-rw-r--r-- | Build/source/texk/dvipdfm-x/pdfobj.c | 443 |
1 files changed, 325 insertions, 118 deletions
diff --git a/Build/source/texk/dvipdfm-x/pdfobj.c b/Build/source/texk/dvipdfm-x/pdfobj.c index be799cc2290..a1acf1b5e25 100644 --- a/Build/source/texk/dvipdfm-x/pdfobj.c +++ b/Build/source/texk/dvipdfm-x/pdfobj.c @@ -1,6 +1,6 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2007-2018 by Jin-Hwan Cho and Shunsaku Hirata, + Copyright (C) 2007-2019 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks <mwicks@kettering.edu> @@ -2223,48 +2223,9 @@ pdf_add_stream (pdf_obj *stream, const void *stream_data, int length) #if HAVE_ZLIB #define WBUF_SIZE 4096 -int -pdf_add_stream_flate (pdf_obj *dst, const void *data, int len) -{ - z_stream z; - Bytef wbuf[WBUF_SIZE]; - - z.zalloc = Z_NULL; z.zfree = Z_NULL; z.opaque = Z_NULL; - - z.next_in = (z_const Bytef *) data; z.avail_in = len; - z.next_out = (Bytef *) wbuf; z.avail_out = WBUF_SIZE; - - if (inflateInit(&z) != Z_OK) { - WARN("inflateInit() failed."); - return -1; - } - - for (;;) { - int status; - status = inflate(&z, Z_NO_FLUSH); - if (status == Z_STREAM_END) - break; - else if (status != Z_OK) { - WARN("inflate() failed. Broken PDF file?"); - inflateEnd(&z); - return -1; - } - - if (z.avail_out == 0) { - pdf_add_stream(dst, wbuf, WBUF_SIZE); - z.next_out = wbuf; - z.avail_out = WBUF_SIZE; - } - } - - if (WBUF_SIZE - z.avail_out > 0) - pdf_add_stream(dst, wbuf, WBUF_SIZE - z.avail_out); - - return (inflateEnd(&z) == Z_OK ? 0 : -1); -} static int -get_decode_parms (struct decode_parms *parms, pdf_obj *dict) +filter_get_DecodeParms_FlateDecode (struct decode_parms *parms, pdf_obj *dict) { pdf_obj *tmp; @@ -2278,18 +2239,25 @@ get_decode_parms (struct decode_parms *parms, pdf_obj *dict) parms->columns = 1; tmp = pdf_deref_obj(pdf_lookup_dict(dict, "Predictor")); - if (tmp) + if (tmp) { parms->predictor = pdf_number_value(tmp); + pdf_release_obj(tmp); + } tmp = pdf_deref_obj(pdf_lookup_dict(dict, "Colors")); - if (tmp) + if (tmp) { parms->colors = pdf_number_value(tmp); + pdf_release_obj(tmp); + } tmp = pdf_deref_obj(pdf_lookup_dict(dict, "BitsPerComponent")); - if (tmp) + if (tmp) { parms->bits_per_component = pdf_number_value(tmp); + pdf_release_obj(tmp); + } tmp = pdf_deref_obj(pdf_lookup_dict(dict, "Columns")); - if (tmp) + if (tmp) { parms->columns = pdf_number_value(tmp); - + pdf_release_obj(tmp); + } if (parms->bits_per_component != 1 && parms->bits_per_component != 2 && parms->bits_per_component != 4 && @@ -2354,17 +2322,19 @@ filter_row_TIFF2 (unsigned char *dst, const unsigned char *src, * Especially, calling pdf_add_stream() for each 4 bytes append is highly * inefficient. */ -static int -filter_decoded (pdf_obj *dst, const void *src, int srclen, - struct decode_parms *parms) +static pdf_obj * +filter_stream_decode_Predictor (const void *src, size_t srclen, struct decode_parms *parms) { + pdf_obj *dst; const unsigned char *p = (const unsigned char *) src; const unsigned char *endptr = p + srclen; - unsigned char *prev, *buf; - int bits_per_pixel = parms->colors * parms->bits_per_component; - int bytes_per_pixel = (bits_per_pixel + 7) / 8; - int length = (parms->columns * bits_per_pixel + 7) / 8; - int i, error = 0; + unsigned char *prev, *buf; + int bits_per_pixel = parms->colors * parms->bits_per_component; + int bytes_per_pixel = (bits_per_pixel + 7) / 8; + int length = (parms->columns * bits_per_pixel + 7) / 8; + int i, error = 0; + + dst = pdf_new_stream(0); prev = NEW(length, unsigned char); buf = NEW(length, unsigned char); @@ -2491,16 +2461,21 @@ filter_decoded (pdf_obj *dst, const void *src, int srclen, RELEASE(prev); RELEASE(buf); - return error; + if (error) { + pdf_release_obj(dst); + dst = NULL; + } + + return dst; } -static int -pdf_add_stream_flate_filtered (pdf_obj *dst, const void *data, int len, struct decode_parms *parms) +static pdf_obj * +filter_stream_decode_FlateDecode (const void *data, size_t len, struct decode_parms *parms) { - pdf_obj *tmp; - z_stream z; - Bytef wbuf[WBUF_SIZE]; - int error; + pdf_obj *dst; + pdf_obj *tmp; + z_stream z; + Bytef wbuf[WBUF_SIZE]; z.zalloc = Z_NULL; z.zfree = Z_NULL; z.opaque = Z_NULL; @@ -2509,7 +2484,7 @@ pdf_add_stream_flate_filtered (pdf_obj *dst, const void *data, int len, struct d if (inflateInit(&z) != Z_OK) { WARN("inflateInit() failed."); - return -1; + return NULL; } tmp = pdf_new_stream(0); @@ -2521,7 +2496,8 @@ pdf_add_stream_flate_filtered (pdf_obj *dst, const void *data, int len, struct d else if (status != Z_OK) { WARN("inflate() failed. Broken PDF file?"); inflateEnd(&z); - return -1; + pdf_release_obj(tmp); + return NULL; } if (z.avail_out == 0) { @@ -2534,79 +2510,310 @@ pdf_add_stream_flate_filtered (pdf_obj *dst, const void *data, int len, struct d if (WBUF_SIZE - z.avail_out > 0) pdf_add_stream(tmp, wbuf, WBUF_SIZE - z.avail_out); - error = filter_decoded(dst, pdf_stream_dataptr(tmp), pdf_stream_length(tmp), parms); + if (inflateEnd(&z) == Z_OK) { + if (parms) { + dst = filter_stream_decode_Predictor(pdf_stream_dataptr(tmp), pdf_stream_length(tmp), parms); + } else { + dst = pdf_link_obj(tmp); + } + } else { + dst = NULL; + } pdf_release_obj(tmp); - return ((!error && inflateEnd(&z) == Z_OK) ? 0 : -1); + return dst; } #endif -int -pdf_concat_stream (pdf_obj *dst, pdf_obj *src) +static pdf_obj * +filter_stream_decode_ASCIIHexDecode (const void *data, size_t len) +{ + pdf_obj *dst; + int eod, error; + const char *p = (const char *) data; + const char *endptr = p + len; + unsigned char *buf, ch; + size_t pos, n; + + buf = NEW((len+1)/2, unsigned char); + skip_white(&p, endptr); + ch = 0; n = 0; pos = 0; eod = 0; error = 0; + while (p < endptr && !error && !eod) { + char c1, val; + c1 = p[0]; + if (c1 >= 'A' && c1 <= 'F') { + val = c1 - 'A' + 10; + } else if (c1 >= 'a' && c1 <= 'f') { + val = c1 - 'a' + 10; + } else if (c1 >= '0' && c1 <= '9') { + val = c1 - '0'; + } else if (c1 == '>') { + val = 0; + eod = 1; + if ((pos % 2) == 0) + break; + } else { + error = -1; + break; + } + if (pos % 2) { + buf[n] = ch + val; + n++; + ch = 0; + } else { + ch = val << 4; + } + pos++; p++; + skip_white(&p, endptr); + } + if (error || !eod) { + WARN("Invalid ASCIIHex data seen: %s", error ? "Invalid character" : "No EOD marker"); + dst = NULL; + } else { + dst = pdf_new_stream(0); + pdf_add_stream(dst, buf, n); + } + RELEASE(buf); + + return dst; +} + +/* Percent sign is not start of comment here. + * We need this for reading Ascii85 encoded data. + */ +#define is_space(c) ((c) == ' ' || (c) == '\t' || (c) == '\f' || \ + (c) == '\r' || (c) == '\n' || (c) == '\0') +static void +skip_white_a85 (const char **p, const char *endptr) { + while (*p < endptr && (is_space(**p))) { + (*p)++; + } +} + +static pdf_obj * +filter_stream_decode_ASCII85Decode (const void *data, size_t len) +{ + pdf_obj *dst; + int eod, error; + const char *p = (const char *) data; + const char *endptr = p + len; + unsigned char *buf; + size_t n; + + buf = NEW(((len+4)/5)*4, unsigned char); + skip_white_a85(&p, endptr); + n = 0; eod = 0; error = 0; + while (p < endptr && !error && !eod) { + char q[5] = {'u', 'u', 'u', 'u', 'u'}; + int m; + char ch; + + ch = p[0]; + p++; + skip_white_a85(&p, endptr); + if (ch == 'z') { + memset(buf+n, 0, 4); + n += 4; + continue; + } else if (ch == '~') { + if (p < endptr && p[0] == '>') { + eod = 1; + p++; + } else { + error = -1; + } + break; + } + q[0] = ch; + for (m = 1; m < 5 && p < endptr; m++) { + ch = p[0]; + p++; + skip_white_a85(&p, endptr); + if (ch == '~') { + if (p < endptr && p[0] == '>') { + eod = 1; + p++; + } else { + error = -1; + } + break; + } else if (ch < '!' || ch > 'u') { + error = -1; + break; + } else { + q[m] = ch; + } + } + if (!error) { + uint32_t val = 0; + int i; + if (m <= 1) { + error = -1; + break; + } + val = 85*85*85*(q[0] - '!') + 85*85*(q[1] - '!') + + 85*(q[2] - '!') + (q[3] - '!'); + /* Check overflow */ + if (val > UINT32_MAX / 85) { + error = -1; + break; + } else { + val = 85 * val; + if (val > UINT32_MAX - (q[4] - '!')) { + error = -1; + break; + } + val += (q[4] - '!'); + } + if (!error) { + for (i = 3; i >= 0; i--) { + buf[n + i] = val & 0xff; + val /= 256; + } + n += m - 1; + } + } + } + + if (error) { + WARN("Error in reading ASCII85 data."); + dst = NULL; + } else if (!eod) { + WARN("Error in reading ASCII85 data: No EOD"); + dst = NULL; + } else { + dst = pdf_new_stream(0); + pdf_add_stream(dst, buf, n); + } + RELEASE(buf); + + return dst; +} + +static pdf_obj * +filter_stream_decode (const char *filter_name, pdf_obj *src, pdf_obj *parm) +{ + pdf_obj *dec; const char *stream_data; - int stream_length; - pdf_obj *stream_dict; - pdf_obj *filter; - int error = 0; + size_t stream_length; - if (!PDF_OBJ_STREAMTYPE(dst) || !PDF_OBJ_STREAMTYPE(src)) - ERROR("Invalid type."); + if (!filter_name) + return pdf_link_obj(src); stream_data = pdf_stream_dataptr(src); - stream_length = pdf_stream_length (src); - stream_dict = pdf_stream_dict (src); + stream_length = pdf_stream_length(src); - filter = pdf_lookup_dict(stream_dict, "Filter"); - if (!filter) - pdf_add_stream(dst, stream_data, stream_length); + if (!strcmp(filter_name, "ASCIIHexDecode")) { + dec = filter_stream_decode_ASCIIHexDecode(stream_data, stream_length); + } else if (!strcmp(filter_name, "ASCII85Decode")) { + dec = filter_stream_decode_ASCII85Decode(stream_data, stream_length); #if HAVE_ZLIB - else { - struct decode_parms parms; - int have_parms = 0; + } else if (!strcmp(filter_name, "FlateDecode")) { + struct decode_parms decode_parm; + if (parm) + filter_get_DecodeParms_FlateDecode(&decode_parm, parm); + dec = filter_stream_decode_FlateDecode(stream_data, stream_length, parm ? &decode_parm : NULL); +#endif /* HAVE_ZLIB */ + } else { + WARN("DecodeFilter \"%s\" not supported.", filter_name); + dec = NULL; + } - if (pdf_lookup_dict(stream_dict, "DecodeParms")) { - pdf_obj *tmp; + return dec; +} - /* Dictionary or array */ - tmp = pdf_deref_obj(pdf_lookup_dict(stream_dict, "DecodeParms")); - if (PDF_OBJ_ARRAYTYPE(tmp)) { - if (pdf_array_length(tmp) > 1) { - WARN("Unexpected size for DecodeParms array."); - return -1; - } - tmp = pdf_deref_obj(pdf_get_array(tmp, 0)); - } - if (!PDF_OBJ_DICTTYPE(tmp)) { - WARN("PDF dict expected for DecodeParms..."); - return -1; - } - error = get_decode_parms(&parms, tmp); - if (error) - ERROR("Invalid value(s) in DecodeParms dictionary."); - have_parms = 1; - } - if (PDF_OBJ_ARRAYTYPE(filter)) { - if (pdf_array_length(filter) > 1) { - WARN("Multiple DecodeFilter not supported."); +int +pdf_concat_stream (pdf_obj *dst, pdf_obj *src) +{ + pdf_obj *filtered; + pdf_obj *stream_dict; + pdf_obj *filter, *parms; + int error = 0; + + if (!PDF_OBJ_STREAMTYPE(dst) || !PDF_OBJ_STREAMTYPE(src)) { + WARN("Passed invalid type in pdf_concat_stream()."); + return -1; + } + + stream_dict = pdf_stream_dict(src); + + filter = pdf_lookup_dict(stream_dict, "Filter"); + if (!filter) { + pdf_add_stream(dst, pdf_stream_dataptr(src), pdf_stream_length(src)); + return 0; + } + if (pdf_lookup_dict(stream_dict, "DecodeParms")) { + /* Dictionary or array */ + parms = pdf_deref_obj(pdf_lookup_dict(stream_dict, "DecodeParms")); + if (!parms) { + WARN("Failed to deref DeocdeParms..."); + return -1; + } else if (!PDF_OBJ_ARRAYTYPE(parms) && !PDF_OBJ_DICTTYPE(parms)) { + WARN("PDF dict or array expected for DecodeParms..."); + pdf_release_obj(parms); + return -1; + } + } else { + parms = NULL; + } + if (PDF_OBJ_ARRAYTYPE(filter)) { + int i, num; + pdf_obj *prev = NULL; + + num = pdf_array_length(filter); + if (parms) { + if (!PDF_OBJ_ARRAYTYPE(parms) || pdf_array_length(parms) != num) { + WARN("Invalid DecodeParam object found."); + pdf_release_obj(parms); return -1; } - filter = pdf_get_array(filter, 0); } - if (PDF_OBJ_NAMETYPE(filter)) { - char *filter_name = pdf_name_value(filter); - if (filter_name && !strcmp(filter_name, "FlateDecode")) { - if (have_parms) - error = pdf_add_stream_flate_filtered(dst, stream_data, stream_length, &parms); - else - error = pdf_add_stream_flate(dst, stream_data, stream_length); - } else { - WARN("DecodeFilter \"%s\" not supported.", filter_name); - error = -1; + if (num == 0) { + filtered = pdf_link_obj(src); + } else { + filtered = NULL; + prev = pdf_link_obj(src); + for (i = 0; i < num && prev != NULL; i++) { + pdf_obj *tmp1, *tmp2; + + tmp1 = pdf_deref_obj(pdf_get_array(filter, i)); + if (parms) { + tmp2 = pdf_deref_obj(pdf_get_array(parms, i)); + } else { + tmp2 = NULL; + } + if (PDF_OBJ_NAMETYPE(tmp1)) { + filtered = filter_stream_decode(pdf_name_value(tmp1), prev, tmp2); + } else if (PDF_OBJ_NULLTYPE(tmp1)) { + filtered = pdf_link_obj(prev); + } else { + WARN("Unexpected object found for /Filter..."); + filtered = NULL; + } + if (prev) + pdf_release_obj(prev); + if (tmp1) + pdf_release_obj(tmp1); + if (tmp2) + pdf_release_obj(tmp2); + prev = filtered; } - } else - ERROR("Broken PDF file?"); -#endif /* HAVE_ZLIB */ + } + } else if (PDF_OBJ_NAMETYPE(filter)) { + filtered = filter_stream_decode(pdf_name_value(filter), src, parms); + } else { + WARN("Invalid value for /Filter found."); + filtered = NULL; + } + if (parms) + pdf_release_obj(parms); + if (filtered) { + pdf_add_stream(dst, pdf_stream_dataptr(filtered), pdf_stream_length(filtered)); + pdf_release_obj(filtered); + error = 0; + } else { + error = -1; } return error; |