diff options
Diffstat (limited to 'Build')
5 files changed, 0 insertions, 7818 deletions
diff --git a/Build/source/texk/web2c/luatexdir/luapplib/ppapi.h-OK b/Build/source/texk/web2c/luatexdir/luapplib/ppapi.h-OK deleted file mode 100644 index eec45c8c2a5..00000000000 --- a/Build/source/texk/web2c/luatexdir/luapplib/ppapi.h-OK +++ /dev/null @@ -1,360 +0,0 @@ - -#ifndef PP_API_H -#define PP_API_H - -#include <stdint.h> -#include <stddef.h> -#include <string.h> - -#include "ppconf.h" - -#define pplib_version "v0.97" -#define pplib_author "p.jackowski@gust.org.pl" - -/* types */ - -typedef int64_t ppint; -typedef size_t ppuint; // machine word - -typedef double ppnum; -typedef char * ppname; -typedef char * ppstring; - -typedef struct { - size_t size; - int flags; -} _ppname; - -typedef struct { - size_t size; - int flags; -} _ppstring; - -typedef struct ppobj ppobj; -typedef struct ppref ppref; - -typedef struct { - ppobj *data; - size_t size; -} pparray; - -typedef struct { - ppobj *data; - ppname *keys; - size_t size; -} ppdict; - -typedef struct { - ppdict *dict; - void *input, *I; - size_t offset; - size_t length; - ppstring cryptkey; - int flags; -} ppstream; - -#define PPSTREAM_COMPRESSED (1<<0) -#define PPSTREAM_ENCRYPTED_AES (1<<1) -#define PPSTREAM_ENCRYPTED_RC4 (1<<2) -#define PPSTREAM_ENCRYPTED (PPSTREAM_ENCRYPTED_AES|PPSTREAM_ENCRYPTED_RC4) -#define PPSTREAM_ENCRYPTED_OWN (1<<3) - -#define ppstream_compressed(stream) ((stream)->flags & PPSTREAM_COMPRESSED) -#define ppstream_encrypted(stream) ((stream)->flags & PPSTREAM_ENCRYPTED) - -typedef enum { - PPNONE = 0, - PPNULL, - PPBOOL, - PPINT, - PPNUM, - PPNAME, - PPSTRING, - PPARRAY, - PPDICT, - PPSTREAM, - PPREF -} ppobjtp; - -PPDEF extern const char * ppobj_kind[]; - -struct ppobj { - ppobjtp type; - union { - ppint integer; - ppnum number; - ppname name; - ppstring string; - pparray *array; - ppdict *dict; - ppstream *stream; - ppref *ref; - void *any; - }; -}; - -typedef struct ppxref ppxref; - -struct ppref { - ppobj object; - ppuint number, version; - size_t offset; - size_t length; - ppxref *xref; -}; - -typedef struct ppdoc ppdoc; - -/* object */ - -#define ppobj_get_null(o) ((o)->type == PPNULL ? 1 : 0) -#define ppobj_get_bool(o, v) ((o)->type == PPBOOL ? ((v = ((o)->integer != 0)), 1) : 0) -#define ppobj_get_int(o, v) ((o)->type == PPINT ? ((v = (o)->integer), 1) : 0) -#define ppobj_get_uint(o, v) ((o)->type == PPINT && (o)->integer >= 0 ? ((v = (ppuint)((o)->integer)), 1) : 0) -#define ppobj_get_num(o, v) ((o)->type == PPNUM ? ((v = (o)->number), 1) : (((o)->type == PPINT ? ((v = (ppnum)((o)->integer)), 1) : 0))) -#define ppobj_get_name(o) ((o)->type == PPNAME ? (o)->name : NULL) -#define ppobj_get_string(o) ((o)->type == PPSTRING ? (o)->string : NULL) -#define ppobj_get_array(o) ((o)->type == PPARRAY ? (o)->array : NULL) -#define ppobj_get_dict(o) ((o)->type == PPDICT ? (o)->dict : NULL) -#define ppobj_get_stream(o) ((o)->type == PPSTREAM ? (o)->stream : NULL) -#define ppobj_get_ref(o) ((o)->type == PPREF ? (o)->ref : NULL) - -#define ppobj_rget_obj(o) ((o)->type == PPREF ? ppref_obj((o)->ref) : o) -#define ppobj_rget_null(o) ((o)->type == PPNULL ? 1 : ((o)->type == PPREF ? ppobj_get_null(ppref_obj((o)->ref)) : 0)) -#define ppobj_rget_bool(o, v) ((o)->type == PPBOOL ? ((v = ((o)->integer != 0)), 1) : ((o)->type == PPREF ? ppobj_get_bool(ppref_obj((o)->ref), v) : 0)) -#define ppobj_rget_int(o, v) ((o)->type == PPINT ? ((v = (o)->integer), 1) : ((o)->type == PPREF ? ppobj_get_int(ppref_obj((o)->ref), v) : 0)) -#define ppobj_rget_uint(o, v) ((o)->type == PPINT && (o)->integer >= 0 ? ((v = (ppuint)((o)->integer)), 1) : ((o)->type == PPREF ? ppobj_get_uint(ppref_obj((o)->ref), v) : 0)) -#define ppobj_rget_num(o, v) ((o)->type == PPNUM ? ((v = (o)->number), 1) : (((o)->type == PPINT ? ((v = (ppnum)((o)->integer)), 1) : ((o)->type == PPREF ? ppobj_get_num(ppref_obj((o)->ref), v) : 0)))) -#define ppobj_rget_name(o) ((o)->type == PPNAME ? (o)->name : ((o)->type == PPREF ? ppobj_get_name(ppref_obj((o)->ref)) : NULL)) -#define ppobj_rget_string(o) ((o)->type == PPSTRING ? (o)->string : ((o)->type == PPREF ? ppobj_get_string(ppref_obj((o)->ref)) : NULL)) -#define ppobj_rget_array(o) ((o)->type == PPARRAY ? (o)->array : ((o)->type == PPREF ? ppobj_get_array(ppref_obj((o)->ref)) : NULL)) -#define ppobj_rget_dict(o) ((o)->type == PPDICT ? (o)->dict : ((o)->type == PPREF ? ppobj_get_dict(ppref_obj((o)->ref)) : NULL)) -#define ppobj_rget_stream(o) ((o)->type == PPSTREAM ? (o)->stream : ((o)->type == PPREF ? ppobj_get_stream(ppref_obj((o)->ref)) : NULL)) -#define ppobj_rget_ref(o) ((o)->type == PPREF ? (o)->ref : ((o)->type == PPREF ? ppobj_get_ref(ppref_obj((o)->ref)) : NULL)) - -#define ppobj_get_bool_value(o) ((o)->type == PPBOOL ? ((o)->integer != 0) : 0) -#define ppobj_get_int_value(o) ((o)->type == PPINT ? (o)->integer : 0) -#define ppobj_get_num_value(o) ((o)->type == PPNUM ? (o)->number : ((o)->type == PPINT ? (ppnum)((o)->integer) : 0.0)) - -/* name */ - -#define ppname_is(name, s) (memcmp(name, s, sizeof("" s) - 1) == 0) -#define ppname_eq(name, n) (memcmp(name, s, ppname_size(name)) == 0) - -#define _ppname_ghost(name) (((const _ppname *)(name)) - 1) -#define ppname_size(name) (_ppname_ghost(name)->size) -#define ppname_exec(name) (_ppname_ghost(name)->flags & PPNAME_EXEC) - -#define PPNAME_ENCODED (1 << 0) -#define PPNAME_DECODED (1 << 1) -#define PPNAME_EXEC (1 << 1) - -PPAPI ppname ppname_decoded (ppname name); -PPAPI ppname ppname_encoded (ppname name); - -/* string */ - -#define _ppstring_ghost(string) (((const _ppstring *)(string)) - 1) -#define ppstring_size(string) (_ppstring_ghost(string)->size) - -#define PPSTRING_ENCODED (1 << 0) -#define PPSTRING_DECODED (1 << 1) -//#define PPSTRING_EXEC (1 << 2) // postscript only -#define PPSTRING_PLAIN 0 -#define PPSTRING_BASE16 (1 << 3) -#define PPSTRING_BASE85 (1 << 4) -#define PPSTRING_UTF16BE (1 << 5) -#define PPSTRING_UTF16LE (1 << 6) - -#define ppstring_type(string) (_ppstring_ghost(string)->flags & (PPSTRING_BASE16|PPSTRING_BASE85)) -#define ppstring_hex(string) (_ppstring_ghost(string)->flags & PPSTRING_BASE16) -#define ppstring_utf(string) (_ppstring_ghost(string)->flags & (PPSTRING_UTF16BE|PPSTRING_UTF16LE)) - -PPAPI ppstring ppstring_decoded (ppstring string); -PPAPI ppstring ppstring_encoded (ppstring string); - -/* array */ - -#define pparray_size(array) ((array)->size) -#define pparray_at(array, index) ((array)->data + index) - -#define pparray_first(array, index, obj) ((index) = 0, (obj) = pparray_at(array, 0)) -#define pparray_next(index, obj) (++(index), ++(obj)) - -#define pparray_get(array, index) (index < (array)->size ? pparray_at(array, index) : NULL) - -PPAPI ppobj * pparray_get_obj (pparray *array, size_t index); -PPAPI int pparray_get_bool (pparray *array, size_t index, int *v); -PPAPI int pparray_get_int (pparray *array, size_t index, ppint *v); -PPAPI int pparray_get_uint (pparray *array, size_t index, ppuint *v); -PPAPI int pparray_get_num (pparray *array, size_t index, ppnum *v); -PPAPI ppname pparray_get_name (pparray *array, size_t index); -PPAPI ppstring pparray_get_string (pparray *array, size_t index); -PPAPI pparray * pparray_get_array (pparray *array, size_t index); -PPAPI ppdict * pparray_get_dict (pparray *array, size_t index); -//PPAPI ppstream * pparray_get_stream (pparray *array, size_t index); -PPAPI ppref * pparray_get_ref (pparray *array, size_t index); - -PPAPI ppobj * pparray_rget_obj (pparray *array, size_t index); -PPAPI int pparray_rget_bool (pparray *array, size_t index, int *v); -PPAPI int pparray_rget_int (pparray *array, size_t index, ppint *v); -PPAPI int pparray_rget_uint (pparray *array, size_t index, ppuint *v); -PPAPI int pparray_rget_num (pparray *array, size_t index, ppnum *v); -PPAPI ppname pparray_rget_name (pparray *array, size_t index); -PPAPI ppstring pparray_rget_string (pparray *array, size_t index); -PPAPI pparray * pparray_rget_array (pparray *array, size_t index); -PPAPI ppdict * pparray_rget_dict (pparray *array, size_t index); -PPAPI ppstream * pparray_rget_stream (pparray *array, size_t index); -PPAPI ppref * pparray_rget_ref (pparray *array, size_t index); - -/* dict */ - -#define ppdict_size(dict) ((dict)->size) -#define ppdict_at(dict, index) ((dict)->data + index) -#define ppdict_key(dict, index) ((dict)->keys[index]) - -PPAPI ppobj * ppdict_get_obj (ppdict *dict, const char *name); -PPAPI int ppdict_get_bool (ppdict *dict, const char *name, int *v); -PPAPI int ppdict_get_int (ppdict *dict, const char *name, ppint *v); -PPAPI int ppdict_get_uint (ppdict *dict, const char *name, ppuint *v); -PPAPI int ppdict_get_num (ppdict *dict, const char *name, ppnum *v); -PPAPI ppname ppdict_get_name (ppdict *dict, const char *name); -PPAPI ppstring ppdict_get_string (ppdict *dict, const char *name); -PPAPI pparray * ppdict_get_array (ppdict *dict, const char *name); -PPAPI ppdict * ppdict_get_dict (ppdict *dict, const char *name); -//PPAPI ppstream * ppdict_get_stream (ppdict *dict, const char *name); -PPAPI ppref * ppdict_get_ref (ppdict *dict, const char *name); - -PPAPI ppobj * ppdict_rget_obj (ppdict *dict, const char *name); -PPAPI int ppdict_rget_bool (ppdict *dict, const char *name, int *v); -PPAPI int ppdict_rget_int (ppdict *dict, const char *name, ppint *v); -PPAPI int ppdict_rget_uint (ppdict *dict, const char *name, ppuint *v); -PPAPI int ppdict_rget_num (ppdict *dict, const char *name, ppnum *v); -PPAPI ppname ppdict_rget_name (ppdict *dict, const char *name); -PPAPI ppstring ppdict_rget_string (ppdict *dict, const char *name); -PPAPI pparray * ppdict_rget_array (ppdict *dict, const char *name); -PPAPI ppdict * ppdict_rget_dict (ppdict *dict, const char *name); -PPAPI ppstream * ppdict_rget_stream (ppdict *dict, const char *name); -PPAPI ppref * ppdict_rget_ref (ppdict *dict, const char *name); - -#define ppdict_first(dict, pkey, obj) (pkey = (dict)->keys, obj = (dict)->data) -#define ppdict_next(pkey, obj) (++(pkey), ++(obj)) - -/* stream */ - -#define ppstream_dict(stream) ((stream)->dict) - -PPAPI uint8_t * ppstream_first (ppstream *stream, size_t *size, int decode); -PPAPI uint8_t * ppstream_next (ppstream *stream, size_t *size); -PPAPI uint8_t * ppstream_all (ppstream *stream, size_t *size, int decode); -PPAPI void ppstream_done (ppstream *stream); - -PPAPI void ppstream_init_buffers (void); -PPAPI void ppstream_free_buffers (void); - -/* ref */ - -#define ppref_obj(ref) (&(ref)->object) - -/* xref */ - -PPAPI ppxref * ppdoc_xref (ppdoc *pdf); -PPAPI ppxref * ppxref_prev (ppxref *xref); -PPAPI ppdict * ppxref_trailer (ppxref *xref); -PPAPI ppdict * ppxref_catalog (ppxref *xref); -PPAPI ppdict * ppxref_info (ppxref *xref); -PPAPI ppref * ppxref_pages (ppxref *xref); -PPAPI ppref * ppxref_find (ppxref *xref, ppuint refnumber); - -/* doc */ - -PPAPI ppdoc * ppdoc_load (const char *filename); -PPAPI ppdoc * ppdoc_mem (const void *data, size_t size); -PPAPI void ppdoc_free (ppdoc *pdf); - -#define ppdoc_trailer(pdf) ppxref_trailer(ppdoc_xref(pdf)) -#define ppdoc_catalog(pdf) ppxref_catalog(ppdoc_xref(pdf)) -#define ppdoc_info(pdf) ppxref_info(ppdoc_xref(pdf)) -#define ppdoc_pages(pdf) ppxref_pages(ppdoc_xref(pdf)) - -PPAPI ppuint ppdoc_page_count (ppdoc *pdf); -PPAPI ppref * ppdoc_page (ppdoc *pdf, ppuint index); -PPAPI ppref * ppdoc_first_page (ppdoc *pdf); -PPAPI ppref * ppdoc_next_page (ppdoc *pdf); - -PPAPI ppstream * ppcontents_first (ppdict *dict); -PPAPI ppstream * ppcontents_next (ppdict *dict, ppstream *stream); - -/* crypt */ - -typedef enum { - PPCRYPT_NONE = 0, - PPCRYPT_DONE = 1, - PPCRYPT_FAIL = -1, - PPCRYPT_PASS = -2 -} ppcrypt_status; - -PPAPI ppcrypt_status ppdoc_crypt_status (ppdoc *pdf); -PPAPI ppcrypt_status ppdoc_crypt_pass (ppdoc *pdf, const void *userpass, size_t userpasslength, const void *ownerpass, size_t ownerpasslength); - -/* permission flags, effect in Acrobat File -> Properties -> Security tab */ - -PPAPI ppint ppdoc_permissions (ppdoc *pdf); - -#define PPDOC_ALLOW_PRINT (1<<2) // printing -#define PPDOC_ALLOW_MODIFY (1<<3) // filling form fields, signing, creating template pages -#define PPDOC_ALLOW_COPY (1<<4) // copying, copying for accessibility -#define PPDOC_ALLOW_ANNOTS (1<<5) // filling form fields, copying, signing -#define PPDOC_ALLOW_EXTRACT (1<<9) // contents copying for accessibility -#define PPDOC_ALLOW_ASSEMBLY (1<<10) // (no effect) -#define PPDOC_ALLOW_PRINT_HIRES (1<<11) // (no effect) - -/* context */ - -typedef struct ppcontext ppcontext; - -PPAPI ppcontext * ppcontext_new (void); -PPAPI void ppcontext_done (ppcontext *context); -PPAPI void ppcontext_free (ppcontext *context); - -/* contents parser */ - -PPAPI ppobj * ppcontents_first_op (ppcontext *context, ppstream *stream, size_t *psize, ppname *pname); -PPAPI ppobj * ppcontents_next_op (ppcontext *context, ppstream *stream, size_t *psize, ppname *pname); -PPAPI ppobj * ppcontents_parse (ppcontext *context, ppstream *stream, size_t *psize); - -/* boxes and transforms */ - -typedef struct { - ppnum lx, ly, rx, ry; -} pprect; - -PPAPI pprect * pparray_to_rect (pparray *array, pprect *rect); -PPAPI pprect * ppdict_get_rect (ppdict *dict, const char *name, pprect *rect); -PPAPI pprect * ppdict_get_box (ppdict *dict, const char *name, pprect *rect); - -typedef struct { - ppnum xx, xy, yx, yy, x, y; -} ppmatrix; - -PPAPI ppmatrix * pparray_to_matrix (pparray *array, ppmatrix *matrix); -PPAPI ppmatrix * ppdict_get_matrix (ppdict *dict, const char *name, ppmatrix *matrix); - -/* logger */ - -typedef void (*pplogger_callback) (const char *message, void *alien); -PPAPI void pplog_callback (pplogger_callback logger, void *alien); -PPAPI int pplog_prefix (const char *prefix); - -/* version */ - -PPAPI const char * ppdoc_version_string (ppdoc *pdf); -PPAPI int ppdoc_version_number (ppdoc *pdf, int *minor); - -/* doc info */ - -PPAPI size_t ppdoc_file_size (ppdoc *pdf); -PPAPI ppuint ppdoc_objects (ppdoc *pdf); -PPAPI size_t ppdoc_memory (ppdoc *pdf, size_t *waste); - -#endif diff --git a/Build/source/texk/web2c/luatexdir/luapplib/ppload.c-OK b/Build/source/texk/web2c/luatexdir/luapplib/ppload.c-OK deleted file mode 100644 index fda726656ab..00000000000 --- a/Build/source/texk/web2c/luatexdir/luapplib/ppload.c-OK +++ /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/luapplib/util/utilfpred.c-OK b/Build/source/texk/web2c/luatexdir/luapplib/util/utilfpred.c-OK deleted file mode 100644 index 8e45ed6c252..00000000000 --- a/Build/source/texk/web2c/luatexdir/luapplib/util/utilfpred.c-OK +++ /dev/null @@ -1,767 +0,0 @@ -/* predictor filters; common for flate and lzw */ - -#include "utilmem.h" -#include "utillog.h" -#include "utilfpred.h" - -/* -Here we implement predictor filters used with flate and lzw compressions in PDF streams. The main idea of data prediction -is to compute and output the differences between data records instead of this records. Adjacent pixels in images are usually -similar, so differences between pixel values tends to be zero. And both Flate and LZW performs better when the input -is rather smooth. Although a preliminary use of predictors is related to bitmap data, The actual need for predictor filter -came from the fact that xref streams may also be predicted (usually with PNG up-predictor). - -PDF specification allows to use several predictor algorithms, specified by /Predictor key in /DecodeParms dictionary: - - 1 - no predictor (default) - 2 - TIFF horizontal predictor - 10 - PNG none predictor - 11 - PNG sub predictor - 12 - PNG up predictor - 13 - PNG average predictor - 14 - PNG paeth predictor - -All PNG predictors works on bytes, regardless the image color-depth. While encoding, every input data byte is decreased -by the appropriate byte of the previous pixel. Even if the pixel does not fit a full byte, PNG predictors use an artificial -pixel size rounded up to a full byte. PNG predictors utilizes previous (left) pixel, pixel above and previous to above -pixel. In case of PNG, the type of the predictor is written on a dedicated byte on the beginning of every scanline. It -means all predictor functions must maintain and information about left, above and left-above pixels. - -Despite the same differencing idea, TIFF predictors are different. The prediction process bases on pixel components, -which are not necessarily bytes (component of a pixel is added/substracted from a relevant component of a previous -pixel). In TIFF predictor 2, only the previous (the left) pixel is taken into account, there is no need to keep -an information about other surrounding pixels. Also there is no expicit algorithm marker in data; the same prediction -method is applied to all input rows. - -Not surprisingly, predictor encoders and decoders are pretty similar. Encoders take some input value and the previous -input value (or 0 at the beginning of the scanline) and output a difference between them. Decoders takes an input value, -previously decoded value (or zero) and outputs their sum. When encoding, the result is cast to the proper unsigned integer, -when decoding, modulo 256 (or appropriate) is used, which makes encoding and decoding looseless. - -Some extra bits trickery is involved in TIFF predictor function, when components doesn't fit bytes boundary. In that case, -an input is treated as an bits stream. Every input byte is "buffered" in a larger integer, as its lower bits (from right). -Every output value is taken from its higher (left) bits. In a special case of bits-per-component equal 1, we buffer all -pixel bits and use XOR to compute bits difference between pixels. I've excerpted that trick from poppler, but I'm not -really sure if it works any better, especially when the number of components per pixel is 1. In that case we do a hard -bit-by-bit work anyway. - -Predictor codecs state keeps a notion of surrounding pixels. PNG predictors uses left, up and upleft -pixel data, while TIFF predictor (2) only needs the previous (left) pixel. Important to note that PNG -predictors always work on bytes, no matter of color-depth (bits per component), while TIFF predictor -works on pixel components, which not necessarily fits into a complete byte. However, for PNG predictor -the size of a pixel still matters, because 'left' and 'upleft' refers to a corresponding pixel byte, -not necessarily previous byte. - -In PNG prediction, we record every pixel byte (in decoded form) in state->rowsave. At the end of a scanline -we copy state->rowsave to state->rowup, so that in the next scanline we can access up-pixel byte. -Left pixel byte is accessed as state->rowsave (the byte recently stored or virtual left edge byte \0). -Up-left pixel byte is accessed via state->rowup, but with state->pixelsize offset (same as left byte, possibly \0 -at the left edge of the row). Both state->rowup and state->rowsave has a safe span of pixelsize bytes on the left, -that are permanently \0. -*/ - -#define predictor_component_t unsigned short -#define predictor_pixel1b_t unsigned int - -typedef struct predictor_state { - int default_predictor; /* default predictor indicator */ - int current_predictor; /* current predictor, possibly taken from algorithm marker in PNG data */ - int rowsamples; /* number of pixels in a scanline (/DecodeParms << /Columns ... >>) */ - int compbits; /* number of bits per component (/DecodeParms << /BitsPerComponent ... >>) */ - int components; /* number of components (/DecodeParms << /Colors ... >>) */ - uint8_t *buffer; /* temporary private buffer area */ - uint8_t *rowin; /* an input row buffer position */ - int rowsize; /* size of a current scanline in bytes (rounded up) */ - int rowend; /* an input buffer end position */ - int rowindex; /* an output buffer position */ - union { - struct { /* used by PNG predictor codecs */ - uint8_t *rowup, *rowsave; /* previous scanline buffers */ - int predictorbyte; /* flag indicating that algorithm byte is read/written */ - int pixelsize; /* number of bytes per pixel (rounded up) */ - }; - struct { /* used by TIFF predictor codecs */ - union { - predictor_component_t *prevcomp; /* an array of left pixel components */ - predictor_pixel1b_t *prevpixel; /* left pixel value stored on a single integer (for 1bit color-depth) */ - }; - int compin, compout; /* bit stream buffers */ - int bitsin, bitsout; /* bit stream counters */ - int sampleindex; /* pixel counter */ - int compindex; /* component counter */ - int pixbufsize; /* size of pixel buffer in bytes */ - }; - }; - int flush; - int status; -} predictor_state; - -enum { - STATUS_LAST = 0, - STATUS_CONTINUE = 1 // any value different then IOFEOF, IOFERR, ... -}; - -predictor_state * predictor_decoder_init (predictor_state *state, int predictor, int rowsamples, int components, int compbits) -{ - int rowsize, pixelsize; -#define storage_pos(b, p, size) ((b = p), (p += size)) - uint8_t *buffer, *p; - size_t buffersize; - - pixelsize = (components * compbits + 7) >> 3; // to bytes, rounded up - rowsize = (rowsamples * components * compbits + 7) >> 3; - - state->default_predictor = state->current_predictor = predictor; - state->rowsamples = rowsamples; - state->components = components; - state->compbits = compbits; - - if (predictor == 2) - { /* tiff predictor */ - size_t compbuf, pixbuf; - compbuf = state->components * sizeof(predictor_component_t); - pixbuf = 1 * sizeof(predictor_pixel1b_t); - state->pixbufsize = (int)(compbuf > pixbuf ? compbuf : pixbuf); - buffersize = rowsize + state->pixbufsize; - buffer = (uint8_t *)util_calloc(buffersize, 1); - state->prevcomp = (predictor_component_t *)(state->rowin + rowsize); - state->sampleindex = state->compindex = 0; - state->bitsin = state->bitsout = 0; - state->compin = state->compout = 0; - } - else - { /* png predictors */ - buffersize = (3 * rowsize + 2 * pixelsize + 1) * sizeof(uint8_t); - p = buffer = (uint8_t *)util_calloc(buffersize, 1); - storage_pos(state->rowin, p, 1 + rowsize); // one extra byte for prediction algorithm tag - p += pixelsize; // pixelsize extra bytes for virtual left pixel at the edge, eg. rowup[-1] (permanently \0) - storage_pos(state->rowup, p, rowsize); // actual row byte - p += pixelsize; // ditto - storage_pos(state->rowsave, p, rowsize); - state->pixelsize = pixelsize; - state->predictorbyte = 0; - } - state->buffer = buffer; - state->rowsize = rowsize; - state->rowindex = 0; - state->rowend = 0; - state->status = STATUS_CONTINUE; - return state; -} - -predictor_state * predictor_encoder_init (predictor_state *state, int predictor, int rowsamples, int components, int compbits) -{ - return predictor_decoder_init(state, predictor, rowsamples, components, compbits); -} - -void predictor_decoder_close (predictor_state *state) -{ - util_free(state->buffer); -} - -void predictor_encoder_close (predictor_state *state) -{ - util_free(state->buffer); -} - -/* -Predictor type identifiers (pdf spec 76). lpdf doesn't hire the codec if predictor is 1. Predictor 15 indicates -that the type of PNG prediction algorithm may change in subsequent lines. We always check algorithm marker anyway. -*/ - -enum predictor_code { - NONE_PREDICTOR = 1, - TIFF_PREDICTOR = 2, - PNG_NONE_PREDICTOR = 10, - PNG_SUB_PREDICTOR = 11, - PNG_UP_PREDICTOR = 12, - PNG_AVERAGE_PREDICTOR = 13, - PNG_PAETH_PREDICTOR = 14, - PNG_OPTIMUM_PREDICTOR = 15 -}; - -/* -All predoctor codecs first read the entire data row into a buffer. This is not crucial for the process, -but allows to separate read/write states. In particular, there is one place in which codec functions -may return on EOD. -*/ - -#define start_row(state) (state->rowindex = 0, state->rowin = state->buffer) - -static int read_scanline (predictor_state *state, iof *I, int size) -{ - int rowtail, left; - while ((rowtail = size - state->rowend) > 0) - { - left = (int)iof_left(I); - if (left >= rowtail) - { - memcpy(state->buffer + state->rowend, I->pos, (size_t)rowtail); - state->rowend += rowtail; - I->pos += rowtail; - start_row(state); - break; - } - else - { - if ((rowtail = left) > 0) - { - memcpy(state->buffer + state->rowend, I->pos, (size_t)rowtail); - state->rowend += rowtail; - I->pos += rowtail; - } - if (iof_input(I) == 0) - { - if (state->rowend == 0) // no scanline to process, no more input - return state->flush ? IOFEOF : IOFEMPTY; - /* If we are here, there is an incomplete scanline in buffer: - - if there is a chance for more (state->flush == 0), than wait for more - - otherwise encode/decode the last incomplete line? - pdf spec p. 76 says that "A row occupies a whole number of bytes", - so this situation should be considered abnormal (not found so far). - */ - if (!state->flush) - return IOFEMPTY; - loggerf("incomplete scanline in predictor filter"); - //return IOFERR; - state->status = STATUS_LAST; - state->rowsize -= size - state->rowend; - start_row(state); - break; - } - } - } - return STATUS_CONTINUE; -} - -#define read_row(state, I, size, status) if ((status = read_scanline(state, I, size)) != STATUS_CONTINUE) return status - -#define ensure_output_bytes(O, n) if (!iof_ensure(O, n)) return IOFFULL - -#define tobyte(c) ((unsigned char)(c)) -#define tocomp(c) ((unsigned short)(c)) - -#define row_byte(state) (state->rowin[state->rowindex]) - -#define up_pixel_byte(state) (state->rowup[state->rowindex]) -#define upleft_pixel_byte(state) (state->rowup[state->rowindex - state->pixelsize]) -#define left_pixel_byte(state) (state->rowsave[state->rowindex - state->pixelsize]) - -#define save_pixel_byte(state, c) (state->rowsave[state->rowindex] = c) - -#define left_pixel_component(state) (state->prevcomp[state->compindex]) // tiff predictor with 2, 4, 8, 16 components -#define left_pixel_value(state) (state->prevpixel[0]) // tiff predictor with 1bit components - -#define save_pixel_component(state, c) ((void)\ - ((state->prevcomp[state->compindex] = c), \ - (++state->compindex < state->components || (state->compindex = 0)))) - -#define save_pixel_value(state, c) (state->prevpixel[0] = c) - -/* Once the codec function is done with the scanline, we set imaginary left pixel data to zero, and reset row counters to -zero in order to allow buffering another input scanline. */ - -#define reset_row(state) state->rowend = 0 - -#define reset_png_row(state) (memcpy(state->rowup, state->rowsave, state->rowsize), state->predictorbyte = 0, reset_row(state)) - -#define reset_tiff_row(state) \ - memset(state->prevcomp, 0, state->pixbufsize), \ - state->bitsin = state->bitsout = 0, \ - state->compin = state->compout = 0, \ - reset_row(state), \ - state->sampleindex = state->compindex = 0 - -/* PNG paeth predictor function; http://www.libpng.org/pub/png/book/chapter09.html -Compute the base value p := left + up - upleft, then choose that byte the closest -(of the smallest absolute difference) to the base value. Left byte has a precedence. */ - - -static int paeth (predictor_state *state) -{ - int p, p1, p2, p3; - p = left_pixel_byte(state) + up_pixel_byte(state) - upleft_pixel_byte(state); - p1 = p >= left_pixel_byte(state) ? (p - left_pixel_byte(state)) : (left_pixel_byte(state) - p); - p2 = p >= up_pixel_byte(state) ? (p - up_pixel_byte(state)) : (up_pixel_byte(state) - p); - p3 = p >= upleft_pixel_byte(state) ? (p - upleft_pixel_byte(state)) : (upleft_pixel_byte(state) - p); - return (p1 <= p2 && p1 <= p3) ? left_pixel_byte(state) : (p2 <= p3 ? up_pixel_byte(state) : upleft_pixel_byte(state)); -} - -/* predictor decoder */ - -iof_status predictor_decode_state (iof *I, iof *O, predictor_state *state) -{ - int status, c, d, outbytes; - while (state->status == STATUS_CONTINUE) - { - if (state->default_predictor >= 10) // PNG predictor? - { - read_row(state, I, state->rowsize + 1, status); - if (state->predictorbyte == 0) - { // we could actually check state->rowin <> state->buffer, but we need this flag for encoder anyway - state->current_predictor = row_byte(state) + 10; - state->predictorbyte = 1; - ++state->rowin; - } - } - else - { - read_row(state, I, state->rowsize, status); - } - switch (state->current_predictor) - { - case NONE_PREDICTOR: - for ( ; state->rowindex < state->rowsize; ++state->rowindex) - { - ensure_output_bytes(O, 1); - c = row_byte(state); - iof_set(O, c); - } - reset_row(state); - break; - case TIFF_PREDICTOR: - switch (state->compbits) - { - case 1: - outbytes = (state->components + 7) >> 3; - for ( ; state->sampleindex < state->rowsamples; ++state->sampleindex) - { - ensure_output_bytes(O, outbytes); - while (state->bitsin < state->components) - { - state->compin = (state->compin << 8) | row_byte(state); - state->bitsin += 8; - ++state->rowindex; - } - state->bitsin -= state->components; - d = state->compin >> state->bitsin; - state->compin &= (1 << state->bitsin) - 1; - c = d ^ left_pixel_value(state); - save_pixel_value(state, c); - state->compout = (state->compout << state->components) | c; - state->bitsout += state->components; - while (state->bitsout >= 8) - { - state->bitsout -= 8; - iof_set(O, state->compout >> state->bitsout); - state->compout &= (1 << state->bitsout) - 1; - } - } - if (state->bitsout > 0) - { - ensure_output_bytes(O, 1); - iof_set(O, state->compin << (8 - state->bitsout)); - } - break; - case 2: case 4: - for ( ; state->sampleindex < state->rowsamples; ++state->sampleindex) - { - for ( ; state->compindex < state->components; ) // state->compindex is ++ed by save_pixel_component() - { - ensure_output_bytes(O, 1); - if (state->bitsin < state->compbits) - { - state->compin = (state->compin << 8) | row_byte(state); - state->bitsin += 8; - ++state->rowindex; - } - state->bitsin -= state->compbits; - d = state->compin >> state->bitsin; - state->compin &= (1 << state->bitsin) - 1; - c = (d + left_pixel_component(state)) & 0xff; - save_pixel_component(state, c); - state->compout = (state->compout << state->compbits) | c; - state->bitsout += state->compbits; - if (state->bitsout >= 8) - { - state->bitsout -= 8; - iof_set(O, state->compout >> state->bitsout); - state->compout &= (1 << state->bitsout) - 1; - } - } - } - if (state->bitsout > 0) - { - ensure_output_bytes(O, 1); - iof_set(O, state->compin << (8 - state->bitsout)); - } - break; - case 8: - for ( ; state->rowindex < state->rowsize; ++state->rowindex) - { - ensure_output_bytes(O, 1); - c = (row_byte(state) + left_pixel_component(state)) & 0xff; - save_pixel_component(state, c); - iof_set(O, c); - } - break; - case 16: - for ( ; state->rowindex < state->rowsize - 1; ++state->rowindex) - { - ensure_output_bytes(O, 2); - d = row_byte(state) << 8; - ++state->rowindex; - d |= row_byte(state); - c = (d + left_pixel_component(state)) & 0xff; - save_pixel_component(state, c); - iof_set2(O, c >> 8, c & 0xff); - } - break; - default: - return IOFERR; - } - reset_tiff_row(state); - break; - case PNG_NONE_PREDICTOR: - for ( ; state->rowindex < state->rowsize; ++state->rowindex) - { - ensure_output_bytes(O, 1); - c = row_byte(state); - save_pixel_byte(state, c); // next row may need it - iof_set(O, c); - } - reset_png_row(state); - break; - case PNG_SUB_PREDICTOR: - for ( ; state->rowindex < state->rowsize; ++state->rowindex) - { - ensure_output_bytes(O, 1); - c = (row_byte(state) + left_pixel_byte(state)) & 0xff; - save_pixel_byte(state, c); - iof_set(O, c); - } - reset_png_row(state); - break; - case PNG_UP_PREDICTOR: - for ( ; state->rowindex < state->rowsize; ++state->rowindex) - { - ensure_output_bytes(O, 1); - c = (row_byte(state) + up_pixel_byte(state)) & 0xff; - save_pixel_byte(state, c); - iof_set(O, c); - } - reset_png_row(state); - break; - case PNG_AVERAGE_PREDICTOR: - for ( ; state->rowindex < state->rowsize; ++state->rowindex) - { - ensure_output_bytes(O, 1); - c = (row_byte(state) + ((up_pixel_byte(state) + left_pixel_byte(state)) / 2)) & 0xff; - save_pixel_byte(state, c); - iof_set(O, c); - } - reset_png_row(state); - break; - case PNG_PAETH_PREDICTOR: - for ( ; state->rowindex < state->rowsize; ++state->rowindex) - { - ensure_output_bytes(O, 1); - c = (row_byte(state) + paeth(state)) & 0xff; - save_pixel_byte(state, c); - iof_set(O, c); - } - reset_png_row(state); - break; - //case PNG_OPTIMUM_PREDICTOR: // valid as default_redictor, but not as algorithm identifier byte - default: - return IOFERR; - } - } - return state->status == STATUS_LAST ? IOFERR : IOFEOF; -} - -/* predictor encoder */ - -iof_status predictor_encode_state (iof *I, iof *O, predictor_state *state) -{ - int status, c, d, outbytes; - while (state->status == STATUS_CONTINUE) - { - read_row(state, I, state->rowsize, status); - if (state->current_predictor >= 10 && state->predictorbyte == 0) - { - ensure_output_bytes(O, 1); - iof_set(O, state->current_predictor - 10); - state->predictorbyte = 1; - } - switch (state->current_predictor) - { - case NONE_PREDICTOR: - for ( ; state->rowindex < state->rowsize; ++state->rowindex) - { - ensure_output_bytes(O, 1); - c = row_byte(state); - iof_set(O, c); - } - reset_row(state); - break; - case TIFF_PREDICTOR: - switch (state->compbits) - { - case 1: - outbytes = (state->components + 7) >> 3; - for ( ; state->sampleindex < state->rowsamples; ++state->sampleindex) - { - ensure_output_bytes(O, outbytes); - while (state->bitsin < state->components) - { - state->compin = (state->compin << 8) | row_byte(state); - state->bitsin += 8; - ++state->rowindex; - } - state->bitsin -= state->components; - c = state->compin >> state->bitsin; - state->compin &= (1 << state->bitsin) - 1; - d = c ^ left_pixel_value(state); - save_pixel_value(state, c); - state->compout = (state->compout << state->components) | d; - state->bitsout += state->components; - while (state->bitsout >= 8) - { - state->bitsout -= 8; - iof_set(O, state->compout >> state->bitsout); - state->compout &= (1 << state->bitsout) - 1; - } - } - if (state->bitsout > 0) - { - ensure_output_bytes(O, 1); - iof_set(O, state->compin << (8 - state->bitsout)); - } - break; - case 2: case 4: - for ( ; state->sampleindex < state->rowsamples; ++state->sampleindex) - { - for ( ; state->compindex < state->components; ) - { - ensure_output_bytes(O, 1); - if (state->bitsin < state->compbits) - { - state->compin = (state->compin << 8) | row_byte(state); - state->bitsin += 8; - ++state->rowindex; - } - state->bitsin -= state->compbits; - c = state->compin >> state->bitsin; - state->compin &= (1 << state->bitsin) - 1; - d = tocomp(c - left_pixel_component(state)); - save_pixel_component(state, c); - state->compout = (state->compout << state->compbits) | d; - state->bitsout += state->compbits; - if (state->bitsout >= 8) - { - state->bitsout -= 8; - iof_set(O, state->compout >> state->bitsout); - state->compout &= (1 << state->bitsout) - 1; - } - } - } - if (state->bitsout > 0) - { - ensure_output_bytes(O, 1); - iof_set(O, state->compin << (8 - state->bitsout)); - } - break; - case 8: - for ( ; state->rowindex < state->rowsize; ++state->rowindex) - { - ensure_output_bytes(O, 1); - c = row_byte(state); - d = tobyte(c - left_pixel_component(state)); - save_pixel_component(state, c); - iof_set(O, d); - } - break; - case 16: - for ( ; state->rowindex < state->rowsize - 1; ++state->rowindex) - { - ensure_output_bytes(O, 2); - c = row_byte(state) << 8; - ++state->rowindex; - c |= row_byte(state); - d = tocomp(c - left_pixel_component(state)); - save_pixel_component(state, c); - iof_set2(O, d >> 8, d & 0xff); - } - break; - default: - return IOFERR; - } - reset_tiff_row(state); - break; - case PNG_NONE_PREDICTOR: - for ( ; state->rowindex < state->rowsize; ++state->rowindex) - { - ensure_output_bytes(O, 1); - c = row_byte(state); - save_pixel_byte(state, c); // next row may need it - iof_set(O, c); - } - reset_png_row(state); - break; - case PNG_SUB_PREDICTOR: - for ( ; state->rowindex < state->rowsize; ++state->rowindex) - { - ensure_output_bytes(O, 1); - c = row_byte(state); - d = tobyte(c - left_pixel_byte(state)); - save_pixel_byte(state, c); - iof_set(O, d); - } - reset_png_row(state); - break; - case PNG_OPTIMUM_PREDICTOR: // not worthy to perform optimization - case PNG_UP_PREDICTOR: - for ( ; state->rowindex < state->rowsize; ++state->rowindex) - { - ensure_output_bytes(O, 1); - c = row_byte(state); - d = tobyte(c - up_pixel_byte(state)); - save_pixel_byte(state, c); - iof_set(O, d); - } - reset_png_row(state); - break; - case PNG_AVERAGE_PREDICTOR: - for ( ; state->rowindex < state->rowsize; ++state->rowindex) - { - ensure_output_bytes(O, 1); - c = row_byte(state); - d = tobyte(c - ((up_pixel_byte(state) + left_pixel_byte(state)) >> 1)); - save_pixel_byte(state, c); - iof_set(O, d); - } - reset_png_row(state); - break; - case PNG_PAETH_PREDICTOR: - for ( ; state->rowindex < state->rowsize; ++state->rowindex) - { - ensure_output_bytes(O, 1); - c = row_byte(state); - d = tobyte(c - paeth(state)); - save_pixel_byte(state, c); - iof_set(O, d); - } - reset_png_row(state); - break; - default: - return IOFERR; - } - } - return state->status == STATUS_LAST ? IOFERR : IOFEOF; -} - -iof_status predictor_decode (iof *I, iof *O, int predictor, int rowsamples, int components, int compbits) -{ - predictor_state state; - int ret; - predictor_decoder_init(&state, predictor, rowsamples, components, compbits); - state.flush = 1; - ret = predictor_decode_state(I, O, &state); - predictor_decoder_close(&state); - return ret; -} - -iof_status predictor_encode (iof *I, iof *O, int predictor, int rowsamples, int components, int compbits) -{ - predictor_state state; - int ret; - predictor_encoder_init(&state, predictor, rowsamples, components, compbits); - state.flush = 1; - ret = predictor_encode_state(I, O, &state); - predictor_encoder_close(&state); - return ret; -} - -/* filters */ - -// predictor decoder function - -static size_t predictor_decoder (iof *F, iof_mode mode) -{ - predictor_state *state; - iof_status status; - size_t tail; - - state = iof_filter_state(predictor_state *, F); - switch(mode) - { - case IOFLOAD: - case IOFREAD: - if (F->flags & IOF_STOPPED) - return 0; - tail = iof_tail(F); - F->pos = F->buf + tail; - F->end = F->buf + F->space; - do { - status = predictor_decode_state(F->next, F, state); - } while (mode == IOFLOAD && status == IOFFULL && iof_resize_buffer(F)); - return iof_decoder_retval(F, "predictor", status); - case IOFCLOSE: - predictor_decoder_close(state); - iof_free(F); - return 0; - default: - break; - } - return 0; -} - -// predictor encoder function - -static size_t predictor_encoder (iof *F, iof_mode mode) -{ - predictor_state *state; - iof_status status; - - state = iof_filter_state(predictor_state *, F); - switch (mode) - { - case IOFFLUSH: - state->flush = 1; - // fall through - case IOFWRITE: - F->end = F->pos; - F->pos = F->buf; - status = predictor_encode_state(F, F->next, state); - return iof_encoder_retval(F, "predictor", status); - case IOFCLOSE: - if (!state->flush) - predictor_encoder(F, IOFFLUSH); - predictor_encoder_close(state); - iof_free(F); - return 0; - default: - break; - } - return 0; -} - -iof * iof_filter_predictor_decoder (iof *N, int predictor, int rowsamples, int components, int compbits) -{ - iof *I; - predictor_state *state; - I = iof_filter_reader(predictor_decoder, sizeof(predictor_state), &state); - iof_setup_next(I, N); - if (predictor_decoder_init(state, predictor, rowsamples, components, compbits) == NULL) - { - iof_discard(I); - return NULL; - } - state->flush = 1; - return I; -} - -iof * iof_filter_predictor_encoder (iof *N, int predictor, int rowsamples, int components, int compbits) -{ - iof *O; - predictor_state *state; - O = iof_filter_writer(predictor_encoder, sizeof(predictor_state), &state); - iof_setup_next(O, N); - if (predictor_encoder_init(state, predictor, rowsamples, components, compbits) == NULL) - { - iof_discard(O); - return NULL; - } - return O; -} diff --git a/Build/source/texk/web2c/luatexdir/luapplib/util/utiliof.c-OK b/Build/source/texk/web2c/luatexdir/luapplib/util/utiliof.c-OK deleted file mode 100644 index 8815c8d5a14..00000000000 --- a/Build/source/texk/web2c/luatexdir/luapplib/util/utiliof.c-OK +++ /dev/null @@ -1,2938 +0,0 @@ -/* input/iutput stream */ - -#include <stdlib.h> -#include <string.h> -#include <stdarg.h> - -#include "utilmem.h" -#include "utillog.h" -#include "utiliof.h" - -/* commons */ - -void * iof_copy_data (const void *data, size_t size) -{ - return memcpy(util_malloc(size), data, size); -} - -uint8_t * iof_copy_file_data (const char *filename, size_t *psize) -{ - FILE *file; - size_t size; - uint8_t *data; - if ((file = fopen(filename, "rb")) == NULL) - return NULL; - fseek(file, 0, SEEK_END); - size = (size_t)ftell(file); - data = (uint8_t *)util_malloc(size); - fseek(file, 0, SEEK_SET); - if ((*psize = fread(data, 1, size, file)) != size) - { - util_free(data); - data = NULL; - } - fclose(file); - return data; -} - -uint8_t * iof_copy_file_handle_data (FILE *file, size_t *psize) -{ - size_t size; - uint8_t *data; - //long offset = ftell(file); // keep offset intact? - fseek(file, 0, SEEK_END); - size = (size_t)ftell(file); - data = (uint8_t *)util_malloc(size); - fseek(file, 0, SEEK_SET); - if ((*psize = fread(data, 1, size, file)) != size) - { - util_free(data); - data = NULL; - } - //fseek(file, offset, SEEK_SET) - return data; -} - -FILE * iof_get_file (iof *F) -{ - if (F->flags & IOF_FILE) - return iof_file_get_file(F->iofile); - if (F->flags & IOF_FILE_HANDLE) - return F->file; - return NULL; -} - -const char * iof_status_kind (iof_status status) -{ - switch (status) - { - case IOFEOF: - return "IOFEOF"; - case IOFERR: - return "IOFERR"; - case IOFEMPTY: - return "IOFEMPTY"; - case IOFFULL: - return "IOFFULL"; - default: - break; - } - return "(unknown)"; -} - -/* shared pseudofile */ - -#define IOF_FILE_DEFAULTS 0 - -iof_file * iof_file_new (FILE *file) -{ - iof_file *iofile = (iof_file *)util_malloc(sizeof(iof_file)); - iof_file_set_fh(iofile, file); - iofile->offset = NULL; - iofile->size = 0; - iofile->name = NULL; - iofile->refcount = 0; - iofile->flags = IOF_FILE_DEFAULTS|IOF_ALLOC; - return iofile; -} - -iof_file * iof_file_init (iof_file *iofile, FILE *file) -{ - iof_file_set_fh(iofile, file); - iofile->offset = NULL; - iofile->size = 0; - iofile->name = NULL; - iofile->refcount = 0; - iofile->flags = IOF_FILE_DEFAULTS; - return iofile; -} - -iof_file * iof_file_rdata (const void *data, size_t size) -{ - iof_file *iofile = (iof_file *)util_malloc(sizeof(iof_file)); - iofile->rbuf = iofile->rpos = (const uint8_t *)data; - iofile->rend = iofile->rbuf + size; - iofile->offset = NULL; - iofile->size = 0; - iofile->name = NULL; - iofile->refcount = 0; - iofile->flags = IOF_FILE_DEFAULTS|IOF_ALLOC|IOF_DATA; - return iofile; -} - -iof_file * iof_file_rdata_init (iof_file *iofile, const void *data, size_t size) -{ - iofile->rbuf = iofile->rpos = (const uint8_t *)data; - iofile->rend = iofile->rbuf + size; - iofile->offset = NULL; - iofile->size = 0; // letse keep it consequently set to zero (only for user disposal) - iofile->name = NULL; - iofile->refcount = 0; - iofile->flags = IOF_FILE_DEFAULTS|IOF_DATA; - return iofile; -} - -iof_file * iof_file_wdata (void *data, size_t size) -{ - return iof_file_rdata((const void *)data, size); -} - -iof_file * iof_file_wdata_init (iof_file *iofile, void *data, size_t size) -{ - return iof_file_rdata_init(iofile, (const void *)data, size); -} - -/* typical uses so far */ - -iof_file * iof_file_reader_from_file_handle (iof_file *iofile, const char *filename, FILE *file, int preload, int closefile) -{ - uint8_t *data; - size_t size; - - if (preload) - { - if ((data = iof_copy_file_handle_data(file, &size)) == NULL) - { - if (closefile) - fclose(file); - return NULL; - } - if (iofile == NULL) - iofile = iof_file_rdata(data, size); - else - iof_file_rdata_init(iofile, data, size); - iofile->flags |= IOF_BUFFER_ALLOC; - if (closefile) - fclose(file); - } - else - { - if (iofile == NULL) - iofile = iof_file_new(file); - else - iof_file_init(iofile, file); - if (closefile) - iofile->flags |= IOF_CLOSE_FILE; - } - if (filename != NULL) - iof_file_set_name(iofile, filename); - return iofile; -} - -iof_file * iof_file_reader_from_file (iof_file *iofile, const char *filename, int preload) -{ - FILE *file; - if ((file = fopen(filename, "rb")) == NULL) - return NULL; - return iof_file_reader_from_file_handle(iofile, filename, file, preload, 1); -} - -iof_file * iof_file_reader_from_data (iof_file *iofile, const void *data, size_t size, int preload, int freedata) -{ - void *newdata; - if (data == NULL) - return NULL; - if (preload) - { - newdata = iof_copy_data(data, size); - if (iofile == NULL) - iofile = iof_file_rdata(newdata, size); - else - iof_file_rdata_init(iofile, newdata, size); - iofile->flags |= IOF_BUFFER_ALLOC; - //if (freedata) // hardly makes sense... we can't free const void * - // util_free((void *)data); - } - else - { - if (iofile == NULL) - iofile = iof_file_rdata(data, size); - else - iof_file_rdata_init(iofile, data, size); - if (freedata) - iofile->flags |= IOF_BUFFER_ALLOC; - } - return iofile; -} - -/* -iof_file * iof_file_writer_from_file (iof_file *iofile, const char *filename) -{ - FILE *file; - if ((file = fopen(filename, "wb")) == NULL) - return NULL; - if (iofile == NULL) - iofile = iof_file_new(file); - else - iof_file_init(iofile, file); - iofile->flags |= IOF_CLOSE_FILE; - iof_file_set_name(iofile, filename); - return iofile; -} -*/ - -/* -Because of limited number of FILE* handles available, we may need to close contained handle -between accessing it. In applications so far (fonts, images) we typically need the source -to parse the file on creation and to rewrite or reload the data on dump. All iof_file api -functions assume that iofile has FILE* opened. Reopening it on every access (ftell, fseek, -read/write) makes no sense, as we would effectively loose control. If the caller invalidates -iofile by closing and nulling its file handle, it is also responsible to reopen when necessary. -*/ - -int iof_file_close_input (iof_file *iofile) -{ - FILE *file; - if (iofile->flags & IOF_DATA) - return 0; - if ((file = iof_file_get_fh(iofile)) == NULL) - return 0; - fclose(file); - iof_file_set_fh(iofile, NULL); - iofile->flags &= ~IOF_RECLOSE_FILE; - iofile->flags |= IOF_REOPEN_FILE; - return 1; -} - -int iof_file_reopen_input (iof_file *iofile) -{ // returns true if iofile readable - FILE *file; - const char *filename; - if (iofile->flags & IOF_DATA) - return 1; - if ((file = iof_file_get_fh(iofile)) != NULL) - return 1; // if present, assumed readable - if ((filename = iofile->name) == NULL || (file = fopen(filename, "rb")) == NULL) - return 0; - iof_file_set_fh(iofile, file); - iofile->flags &= ~IOF_REOPEN_FILE; - iofile->flags |= IOF_RECLOSE_FILE; - return 1; -} - -/* freeing iof_file */ - -void iof_file_free (iof_file *iofile) -{ - FILE *file; - if (iofile->flags & IOF_DATA) - { - if (iofile->flags & IOF_BUFFER_ALLOC) - { - iofile->flags &= ~IOF_BUFFER_ALLOC; - if (iofile->buf != NULL) - { - util_free(iofile->buf); - iofile->buf = iofile->pos = iofile->end = NULL; - } - } - } - else if ((file = iof_file_get_fh(iofile)) != NULL) - { - if (iofile->flags & IOF_CLOSE_FILE) - fclose(file); - iof_file_set_fh(iofile, NULL); - } - iof_file_set_name(iofile, NULL); - if (iofile->flags & IOF_ALLOC) - util_free(iofile); -} - -/* set filename for reopen */ - -void iof_file_set_name (iof_file *iofile, const char *name) -{ - if (iofile->name != NULL) - util_free(iofile->name); - if (name != NULL) - iofile->name = iof_copy_data(name, strlen(name) + 1); - else - iofile->name = NULL; -} - -/* seek */ - -int iof_file_seek (iof_file *iofile, long offset, int whence) -{ - if (iofile->flags & IOF_DATA) - { - switch (whence) - { - case SEEK_SET: - if (offset >= 0 && iofile->buf + offset <= iofile->end) - { - iofile->pos = iofile->buf + offset; - return 0; - } - return -1; - case SEEK_CUR: - if ((offset >= 0 && iofile->pos + offset <= iofile->end) || (offset < 0 && iofile->pos + offset >= iofile->buf)) - { - iofile->pos += offset; - return 0; - } - return -1; - case SEEK_END: - if (offset <= 0 && iofile->end + offset >= iofile->buf) - { - iofile->pos = iofile->end + offset; - return 0; - } - return -1; - } - return -1; - } - return fseek(iof_file_get_fh(iofile), offset, whence); -} - -/* */ - -long iof_file_tell (iof_file *iofile) -{ - return (iofile->flags & IOF_DATA) ? (long)(iofile->pos - iofile->buf) : ftell(iof_file_get_fh(iofile)); -} - -size_t iof_file_size (iof_file *iofile) -{ - long pos, size; - FILE *file; - if (iofile->flags & IOF_DATA) - return (size_t)iof_space(iofile); - file = iof_file_get_fh(iofile); - pos = ftell(file); - fseek(file, 0, SEEK_END); - size = ftell(file); - fseek(file, pos, SEEK_SET); - return size; -} - -int iof_file_eof (iof_file *iofile) -{ - if (iofile->flags & IOF_DATA) - return iofile->pos == iofile->end ? -1 : 0; - return feof(iof_file_get_fh(iofile)); -} - -int iof_file_flush (iof_file *iofile) -{ - if (iofile->flags & IOF_DATA) - return 0; - return fflush(iof_file_get_fh(iofile)); -} - -size_t iof_file_read (void *ptr, size_t size, size_t items, iof_file *iofile) -{ - if (iofile->flags & IOF_DATA) - { - size_t bytes = size * items; - if (bytes > (size_t)iof_left(iofile)) - bytes = (size_t)iof_left(iofile); - memcpy(ptr, iofile->pos, bytes); - iofile->pos += bytes; - return bytes / size; // number of elements read - } - return fread(ptr, size, items, iof_file_get_fh(iofile)); -} - -static size_t iof_file_data_resizeto (iof_file *iofile, size_t space) -{ - uint8_t *newbuf; - size_t size; - size = iof_size(iofile); - if (iofile->flags & IOF_BUFFER_ALLOC) - { - newbuf = (uint8_t *)util_realloc(iofile->buf, space); - } - else - { - newbuf = (uint8_t *)util_malloc(space); - if (size > 0) - memcpy(newbuf, iofile->buf, size); - iofile->flags |= IOF_BUFFER_ALLOC; - } - iofile->buf = newbuf; - iofile->pos = newbuf + size; - iofile->end = newbuf + space; - return space - size; -} - -#define iof_file_data_resize(iofile) iof_file_data_resizeto(iofile, iof_space(iofile) << 1) - -size_t iof_file_write (const void *ptr, size_t size, size_t items, iof_file *iofile) -{ - if (iofile->flags & IOF_DATA) - { - size_t space, sizesofar, bytes; - bytes = size * items; - if (bytes > (size_t)iof_left(iofile)) - { - if ((space = iof_space(iofile)) == 0) // allow iofile->buf/end initially NULL - space = BUFSIZ; - for (sizesofar = iof_size(iofile), space <<= 1; sizesofar + bytes > space; space <<= 1) - ; - if (iof_file_data_resizeto(iofile, space) == 0) - return 0; - } - memcpy(iofile->pos, ptr, bytes); - iofile->pos += bytes; - return bytes / size; - } - return fwrite(ptr, size, items, iof_file_get_fh(iofile)); -} - -size_t iof_file_ensure (iof_file *iofile, size_t bytes) -{ - if (iofile->flags & IOF_DATA) - { - size_t space, sizesofar, left; - left = (size_t)iof_left(iofile); - if (bytes > left) - { - if ((space = iof_space(iofile)) == 0) // allow iofile->buf/end initially NULL - space = BUFSIZ; - for (sizesofar = iof_size(iofile), space <<= 1; sizesofar + bytes > space; space <<= 1); - return iof_file_data_resizeto(iofile, space); - } - return left; - } - return 0; -} - -int iof_file_getc (iof_file *iofile) -{ - if (iofile->flags & IOF_DATA) - return iofile->pos < iofile->end ? *iofile->pos++ : IOFEOF; - return fgetc(iof_file_get_fh(iofile)); -} - -int iof_file_putc (iof_file *iofile, int c) -{ - if (iofile->flags & IOF_DATA) - { - if (iofile->pos >= iofile->end) - if (iof_file_data_resize(iofile) == 0) - return IOFEOF; - *iofile->pos++ = (uint8_t)c; - return c; - } - return fputc(c, iof_file_get_fh(iofile)); -} - -static int iof_file_sync (iof_file *iofile, size_t *offset) -{ - if (iofile->offset != offset) - { - if (iofile->offset != NULL) - *iofile->offset = iof_file_tell(iofile); - iofile->offset = offset; - if (offset) // let offset be NULL - return iof_file_seek(iofile, (long)*offset, SEEK_SET); - } - return 0; -} - -//#define iof_file_unsync(iofile, poffset) (void)((iofile)->offset == poffset && (((iofile)->offset = NULL), 0)) -#define iof_file_unsync(iofile, poffset) ((void)poffset, (iofile)->offset = NULL) - -/* iof seek */ - -#define iof_reader_reset(I) ((I)->pos = (I)->end = (I)->buf) -#define iof_reader_reseek_file(I, offset, whence) (fseek((I)->file, offset, whence) == 0 ? (iof_reader_reset(I), 0) : -1) -#define iof_reader_reseek_iofile(I, offset, whence) (iof_file_seek((I)->iofile, offset, whence) == 0 ? (iof_reader_reset(I), 0) : -1) - -#define iof_writer_reset(O) ((O)->pos = (O)->buf) -#define iof_writer_reseek_file(O, offset, whence) (iof_flush(O), (fseek((O)->file, offset, whence) == 0 ? (iof_writer_reset(O), 0) : -1)) -#define iof_writer_reseek_iofile(O, offset, whence) (iof_flush(O), (iof_file_seek((O)->iofile, offset, whence) == 0 ? (iof_writer_reset(O), 0) : -1)) - -static int iof_reader_seek_data (iof *I, long offset, int whence) -{ - switch (whence) - { - case SEEK_SET: - if (offset >= 0 && I->buf + offset <= I->end) - { - I->pos = I->buf + offset; - return 0; - } - return -1; - case SEEK_CUR: - if ((offset >= 0 && I->pos + offset <= I->end) || (offset < 0 && I->pos + offset >= I->buf)) - { - I->pos += offset; - return 0; - } - return -1; - case SEEK_END: - if (offset <= 0 && I->end + offset >= I->buf) - { - I->pos = I->end + offset; - return 0; - } - return -1; - } - return -1; -} - -static int iof_reader_seek_iofile (iof *I, long offset, int whence) -{ - long fileoffset; - switch (whence) - { - case SEEK_SET: - fileoffset = iof_file_tell(I->iofile); - if (offset <= fileoffset && offset >= fileoffset - iof_space(I)) - { - I->pos = I->end - (fileoffset - offset); - return 0; - } - return iof_reader_reseek_iofile(I, offset, SEEK_SET); - case SEEK_CUR: - if ((offset >= 0 && I->pos + offset <= I->end) || (offset < 0 && I->pos + offset >= I->buf)) - { - I->pos += offset; - return 0; - } - return iof_reader_reseek_iofile(I, offset, SEEK_CUR); - case SEEK_END: - return iof_reader_reseek_iofile(I, offset, SEEK_END); // can we do better? - } - return -1; -} - -static int iof_reader_seek_file (iof *I, long offset, int whence) -{ - long fileoffset; - switch (whence) - { - case SEEK_SET: - fileoffset = ftell(I->file); - if (offset <= fileoffset && offset >= fileoffset - iof_space(I)) - { - I->pos = I->end - (fileoffset - offset); - return 0; - } - return iof_reader_reseek_file(I, offset, SEEK_SET); - case SEEK_CUR: - if ((offset >= 0 && I->pos + offset <= I->end) || (offset < 0 && I->pos + offset >= I->buf)) - { - I->pos += offset; - return 0; - } - return iof_reader_reseek_file(I, offset, SEEK_CUR); - case SEEK_END: - return iof_reader_reseek_file(I, offset, SEEK_END); // can we do better? - } - return -1; -} - -int iof_reader_seek (iof *I, long offset, int whence) -{ - I->flags &= ~IOF_STOPPED; - if (I->flags & IOF_FILE) - return iof_reader_seek_iofile(I, offset, whence); - if (I->flags & IOF_FILE_HANDLE) - return iof_reader_seek_file(I, offset, whence); - if (I->flags & IOF_DATA) - return iof_reader_seek_data(I, offset, whence); - return -1; -} - -int iof_reader_reseek (iof *I, long offset, int whence) -{ - I->flags &= ~IOF_STOPPED; - if (I->flags & IOF_FILE) - return iof_reader_reseek_iofile(I, offset, whence); - if (I->flags & IOF_FILE_HANDLE) - return iof_reader_reseek_file(I, offset, whence); - if (I->flags & IOF_DATA) - return iof_reader_seek_data(I, offset, whence); - return -1; -} - -static int iof_writer_seek_data (iof *O, long offset, int whence) -{ - /* - fseek() allows to seek after the end of file. Seeking does not increase the output file. - No byte is written before fwirte(). It seems to fill the gap with zeros. Until we really need that, - no seeking out of bounds for writers. - */ - O->flags &= ~IOF_STOPPED; - return iof_reader_seek_data(O, offset, whence); -} - -static int iof_writer_seek_iofile (iof *O, long offset, int whence) -{ - long fileoffset; - switch (whence) - { - case SEEK_SET: - fileoffset = iof_file_tell(O->iofile); - if (offset >= fileoffset && offset <= fileoffset + iof_space(O)) - { - O->pos = O->buf + (offset - fileoffset); - return 0; - } - return iof_writer_reseek_iofile(O, offset, SEEK_SET); - case SEEK_CUR: - if ((offset >=0 && O->pos + offset <= O->end) || (offset < 0 && O->pos + offset >= O->buf)) - { - O->pos += offset; - return 0; - } - return iof_writer_reseek_iofile(O, offset, SEEK_CUR); - case SEEK_END: - return iof_writer_reseek_iofile(O, offset, SEEK_END); - } - return -1; -} - -static int iof_writer_seek_file (iof *O, long offset, int whence) -{ - long fileoffset; - switch (whence) - { - case SEEK_SET: - fileoffset = ftell(O->file); - if (offset >= fileoffset && offset <= fileoffset + iof_space(O)) - { - O->pos = O->buf + (offset - fileoffset); - return 0; - } - return iof_writer_reseek_file(O, offset, SEEK_SET); - case SEEK_CUR: - if ((offset >=0 && O->pos + offset <= O->end) || (offset < 0 && O->pos + offset >= O->buf)) - { - O->pos += offset; - return 0; - } - return iof_writer_reseek_file(O, offset, SEEK_CUR); - case SEEK_END: - return iof_writer_reseek_file(O, offset, SEEK_END); - } - return -1; -} - -int iof_writer_seek (iof *I, long offset, int whence) -{ - I->flags &= ~IOF_STOPPED; - if (I->flags & IOF_FILE) - return iof_writer_seek_iofile(I, offset, whence); - if (I->flags & IOF_FILE_HANDLE) - return iof_writer_seek_file(I, offset, whence); - if (I->flags & IOF_DATA) - return iof_writer_seek_data(I, offset, whence); - return -1; -} - -int iof_writer_reseek (iof *I, long offset, int whence) -{ - I->flags &= ~IOF_STOPPED; - if (I->flags & IOF_FILE) - return iof_writer_reseek_iofile(I, offset, whence); - if (I->flags & IOF_FILE_HANDLE) - return iof_writer_reseek_file(I, offset, whence); - if (I->flags & IOF_DATA) - return iof_writer_seek_data(I, offset, whence); - return -1; -} - -int iof_seek (iof *F, long offset, int whence) -{ - return (F->flags & IOF_WRITER) ? iof_writer_seek(F, offset, whence) : iof_reader_seek(F, offset, whence); -} - -int iof_reseek (iof *F, long offset, int whence) -{ - return (F->flags & IOF_WRITER) ? iof_writer_reseek(F, offset, whence) : iof_reader_reseek(F, offset, whence); -} - -/* tell */ - -long iof_reader_tell (iof *I) -{ - if (I->flags & IOF_FILE) - return iof_file_tell(I->iofile) - (long)iof_left(I); - if (I->flags & IOF_FILE_HANDLE) - return ftell(I->file) - (long)iof_left(I); - //if (I->flags & IOF_DATA) - return (long)iof_size(I); -} - -long iof_writer_tell (iof *O) -{ - if (O->flags & IOF_FILE) - return iof_file_tell(O->iofile) + (long)iof_size(O); - if (O->flags & IOF_FILE_HANDLE) - return ftell(O->file) + (long)iof_size(O); - //if (I->flags & IOF_DATA) - return (long)iof_size(O); -} - -long iof_tell (iof *I) -{ - return (I->flags & IOF_WRITER) ? iof_writer_tell(I) : iof_reader_tell(I); -} - -size_t iof_fsize (iof *I) -{ - size_t pos, size; - if (I->flags & IOF_FILE) - return iof_file_size(I->iofile); - if (I->flags & IOF_FILE_HANDLE) - { - pos = (size_t)ftell(I->file); - fseek(I->file, 0, SEEK_END); - size = (size_t)ftell(I->file); - fseek(I->file, (long)pos, SEEK_SET); - return size; - } - //if (I->flags & IOF_DATA) - return (size_t)iof_space(I); -} - -/* save reader tail */ - -size_t iof_save_tail (iof *I) -{ - size_t size, left; - size = iof_size(I); - left = iof_left(I); - if (size >= left) - memcpy(I->buf, I->pos, left); - else - memmove(I->buf, I->pos, left); - return left; -} - -size_t iof_input_save_tail (iof *I, size_t back) -{ - size_t size; - I->flags |= IOF_TAIL; - I->pos -= back; - size = iof_input(I); - I->pos += back; - I->flags &= ~IOF_TAIL; - return size; // + back - back -} - -/* read from file */ - -/* iof free*/ - -static size_t file_read (iof *I); -static size_t file_load (iof *I); - -static size_t file_reader (iof *I, iof_mode mode) -{ - switch (mode) - { - case IOFREAD: - return file_read(I); - case IOFLOAD: - return file_load(I); - case IOFCLOSE: - iof_free(I); - return 0; - default: - return 0; - } -} - -iof * iof_setup_file_handle_reader (iof *I, void *buffer, size_t space, FILE *f) -{ - if (I == NULL) - iof_setup_reader(I, buffer, space); - else - iof_reader_buffer(I, buffer, space); - iof_setup_file(I, f); - I->more = file_reader; - return I; -} - -iof * iof_setup_file_reader (iof *I, void *buffer, size_t space, const char *filename) -{ - FILE *f; - if ((f = fopen(filename, "rb")) == NULL) - return NULL; - if (I == NULL) - iof_setup_reader(I, buffer, space); - else - iof_reader_buffer(I, buffer, space); - iof_setup_file(I, f); - I->flags |= IOF_CLOSE_FILE; - I->more = file_reader; - return I; -} - -/* write to file */ - -static size_t file_write (iof *O, int flush); - -static size_t file_writer (iof *O, iof_mode mode) -{ - switch (mode) - { - case IOFWRITE: - return file_write(O, 0); - case IOFFLUSH: - return file_write(O, 1); - case IOFCLOSE: - file_write(O, 1); - iof_free(O); - return 0; - default: - return 0; - } -} - -iof * iof_setup_file_handle_writer (iof *O, void *buffer, size_t space, FILE *f) -{ - if (O == NULL) - iof_setup_writer(O, buffer, space); - else - iof_writer_buffer(O, buffer, space); - iof_setup_file(O, f); - O->more = file_writer; - return O; -} - -iof * iof_setup_file_writer (iof *O, void *buffer, size_t space, const char *filename) -{ - FILE *f; - if ((f = fopen(filename, "wb")) == NULL) - return NULL; - if (O == NULL) - iof_setup_writer(O, buffer, space); - else - iof_writer_buffer(O, buffer, space); - iof_setup_file(O, f); - O->flags |= IOF_CLOSE_FILE; - O->more = file_writer; - return O; -} - -/* a dedicated handler for stdout/stderr */ - -static size_t stdout_writer (iof *O, iof_mode mode) -{ - switch(mode) - { - case IOFWRITE: - { - fwrite(O->buf, sizeof(uint8_t), iof_size(O), stdout); - O->pos = O->buf; - return O->space; - } - case IOFCLOSE: - case IOFFLUSH: - { - fwrite(O->buf, sizeof(uint8_t), iof_size(O), stdout); - fflush(stdout); - O->pos = O->buf; - return 0; - } - default: - break; - } - return 0; -} - -static size_t stderr_writer (iof *O, iof_mode mode) -{ - switch(mode) - { - case IOFWRITE: - { - fwrite(O->buf, sizeof(uint8_t), iof_size(O), stderr); - O->pos = O->buf; - return O->space; - } - case IOFCLOSE: - case IOFFLUSH: - { - fwrite(O->buf, sizeof(uint8_t), iof_size(O), stderr); - fflush(stderr); - O->pos = O->buf; - return 0; - } - default: - break; - } - return 0; -} - -static uint8_t iof_stdout_buffer[BUFSIZ]; -iof iof_stdout = IOF_WRITER_STRUCT(stdout_writer, NULL, iof_stdout_buffer, BUFSIZ, 0); - -static uint8_t iof_stderr_buffer[BUFSIZ]; -iof iof_stderr = IOF_WRITER_STRUCT(stderr_writer, NULL, iof_stderr_buffer, BUFSIZ, 0); - -/* read from somewhere */ - -iof * iof_reader (iof *I, void *link, iof_handler reader, const void *m, size_t bytes) -{ - I->space = 0; - I->link = link; - I->more = reader; - I->flags = 0; - I->refcount = 0; - if (m != NULL) - { - I->rbuf = I->rpos = (const uint8_t *)m; - I->rend = (const uint8_t *)m + bytes; - return I; - } - return NULL; -} - -iof * iof_string_reader (iof *I, const void *s, size_t bytes) -{ - I->space = 0; - I->link = NULL; - I->more = NULL; - I->flags = 0; // iof_string() sets IOF_DATA - I->refcount = 0; - if (s != NULL) - return iof_string(I, s, bytes); - return NULL; -} - -/* write somewhere */ - -iof * iof_writer (iof *O, void *link, iof_handler writer, void *m, size_t bytes) -{ - O->space = 0; - O->link = link; - O->more = writer; - O->flags = 0; - O->refcount = 0; - if (m != NULL && bytes > 0) - { - O->buf = O->pos = (uint8_t *)m; - O->end = (uint8_t *)m + bytes; - return O; - } - // return iof_null(O); - return NULL; -} - -/* write to growing bytes buffer */ - -static size_t iof_mem_handler (iof *O, iof_mode mode) -{ - switch(mode) - { - case IOFWRITE: - return iof_resize_buffer(O); - case IOFCLOSE: - iof_free(O); - return 0; - default: - return 0; - } -} - -iof * iof_setup_buffer (iof *O, void *buffer, size_t space) -{ - if (O == NULL) - iof_setup_writer(O, buffer, space); - else - iof_writer_buffer(O, buffer, space); - O->link = NULL; - O->flags |= IOF_DATA; - O->more = iof_mem_handler; - return O; -} - -iof * iof_setup_buffermin (iof *O, void *buffer, size_t space, size_t min) -{ - if ((O = iof_setup_buffer(O, buffer, space)) != NULL && space < min) // just allocate min now to avoid further rewriting - { - O->buf = O->pos = (uint8_t *)util_malloc(min); - O->flags |= IOF_BUFFER_ALLOC; - O->end = O->buf + min; - } - return O; -} - -iof * iof_buffer_create (size_t space) -{ - uint8_t *buffer; - iof *O; - space += sizeof(iof); - buffer = util_malloc(space); - if ((O = iof_setup_buffer(NULL, buffer, space)) != NULL) - O->flags |= IOF_ALLOC; - return O; -} - -/* set/get */ - -int iof_getc (iof *I) -{ - if (iof_readable(I)) - return *I->pos++; - return IOFEOF; -} - -int iof_putc (iof *O, int u) -{ - if (iof_writable(O)) - { - iof_set(O, u); - return (uint8_t)u; - } - return IOFFULL; -} - -size_t iof_skip (iof *I, size_t bytes) -{ - while (bytes) - { - if (iof_readable(I)) - ++I->pos; - else - break; - --bytes; - } - return bytes; -} - -/* from iof to iof */ - -iof_status iof_pass (iof *I, iof *O) -{ - size_t leftin, leftout; - if ((leftin = iof_left(I)) == 0) - leftin = iof_input(I); - while (leftin) - { - if ((leftout = iof_left(O)) == 0) - if ((leftout = iof_output(O)) == 0) - return IOFFULL; - while (leftin > leftout) - { - memcpy(O->pos, I->pos, leftout); - I->pos += leftout; - O->pos = O->end; /* eq. += leftout */ - leftin -= leftout; - if ((leftout = iof_output(O)) == 0) - return IOFFULL; - } - if (leftin) - { - memcpy(O->pos, I->pos, leftin); - I->pos = I->end; /* eq. += leftin */ - O->pos += leftin; - } - leftin = iof_input(I); - } - return IOFEOF; -} - -/* read n-bytes */ - -size_t iof_read (iof *I, void *to, size_t size) -{ - size_t leftin, done = 0; - char *s = (char *)to; - - if ((leftin = iof_left(I)) == 0) - if ((leftin = iof_input(I)) == 0) - return done; - while (size > leftin) - { - memcpy(s, I->pos, leftin * sizeof(uint8_t)); - size -= leftin; - done += leftin; - s += leftin; - I->pos = I->end; - if ((leftin = iof_input(I)) == 0) - return done; - } - if (size) - { - memcpy(s, I->pos, size * sizeof(uint8_t)); - I->pos += size; - done += size; - } - return done; -} - -/* rewrite FILE content (use fseek if needed) */ - -size_t iof_write_file_handle (iof *O, FILE *file) -{ - size_t leftout, size, readout; - if ((leftout = iof_left(O)) == 0) - if ((leftout = iof_output(O)) == 0) - return 0; - size = 0; - do { - readout = fread(O->pos, 1, leftout, file); - O->pos += readout; - size += readout; - } while(readout == leftout && (leftout = iof_output(O)) > 0); - return size; -} - -size_t iof_write_file (iof *O, const char *filename) -{ - FILE *file; - size_t size; - if ((file = fopen(filename, "rb")) == NULL) - return 0; - size = iof_write_file_handle(O, file); - fclose(file); - return size; -} - -size_t iof_write_iofile (iof *O, iof_file *iofile, int savepos) -{ - long offset; - size_t size; - FILE *file; - if (iofile->flags & IOF_DATA) - return iof_write(O, iofile->pos, (size_t)(iofile->end - iofile->pos)); - file = iof_file_get_fh(iofile); - if (savepos) - { - offset = ftell(file); - size = iof_write_file_handle(O, file); - fseek(file, offset, SEEK_SET); - return size; - } - return iof_write_file_handle(O, file); -} - -/* write n-bytes */ - -size_t iof_write (iof *O, const void *data, size_t size) -{ - size_t leftout, done = 0; - const char *s = (const char *)data; - if ((leftout = iof_left(O)) == 0) - if ((leftout = iof_output(O)) == 0) - return done; - while (size > leftout) - { - memcpy(O->pos, s, leftout * sizeof(uint8_t)); - size -= leftout; - done += leftout; - s += leftout; - O->pos = O->end; - if ((leftout = iof_output(O)) == 0) - return done; - } - if (size) - { - memcpy(O->pos, s, size * sizeof(uint8_t)); - O->pos += size; - done += size; - } - return done; -} - -/* write '\0'-terminated string */ - -iof_status iof_puts (iof *O, const void *data) -{ - const char *s = (const char *)data; - while (*s) - { - if (iof_writable(O)) - iof_set(O, *s++); - else - return IOFFULL; - } - return IOFEOF; // ? -} - -size_t iof_put_string (iof *O, const void *data) -{ - const char *p, *s = (const char *)data; - for (p = s; *p != '\0' && iof_writable(O); iof_set(O, *p++)); - return p - s; -} - -/* write byte n-times */ - -/* -iof_status iof_repc (iof *O, char c, size_t bytes) -{ - while (bytes) - { - if (iof_writable(O)) - iof_set(O, c); - else - return IOFFULL; - --bytes; - } - return IOFEOF; // ? -} -*/ - -size_t iof_repc (iof *O, char c, size_t bytes) -{ - size_t leftout, todo = bytes; - if ((leftout = iof_left(O)) == 0) - if ((leftout = iof_output(O)) == 0) - return 0; - while (bytes > leftout) - { - memset(O->pos, c, leftout); - bytes -= leftout; - O->pos = O->end; - if ((leftout = iof_output(O)) == 0) - return todo - bytes; - } - if (bytes) - { - memset(O->pos, c, bytes); - O->pos += bytes; - } - return todo; -} - -/* putfs */ - -#define IOF_FMT_SIZE 1024 - -size_t iof_putfs (iof *O, const char *format, ...) -{ - static char buffer[IOF_FMT_SIZE]; - va_list args; - va_start(args, format); - if (vsnprintf(buffer, IOF_FMT_SIZE, format, args) > 0) - { - va_end(args); - return iof_put_string(O, buffer); - } - else - { - va_end(args); - return iof_write(O, buffer, IOF_FMT_SIZE); - } -} - -/* integer from iof; return 1 on success, 0 otherwise */ - -int iof_get_int32 (iof *I, int32_t *number) -{ - int sign, c = iof_char(I); - iof_scan_sign(I, c, sign); - if (!base10_digit(c)) return 0; - iof_read_integer(I, c, *number); - if (sign) *number = -*number; - return 1; -} - -int iof_get_intlw (iof *I, intlw_t *number) -{ - int sign, c = iof_char(I); - iof_scan_sign(I, c, sign); - if (!base10_digit(c)) return 0; - iof_read_integer(I, c, *number); - if (sign) *number = -*number; - return 1; -} - -int iof_get_int64 (iof *I, int64_t *number) -{ - int sign, c = iof_char(I); - iof_scan_sign(I, c, sign); - if (!base10_digit(c)) return 0; - iof_read_integer(I, c, *number); - if (sign) *number = -*number; - return 1; -} - -int iof_get_uint32 (iof *I, uint32_t *number) -{ - int c = iof_char(I); - if (!base10_digit(c)) return 0; - iof_read_integer(I, c, *number); - return 1; -} - -int iof_get_uintlw (iof *I, uintlw_t *number) -{ - int c = iof_char(I); - if (!base10_digit(c)) return 0; - iof_read_integer(I, c, *number); - return 1; -} - -int iof_get_uint64 (iof *I, uint64_t *number) -{ - int c = iof_char(I); - if (!base10_digit(c)) return 0; - iof_read_integer(I, c, *number); - return 1; -} - -int iof_get_int32_radix (iof *I, int32_t *number, int radix) -{ - int sign, c = iof_char(I); - iof_scan_sign(I, c, sign); - if (!base10_digit(c)) return 0; - iof_read_radix(I, c, *number, radix); - if (sign) *number = -*number; - return 1; - -} - -int iof_get_intlw_radix (iof *I, intlw_t *number, int radix) -{ - int sign, c = iof_char(I); - iof_scan_sign(I, c, sign); - if (!base10_digit(c)) return 0; - iof_read_radix(I, c, *number, radix); - if (sign) *number = -*number; - return 1; -} - -int iof_get_int64_radix (iof *I, int64_t *number, int radix) -{ - int sign, c = iof_char(I); - iof_scan_sign(I, c, sign); - if (!base10_digit(c)) return 0; - iof_read_radix(I, c, *number, radix); - if (sign) *number = -*number; - return 1; -} - -int iof_get_uint32_radix (iof *I, uint32_t *number, int radix) -{ - int c = iof_char(I); - if (!base10_digit(c)) return 0; - iof_read_radix(I, c, *number, radix); - return 1; -} - -int iof_get_uintlw_radix (iof *I, uintlw_t *number, int radix) -{ - int c = iof_char(I); - if (!base10_digit(c)) return 0; - iof_read_radix(I, c, *number, radix); - return 1; -} - -int iof_get_uint64_radix (iof *I, uint64_t *number, int radix) -{ - int c = iof_char(I); - if (!base10_digit(c)) return 0; - iof_read_radix(I, c, *number, radix); - return 1; -} - -/* get roman to uint16_t, cf. roman_to_uint16() from utilnumber.c*/ - -/* todo: some trick in place of this macro horror? */ - -#define roman1000(c) (c == 'M' || c == 'm') -#define roman500(c) (c == 'D' || c == 'd') -#define roman100(c) (c == 'C' || c == 'c') -#define roman50(c) (c == 'L' || c == 'l') -#define roman10(c) (c == 'X' || c == 'x') -#define roman5(c) (c == 'V' || c == 'v') -#define roman1(c) (c == 'I' || c == 'i') - -#define roman100s(I, c) \ - (roman100(c) ? (100 + ((c = iof_next(I), roman100(c)) ? (100 + ((c = iof_next(I), roman100(c)) ? (c = iof_next(I), 100) : 0)) : 0)) : 0) -#define roman10s(I, c) \ - (roman10(c) ? (10 + ((c = iof_next(I), roman10(c)) ? (10 + ((c = iof_next(I), roman10(c)) ? (c = iof_next(I), 10) : 0)) : 0)) : 0) -#define roman1s(I, c) \ - (roman1(c) ? (1 + ((c = iof_next(I), roman1(c)) ? (1 + ((c = iof_next(I), roman1(c)) ? (c = iof_next(I), 1) : 0)) : 0)) : 0) - -int iof_get_roman (iof *I, uint16_t *number) -{ - int c; - /* M */ - for (*number = 0, c = iof_char(I); roman1000(c); *number += 1000, c = iof_next(I)); - /* D C */ - if (roman500(c)) - { - c = iof_next(I); - *number += 500 + roman100s(I, c); - } - else if (roman100(c)) - { - c = iof_next(I); - if (roman1000(c)) - { - c = iof_next(I); - *number += 900; - } - else if (roman500(c)) - { - c = iof_next(I); - *number += 400; - } - else - *number += 100 + roman100s(I, c); - } - /* L X */ - if (roman50(c)) - { - c = iof_next(I); - *number += 50 + roman10s(I, c); - } - else if (roman10(c)) - { - c = iof_next(I); - if (roman100(c)) - { - c = iof_next(I); - *number += 90; - } - else if (roman50(c)) - { - c = iof_next(I); - *number += 40; - } - else - *number += 10 + roman10s(I, c); - } - /* V I */ - if (roman5(c)) - { - c = iof_next(I); - *number += 5 + roman1s(I, c); - } - else if (roman1(c)) - { - c = iof_next(I); - if (roman10(c)) - { - c = iof_next(I); - *number += 9; - } - else if (roman5(c)) - { - c = iof_next(I); - *number += 4; - } - else - *number += 1 + roman1s(I, c); - } - return 1; -} - -/* double from iof; return 1 on success */ - -int iof_get_double (iof *I, double *number) // cf. string_to_double() -{ - int sign, exponent10, c = iof_char(I); - iof_scan_sign(I, c, sign); - iof_scan_decimal(I, c, *number); - if (c == '.') - { - c = iof_next(I); - iof_scan_fraction(I, c, *number, exponent10); - } - else - exponent10 = 0; - if (c == 'e' || c == 'E') - { - c = iof_next(I); - iof_scan_exponent10(I, c, exponent10); - } - double_exp10(*number, exponent10); - if (sign) *number = -*number; - return 1; -} - -int iof_get_float (iof *I, float *number) // cf. string_to_float() in utilnumber.c -{ - int sign, exponent10, c = iof_char(I); - iof_scan_sign(I, c, sign); - iof_scan_decimal(I, c, *number); - if (c == '.') - { - c = iof_next(I); - iof_scan_fraction(I, c, *number, exponent10); - } - else - exponent10 = 0; - if (c == 'e' || c == 'E') - { - c = iof_next(I); - iof_scan_exponent10(I, c, exponent10); - } - float_exp10(*number, exponent10); - if (sign) *number = -*number; - return 1; -} - -int iof_conv_double (iof *I, double *number) // cf. convert_to_double() in utilnumber.c -{ - int sign, exponent10, c = iof_char(I); - iof_scan_sign(I, c, sign); - iof_scan_decimal(I, c, *number); - if (c == '.' || c == ',') - { - c = iof_next(I); - iof_scan_fraction(I, c, *number, exponent10); - if (exponent10 < 0) - double_negative_exp10(*number, exponent10); - } - if (sign) *number = -*number; - return 1; -} - -int iof_conv_float (iof *I, float *number) // cf. convert_to_float() -{ - int sign, exponent10, c = iof_char(I); - iof_scan_sign(I, c, sign); - iof_scan_decimal(I, c, *number); - if (c == '.' || c == ',') - { - c = iof_next(I); - iof_scan_fraction(I, c, *number, exponent10); - if (exponent10 < 0) - float_negative_exp10(*number, exponent10); - } - if (sign) *number = -*number; - return 1; -} - -/* integer to iof; return a number of written bytes */ - -#define iof_copy_number_buffer(O, s, p) for (p = s; *p && iof_writable(O); iof_set(O, *p), ++p) - -size_t iof_put_int32 (iof *O, int32_t number) -{ - const char *s, *p; - s = int32_to_string(number); - iof_copy_number_buffer(O, s, p); - return p - s; -} - -size_t iof_put_intlw (iof *O, intlw_t number) -{ - const char *s, *p; - s = intlw_to_string(number); - iof_copy_number_buffer(O, s, p); - return p - s; -} - -size_t iof_put_int64 (iof *O, int64_t number) -{ - const char *s, *p; - s = int64_to_string(number); - iof_copy_number_buffer(O, s, p); - return p - s; -} - -size_t iof_put_uint32 (iof *O, uint32_t number) -{ - const char *s, *p; - s = uint32_to_string(number); - iof_copy_number_buffer(O, s, p); - return p - s; -} - -size_t iof_put_uintlw (iof *O, uintlw_t number) -{ - const char *s, *p; - s = uintlw_to_string(number); - iof_copy_number_buffer(O, s, p); - return p - s; -} - -size_t iof_put_uint64 (iof *O, uint64_t number) -{ - const char *s, *p; - s = uint64_to_string(number); - iof_copy_number_buffer(O, s, p); - return p - s; -} - -size_t iof_put_int32_radix (iof *O, int32_t number, int radix) -{ - const char *s, *p; - s = int32_to_radix(number, radix); - iof_copy_number_buffer(O, s, p); - return p - s; -} - -size_t iof_put_intlw_radix (iof *O, intlw_t number, int radix) -{ - const char *s, *p; - s = intlw_to_radix(number, radix); - iof_copy_number_buffer(O, s, p); - return p - s; -} - -size_t iof_put_int64_radix (iof *O, int64_t number, int radix) -{ - const char *s, *p; - s = int64_to_radix(number, radix); - iof_copy_number_buffer(O, s, p); - return p - s; -} - -size_t iof_put_uint32_radix (iof *O, uint32_t number, int radix) -{ - const char *s, *p; - s = uint32_to_radix(number, radix); - iof_copy_number_buffer(O, s, p); - return p - s; -} - -size_t iof_put_uintlw_radix (iof *O, uintlw_t number, int radix) -{ - const char *s, *p; - s = uintlw_to_radix(number, radix); - iof_copy_number_buffer(O, s, p); - return p - s; -} - -size_t iof_put_uint64_radix (iof *O, uint64_t number, int radix) -{ - const char *s, *p; - s = uint64_to_radix(number, radix); - iof_copy_number_buffer(O, s, p); - return p - s; -} - -/* roman numerals */ - -size_t iof_put_roman_uc (iof *O, uint16_t number) -{ - const char *s, *p; - s = uint16_to_roman_uc(number); - iof_copy_number_buffer(O, s, p); - return p - s; -} - -size_t iof_put_roman_lc (iof *O, uint16_t number) -{ - const char *s, *p; - s = uint16_to_roman_lc(number); - iof_copy_number_buffer(O, s, p); - return p - s; -} - -/* double/float to iof; return the number of written bytes */ - -size_t iof_put_double (iof *O, double number, int digits) -{ - const char *s, *p; - s = double_to_string(number, digits); - iof_copy_number_buffer(O, s, p); - return p - s; -} - -size_t iof_put_float (iof *O, float number, int digits) -{ - const char *s, *p; - s = float_to_string(number, digits); - iof_copy_number_buffer(O, s, p); - return p - s; -} - -/* iof to binary integer; pretty common */ - -int iof_get_be_uint2 (iof *I, uint32_t *pnumber) -{ - int c1, c2; - if ((c1 = iof_get(I)) < 0 || (c2 = iof_get(I)) < 0) - return 0; - *pnumber = (c1<<8)|c2; - return 1; -} - -int iof_get_be_uint3 (iof *I, uint32_t *pnumber) -{ - int c1, c2, c3; - if ((c1 = iof_get(I)) < 0 || (c2 = iof_get(I)) < 0 || (c3 = iof_get(I)) < 0) - return 0; - *pnumber = (c1<<16)|(c2<<8)|c3; - return 1; -} - -int iof_get_be_uint4 (iof *I, uint32_t *pnumber) -{ - int c1, c2, c3, c4; - if ((c1 = iof_get(I)) < 0 || (c2 = iof_get(I)) < 0 || (c3 = iof_get(I)) < 0 || (c4 = iof_get(I)) < 0) - return 0; - *pnumber = (c1<<24)|(c2<<16)|(c3<<8)|c4; - return 1; -} - -int iof_get_le_uint2 (iof *I, uint32_t *pnumber) -{ - int c1, c2; - if ((c1 = iof_get(I)) < 0 || (c2 = iof_get(I)) < 0) - return 0; - *pnumber = (c2<<8)|c1; - return 1; -} - -int iof_get_le_uint3 (iof *I, uint32_t *pnumber) -{ - int c1, c2, c3; - if ((c1 = iof_get(I)) < 0 || (c2 = iof_get(I)) < 0 || (c3 = iof_get(I)) < 0) - return 0; - *pnumber = (c3<<16)|(c2<<8)|c1; - return 1; -} - -int iof_get_le_uint4 (iof *I, uint32_t *pnumber) -{ - int c1, c2, c3, c4; - if ((c1 = iof_get(I)) < 0 || (c2 = iof_get(I)) < 0 || (c3 = iof_get(I)) < 0 || (c4 = iof_get(I)) < 0) - return 0; - *pnumber = (c4<<24)|(c3<<16)|(c2<<8)|c1; - return 1; -} - -/* iof input data */ - -uint8_t * iof_file_input_data (iof_file *iofile, size_t *psize, int *isnew) -{ - uint8_t *data; - if (iofile->flags & IOF_DATA) - { - data = iofile->buf; - *psize = iofile->end - iofile->buf; - *isnew = 0; - return data; - } - if (iof_file_reopen(iofile)) - { - data = iof_copy_file_handle_data(iof_file_get_fh(iofile), psize); - *isnew = 1; - iof_file_reclose(iofile); - return data; - } - return NULL; -} - -/* -uint8_t * iof_file_reader_data (iof_file *iofile, size_t *size) -{ - uint8_t *data; - if (!(iofile->flags & IOF_DATA) || iofile->pos == NULL || (*size = (size_t)iof_left(iofile)) == 0) - return NULL; - if (iofile->flags & IOF_BUFFER_ALLOC) - { - data = iofile->buf; // iofile->pos; // returned must be freeable, makes sense when ->buf == ->pos - iofile->flags &= ~IOF_BUFFER_ALLOC; - iofile->buf = iofile->pos = iofile->end = NULL; - return data; - } - data = (uint8_t *)util_malloc(*size); - memcpy(data, iofile->buf, *size); - return data; -} - -uint8_t * iof_file_writer_data (iof_file *iofile, size_t *size) -{ - uint8_t *data; - if (!(iofile->flags & IOF_DATA) || iofile->buf == NULL || (*size = (size_t)iof_size(iofile)) == 0) - return NULL; - if (iofile->flags & IOF_BUFFER_ALLOC) - { - iofile->flags &= ~IOF_BUFFER_ALLOC; - data = iofile->buf; - iofile->buf = iofile->pos = iofile->end = NULL; - return data; - } - data = (uint8_t *)util_malloc(*size); - memcpy(data, iofile->buf, *size); - return data; -} -*/ - -uint8_t * iof_reader_data (iof *I, size_t *psize) -{ - uint8_t *data; - *psize = (size_t)iof_left(I); - if (I->flags & IOF_BUFFER_ALLOC) - { - data = I->buf; // actually I->pos, but we have to return something freeable - I->flags &= ~IOF_BUFFER_ALLOC; - I->buf = NULL; - } - else - { - data = util_malloc(*psize); - memcpy(data, I->pos, *psize); - } - iof_close(I); - return data; -} - - -uint8_t * iof_writer_data (iof *O, size_t *psize) -{ - uint8_t *data; - *psize = (size_t)iof_size(O); - if (O->flags & IOF_BUFFER_ALLOC) - { - data = O->buf; - O->flags &= ~IOF_BUFFER_ALLOC; - O->buf = NULL; - } - else - { - data = util_malloc(*psize); - memcpy(data, O->buf, *psize); - } - iof_close(O); - return data; -} - -size_t iof_reader_to_file_handle (iof *I, FILE *file) -{ - size_t size; - for (size = 0; iof_readable(I); I->pos = I->end) - size += fwrite(I->buf, sizeof(uint8_t), iof_left(I), file); - return size; -} - -size_t iof_reader_to_file (iof *I, const char *filename) -{ - FILE *file; - size_t size; - if ((file = fopen(filename, "wb")) == NULL) - return 0; - for (size = 0; iof_readable(I); I->pos = I->end) - size += fwrite(I->buf, sizeof(uint8_t), iof_left(I), file); - fclose(file); - return size; -} - -/* debug */ - -size_t iof_data_to_file (const void *data, size_t size, const char *filename) -{ - FILE *fh; - if ((fh = fopen(filename, "wb")) == NULL) - return 0; - // size = fwrite(data, size, sizeof(uint8_t), fh); // WRONG, this always returns 1, as fwrite returns the number of elements successfully written out - size = fwrite(data, sizeof(uint8_t), size, fh); - fclose(fh); - return size; -} - -size_t iof_result_to_file_handle (iof *F, FILE *file) -{ - const void *data; - size_t size; - data = iof_result(F, size); - return iof_data_to_file_handle(data, size, file); -} - -size_t iof_result_to_file (iof *F, const char *filename) -{ - const void *data; - size_t size; - data = iof_result(F, size); - return iof_data_to_file(data, size, filename); -} - -void iof_debug (iof *I, const char *filename) -{ - FILE *file = fopen(filename, "wb"); - if (file != NULL) - { - fprintf(file, ">>> buf %p <<<\n", I->buf); - fwrite(I->buf, sizeof(uint8_t), iof_size(I), file); - fprintf(file, "\n>>> pos %p (%ld) <<<\n", I->pos, (long)iof_size(I)); - fwrite(I->pos, sizeof(uint8_t), iof_left(I), file); - fprintf(file, "\n>>> end %p (%ld) <<<\n", I->end, (long)iof_left(I)); - fwrite(I->end, sizeof(uint8_t), I->space - iof_space(I), file); - fprintf(file, "\n>>> end of buffer %p (%ld) <<<\n", I->buf + I->space, (long)(I->buf + I->space - I->end)); - fclose(file); - } -} - -/* common filters api */ - -/* sizes of filter states on x64 -size of iof_filter: 640 (no longer used; sizeof(iof) + sizeof larger state) -size of file_state: 16 -size of stream_state: 16 -size of flate_state: 104 -size of lzw_state: 56 -size of predictor_state: 104 -size of basexx_state: 48 -size of basexx_state: 48 -size of basexx_state: 48 -size of eexec_state: 40 -size of runlength_state: 24 -size of rc4_state: 24 -size of aes_state: 72 -size of img_state: 576 -size of img: 496 -*/ - -typedef struct iof_heap iof_heap; - -struct iof_heap { - uint8_t *data, *pos; - size_t size, space; - iof_heap *next, *prev; - int refcount; -}; - -typedef struct { - iof_heap *heap; -} iof_heap_ghost; - -static iof_heap * iof_buffers_heap = NULL; -static iof_heap * iof_filters_heap = NULL; - -#define IOF_HEAP_FILTERS_COUNT 4 -#define IOF_BUFFER_SIZE 262144 // (1<<18) -#define IOF_FILTER_SIZE 1024 -// sizeof(iof_filter) on x64 is now 640, img_state 576, img 496, others 16-104 -#define IOF_BUFFER_HEAP_SIZE (IOF_HEAP_FILTERS_COUNT * (IOF_BUFFER_SIZE + sizeof(iof_heap_ghost))) -#define IOF_FILTER_HEAP_SIZE (IOF_HEAP_FILTERS_COUNT * (IOF_FILTER_SIZE + sizeof(iof_heap_ghost))) - -static iof_heap * iof_heap_new (size_t space) -{ - iof_heap *iofheap; - iofheap = (iof_heap *)util_malloc(sizeof(iof_heap) + space); - iofheap->data = iofheap->pos = (uint8_t *)(iofheap + 1); - iofheap->size = iofheap->space = space; - iofheap->next = NULL; - iofheap->prev = NULL; - iofheap->refcount = 0; - return iofheap; -} - -#define iof_heap_free(iofheap) util_free(iofheap) - -void iof_filters_init (void) -{ - if (iof_buffers_heap == NULL) - iof_buffers_heap = iof_heap_new(IOF_BUFFER_HEAP_SIZE); - if (iof_filters_heap == NULL) - iof_filters_heap = iof_heap_new(IOF_FILTER_HEAP_SIZE); -} - -void iof_filters_free (void) -{ - iof_heap *heap, *next; - for (heap = iof_buffers_heap; heap != NULL; heap = next) - { - next = heap->next; - if (heap->refcount != 0) - loggerf("not closed iof filters left (%d)", heap->refcount); - if (next != NULL) - loggerf("iof filters heap left"); - iof_heap_free(heap); - } - iof_buffers_heap = NULL; - for (heap = iof_filters_heap; heap != NULL; heap = next) - { - next = heap->next; - if (heap->refcount != 0) - loggerf("not closed iof buffers left (%d)", heap->refcount); - if (next != NULL) - loggerf("iof buffers heap left"); - iof_heap_free(heap); - } - iof_filters_heap = NULL; -} - -#define iof_heap_get(hp, ghost, data, siz) \ - (ghost = (iof_heap_ghost *)((hp)->pos), \ - ghost->heap = hp, \ - data = (uint8_t *)(ghost + 1), \ - (hp)->pos += siz, \ - (hp)->size -= siz, \ - ++(hp)->refcount) - - -static void * iof_heap_take (iof_heap **pheap, size_t size) -{ - uint8_t *data; - iof_heap_ghost *ghost; - iof_heap *heap, *newheap, *next; - - heap = *pheap; - size += sizeof(iof_heap_ghost); - if (heap->size >= size) - { /* take cheap mem from main heap */ - iof_heap_get(heap, ghost, data, size); - return data; - } - if (size <= heap->space >> 1) - { /* make new cheap heap, make it front */ - *pheap = newheap = iof_heap_new(heap->space); - newheap->next = heap; - heap->prev = newheap; - iof_heap_get(newheap, ghost, data, size); - return data; - } - /* size much larger than expected? should not happen. - make a single-item heap, keep the front heap intact. */ - newheap = iof_heap_new(size); - if ((next = heap->next) != NULL) - { - newheap->next = next; - next->prev = newheap; - } - heap->next = newheap; - newheap->prev = heap; - iof_heap_get(newheap, ghost, data, size); - return data; -} - -void iof_heap_back (void *data) -{ - iof_heap_ghost *ghost; - iof_heap *heap, *next, *prev; - - ghost = ((iof_heap_ghost *)data) - 1; - heap = ghost->heap; - if (heap->refcount == 0) - loggerf("invalid use of iof heap, refcount < 0"); - if (--heap->refcount <= 0) - { - if ((prev = heap->prev) != NULL) - { /* free the heap */ - if ((next = heap->next) != NULL) - prev->next = next, next->prev = prev; - else - prev->next = NULL; - iof_heap_free(heap); - } - else - { /* this is the front heap, just reset */ - heap->pos = heap->data; - heap->size = heap->space; - } - } -} - -void * iof_filter_new (size_t size) -{ // to be removed - void *data; - - iof_filters_init(); - data = iof_heap_take(&iof_filters_heap, size); - return memset(data, 0, size); -} - -static uint8_t * iof_filter_buffer_new (size_t *psize) -{ - iof_filters_init(); - *psize = IOF_BUFFER_SIZE; - return iof_heap_take(&iof_buffers_heap, IOF_BUFFER_SIZE); -} - -iof * iof_filter_reader_new (iof_handler handler, size_t statesize, void **pstate) -{ - iof *F; - void *filter; - uint8_t *buffer; - size_t buffersize; - - iof_filters_init(); - filter = iof_heap_take(&iof_filters_heap, sizeof(iof) + statesize); - F = (iof *)memset(filter, 0, sizeof(iof) + statesize); - buffer = iof_filter_buffer_new(&buffersize); - iof_reader_buffer(F, buffer, buffersize); - F->flags |= IOF_HEAP|IOF_BUFFER_HEAP; - F->more = handler; - *pstate = (F + 1); - return F; -} - -iof * iof_filter_reader_with_buffer_new (iof_handler handler, size_t statesize, void **pstate, void *buffer, size_t buffersize) -{ // for filters that has own buffer (string, some image filters) - iof *F; - void *filter; - iof_filters_init(); - filter = iof_heap_take(&iof_filters_heap, sizeof(iof) + statesize); - F = (iof *)memset(filter, 0, sizeof(iof) + statesize); - iof_reader_buffer(F, buffer, buffersize); - F->flags |= IOF_HEAP; - F->more = handler; - *pstate = (F + 1); - return F; -} - -iof * iof_filter_writer_new (iof_handler handler, size_t statesize, void **pstate) -{ - iof *F; - void *filter; - uint8_t *buffer; - size_t buffersize; - - iof_filters_init(); - filter = iof_heap_take(&iof_filters_heap, sizeof(iof) + statesize); - F = (iof *)memset(filter, 0, sizeof(iof) + statesize); - buffer = iof_filter_buffer_new(&buffersize); - iof_writer_buffer(F, buffer, buffersize); - F->flags |= IOF_HEAP|IOF_BUFFER_HEAP; - F->more = handler; - *pstate = (F + 1); - return F; -} - -iof * iof_filter_writer_with_buffer_new (iof_handler handler, size_t statesize, void **pstate, void *buffer, size_t size) -{ - iof *F; - void *filter; - size_t buffersize; - - iof_filters_init(); - filter = iof_heap_take(&iof_filters_heap, sizeof(iof) + statesize); - F = (iof *)memset(filter, 0, sizeof(iof) + statesize); - buffer = iof_filter_buffer_new(&buffersize); - iof_writer_buffer(F, buffer, buffersize); - F->flags |= IOF_HEAP; - F->more = handler; - *pstate = (F + 1); - return F; -} - -/* close */ - -#define iof_close_next(F) ((void)(iof_decref((F)->next), (F)->next = NULL, 0)) -/* when filter creation fails, we should take care to destroy the filter but leave ->next intact */ -#define iof_clear_next(F) ((void)(iof_unref((F)->next), (F)->next = NULL, 0)) - -#define iof_close_buffer(F) ((void)\ - ((F)->buf != NULL ? \ - ((F->flags & IOF_BUFFER_ALLOC) ? (util_free((F)->buf), (F)->buf = NULL, 0) : \ - ((F->flags & IOF_BUFFER_HEAP) ? (iof_filter_buffer_free((F)->buf), (F)->buf = NULL, 0) : ((F)->buf = NULL, 0))) : 0)) - -/* closing underlying file handle */ - -static void iof_close_file (iof *F) -{ - FILE *file; - //if (F->flags & IOF_FILE_HANDLE) - //{ - if ((file = F->file) != NULL) - { - if (F->flags & IOF_CLOSE_FILE) - fclose(F->file); - F->file = NULL; - } - //} -} - -/* a very special variant for reader filters initiated with iof_file_reopen(). It also calls - iof_file_reclose(), which takes an effect only if previously reopened, but better to keep - all this thin ice separated. Used in filters: iofile_reader, iofile_stream_reader, image - decoders. */ - -static void iof_close_iofile (iof *F) -{ - iof_file *iofile; - //if (F->flags & IOF_FILE) - //{ - if ((iofile = F->iofile) != NULL) - { - iof_file_unsync(iofile, NULL); - iof_file_reclose(iofile); // takes an effect iff prevoiusly reopened - iof_file_decref(iofile); - F->iofile = NULL; - } - //} -} - -void iof_free (iof *F) -{ - if (F->flags & IOF_FILE_HANDLE) - iof_close_file(F); - else if (F->flags & IOF_FILE) - iof_close_iofile(F); - else if (F->flags & IOF_NEXT) - iof_close_next(F); - iof_close_buffer(F); - if (F->flags & IOF_HEAP) - iof_filter_free(F); - else if (F->flags & IOF_ALLOC) - util_free(F); -} - -void iof_discard (iof *F) -{ // so far used only on failed filters creation; as iof_free() but don't dare to release ->next - if (F->flags & IOF_FILE_HANDLE) - iof_close_file(F); - else if (F->flags & IOF_FILE) - iof_close_iofile(F); - else if (F->flags & IOF_NEXT) - iof_close_next(F); - iof_close_buffer(F); - if (F->flags & IOF_HEAP) - iof_filter_free(F); - else if (F->flags & IOF_ALLOC) - util_free(F); -} - -/* resizing buffer */ - -size_t iof_resize_buffer_to (iof *O, size_t space) -{ - uint8_t *buf; - - if (O->flags & IOF_BUFFER_ALLOC) - { - buf = (uint8_t *)util_realloc(O->buf, space); - } - else - { - buf = (uint8_t *)util_malloc(space); - memcpy(buf, O->buf, iof_size(O)); - if (O->flags & IOF_BUFFER_HEAP) - { - iof_filter_buffer_free(O->buf); - O->flags &= ~IOF_BUFFER_HEAP; - } - O->flags |= IOF_BUFFER_ALLOC; - - } - O->pos = buf + iof_size(O); - O->end = buf + space; - O->buf = buf; - O->space = space; - return iof_left(O); -} - -/* */ - -size_t iof_decoder_retval (iof *I, const char *type, iof_status status) -{ - switch (status) - { - case IOFERR: - case IOFEMPTY: // should never happen as we set state.flush = 1 on decoders init - loggerf("%s decoder error (%d, %s)", type, status, iof_status_kind(status)); - I->flags |= IOF_STOPPED; - return 0; - case IOFEOF: // this is the last chunk, - I->flags |= IOF_STOPPED; // so stop it and fall - case IOFFULL: // prepare pointers to read from I->buf - I->end = I->pos; - I->pos = I->buf; - return I->end - I->buf; - } - loggerf("%s decoder bug, invalid retval %d", type, status); - return 0; -} - -size_t iof_encoder_retval (iof *O, const char *type, iof_status status) -{ - switch (status) - { - case IOFERR: - case IOFFULL: - loggerf("%s encoder error (%d, %s)", type, status, iof_status_kind(status)); - return 0; - case IOFEMPTY: - O->pos = O->buf; - O->end = O->buf + O->space; - return O->space; - case IOFEOF: - return 0; - } - loggerf("%s encoder bug, invalid retval %d", type, status); - return 0; -} - -/* file/stream state */ - -typedef struct { - size_t length; - size_t offset; -} file_state; - - -#define file_state_init(state, off, len) ((state)->offset = off, (state)->length = len) - -typedef struct { - size_t length; - size_t offset; -} stream_state; - -#define stream_state_init(state, off, len) ((state)->offset = off, (state)->length = len) - -static size_t file_read (iof *I) -{ - size_t bytes, tail; - if (I->flags & IOF_STOPPED) - return 0; - tail = iof_tail(I); - if ((bytes = tail + fread(I->buf + tail, sizeof(uint8_t), I->space - tail, I->file)) < I->space) - I->flags |= IOF_STOPPED; - I->pos = I->buf; - I->end = I->buf + bytes; - return bytes; -} - -static size_t iofile_read (iof *I, size_t *poffset) -{ - size_t bytes, tail; - if (I->flags & IOF_STOPPED) - return 0; - iof_file_sync(I->iofile, poffset); - tail = iof_tail(I); - if ((bytes = tail + iof_file_read(I->buf + tail, sizeof(uint8_t), I->space - tail, I->iofile)) < I->space) - { - I->flags |= IOF_STOPPED; - iof_file_unsync(I->iofile, poffset); - } - I->pos = I->buf; - I->end = I->buf + bytes; - return bytes; -} - -static size_t file_load (iof *I) -{ - size_t bytes, left, tail; - if (I->flags & IOF_STOPPED) - return 0; - tail = iof_tail(I); - I->pos = I->buf + tail; - I->end = I->buf + I->space; /* don't assume its done when initializing the filter */ - left = I->space - tail; - do { - bytes = fread(I->pos, sizeof(uint8_t), left, I->file); - I->pos += bytes; - } while (bytes == left && (left = iof_resize_buffer(I)) > 0); - I->flags |= IOF_STOPPED; - return iof_loaded(I); -} - -static size_t iofile_load (iof *I, size_t *poffset) -{ - size_t bytes, left, tail; - if (I->flags & IOF_STOPPED) - return 0; - tail = iof_tail(I); - I->pos = I->buf + tail; - I->end = I->buf + I->space; /* don't assume its done when initializing the filter */ - left = I->space - tail; - iof_file_sync(I->iofile, poffset); - do { - bytes = iof_file_read(I->pos, sizeof(uint8_t), left, I->iofile); - I->pos += bytes; - } while (bytes == left && (left = iof_resize_buffer(I)) > 0); - I->flags |= IOF_STOPPED; - iof_file_unsync(I->iofile, poffset); - return iof_loaded(I); -} - -static size_t filter_file_reader (iof *I, iof_mode mode) -{ - switch (mode) - { - case IOFREAD: - return file_read(I); - case IOFLOAD: - return file_load(I); - case IOFCLOSE: - iof_free(I); - return 0; - default: - return 0; - } -} - -static size_t filter_iofile_reader (iof *I, iof_mode mode) -{ - file_state *state; - state = iof_filter_state(file_state *, I); - switch (mode) - { - case IOFREAD: - return iofile_read(I, &state->offset); - case IOFLOAD: - return iofile_load(I, &state->offset); - case IOFCLOSE: - iof_free(I); - return 0; - default: - return 0; - } -} - -static size_t file_write (iof *O, int flush) -{ - size_t bytes; - if ((bytes = iof_size(O)) > 0) - if (bytes != fwrite(O->buf, sizeof(uint8_t), bytes, O->file)) - return 0; - if (flush) - fflush(O->file); - O->end = O->buf + O->space; // remains intact actually - O->pos = O->buf; - return O->space; -} - -static size_t iofile_write (iof *O, size_t *poffset, int flush) -{ - size_t bytes; - iof_file_sync(O->iofile, poffset); - if ((bytes = iof_size(O)) > 0) - { - if (bytes != iof_file_write(O->buf, sizeof(uint8_t), bytes, O->iofile)) - { - iof_file_unsync(O->iofile, poffset); - return 0; - } - } - if (flush) - iof_file_flush(O->iofile); - O->end = O->buf + O->space; // remains intact actually - O->pos = O->buf; - return O->space; -} - -static size_t filter_file_writer (iof *O, iof_mode mode) -{ - switch (mode) - { - case IOFWRITE: - return file_write(O, 0); - case IOFFLUSH: - return file_write(O, 1); - case IOFCLOSE: - file_write(O, 1); - iof_free(O); - return 0; - default: - return 0; - } -} - -static size_t filter_iofile_writer (iof *O, iof_mode mode) -{ - file_state *state; - state = iof_filter_state(file_state *, O); - switch (mode) - { - case IOFWRITE: - return iofile_write(O, &state->offset, 0); - case IOFFLUSH: - return iofile_write(O, &state->offset, 1); - case IOFCLOSE: - iofile_write(O, &state->offset, 1); - iof_free(O); - return 0; - default: - return 0; - } -} - -/* filter from FILE* */ - -iof * iof_filter_file_handle_reader (FILE *file) -{ - iof *I; - file_state *state; - if (file == NULL) - return NULL; - I = iof_filter_reader(filter_file_reader, sizeof(file_state), &state); - iof_setup_file(I, file); - file_state_init(state, 0, 0); - return I; -} - -iof * iof_filter_file_handle_writer (FILE *file) -{ - iof *O; - file_state *state; - if (file == NULL) - return NULL; - O = iof_filter_writer(filter_file_writer, sizeof(file_state), &state); - iof_setup_file(O, file); - file_state_init(state, 0, 0); - return O; -} - -/* filter from iof_file * */ - -iof * iof_filter_iofile_reader (iof_file *iofile, size_t offset) -{ - iof *I; - file_state *state; - if (!iof_file_reopen(iofile)) - return NULL; - I = iof_filter_reader(filter_iofile_reader, sizeof(file_state), &state); - iof_setup_iofile(I, iofile); - file_state_init(state, offset, 0); - return I; -} - -iof * iof_filter_iofile_writer (iof_file *iofile, size_t offset) -{ - iof *O; - file_state *state; - O = iof_filter_writer(filter_iofile_writer, sizeof(file_state), &state); - iof_setup_iofile(O, iofile); - file_state_init(state, offset, 0); - return O; -} - -/* filter from filename */ - -iof * iof_filter_file_reader (const char *filename) -{ - iof *I; - file_state *state; - FILE *file; - if ((file = fopen(filename, "rb")) == NULL) - return NULL; - I = iof_filter_reader(filter_file_reader, sizeof(file_state), &state); - iof_setup_file(I, file); - file_state_init(state, 0, 0); - I->flags |= IOF_CLOSE_FILE; - return I; -} - -iof * iof_filter_file_writer (const char *filename) -{ - iof *O; - file_state *state; - FILE *file; - if ((file = fopen(filename, "wb")) == NULL) - return NULL; - O = iof_filter_writer(filter_file_writer, sizeof(file_state), &state); - iof_setup_file(O, file); - file_state_init(state, 0, 0); - O->flags |= IOF_CLOSE_FILE; - return O; -} - -/* from string */ - -static size_t dummy_handler (iof *I, iof_mode mode) -{ - switch (mode) - { - case IOFCLOSE: - iof_free(I); - return 0; - default: - return 0; - } -} - -iof * iof_filter_string_reader (const void *s, size_t length) -{ - iof *I; - void *dummy; - I = iof_filter_reader_with_buffer(dummy_handler, 0, &dummy, NULL, 0); - I->rbuf = I->rpos = (const uint8_t *)s; - I->rend = (const uint8_t *)s + length; - // I->space = length; - return I; -} - -iof * iof_filter_string_writer (const void *s, size_t length) -{ - iof *O; - void *dummy; - O = iof_filter_reader_with_buffer(dummy_handler, 0, &dummy, NULL, 0); - O->rbuf = O->rpos = (const uint8_t *)s; - O->rend = (const uint8_t *)s + length; - // O->space = length; - return O; -} - -iof * iof_filter_buffer_writer (size_t size) -{ // filter alternative of iof_buffer_create() - iof *O; - void *dummy; - uint8_t *buffer; - if (size > IOF_BUFFER_SIZE) - { - buffer = (uint8_t *)util_malloc(size); - O = iof_filter_writer_with_buffer(iof_mem_handler, 0, &dummy, buffer, size); - O->flags |= IOF_BUFFER_ALLOC; - return O; - } - return iof_filter_writer(iof_mem_handler, 0, &dummy); -} - -/* stream */ - -static size_t file_stream_read (iof *I, size_t *plength) -{ - size_t bytes, tail; - if (I->flags & IOF_STOPPED || *plength == 0) - return 0; - tail = iof_tail(I); - if (I->space - tail >= *plength) - { - bytes = tail + fread(I->buf + tail, sizeof(uint8_t), *plength, I->file); - I->flags |= IOF_STOPPED; - *plength = 0; - } - else - { - bytes = tail + fread(I->buf + tail, sizeof(uint8_t), I->space - tail, I->file); - *plength -= bytes - tail; - } - I->pos = I->buf; - I->end = I->buf + bytes; - return bytes; -} - -static size_t iofile_stream_read (iof *I, size_t *plength, size_t *poffset) -{ - size_t bytes, tail; - if (I->flags & IOF_STOPPED || *plength == 0) - return 0; - tail = iof_tail(I); - iof_file_sync(I->iofile, poffset); - if (I->space - tail >= *plength) - { - bytes = tail + iof_file_read(I->buf + tail, sizeof(uint8_t), *plength, I->iofile); - iof_file_unsync(I->iofile, poffset); - I->flags |= IOF_STOPPED; - *plength = 0; - } - else - { - bytes = tail + iof_file_read(I->buf + tail, sizeof(uint8_t), I->space - tail, I->iofile); - *plength -= bytes - tail; - } - I->pos = I->buf; - I->end = I->buf + bytes; - return bytes; -} - -static size_t file_stream_load (iof *I, size_t *plength) -{ - size_t bytes, tail; - if (I->flags & IOF_STOPPED || *plength == 0) - return 0; - tail = iof_tail(I); - if (I->space - tail < *plength) - if (iof_resize_buffer_to(I, tail + *plength) == 0) - return 0; - bytes = tail + fread(I->buf + tail, sizeof(uint8_t), *plength, I->file); - I->flags |= IOF_STOPPED; - *plength = 0; - I->pos = I->buf; - I->end = I->buf + bytes; - return bytes; -} - -static size_t iofile_stream_load (iof *I, size_t *plength, size_t *poffset) -{ - size_t bytes, tail; - if (I->flags & IOF_STOPPED || *plength == 0) - return 0; - iof_file_sync(I->iofile, poffset); - tail = iof_tail(I); - if (I->space - tail < *plength) - if (iof_resize_buffer_to(I, tail + *plength) == 0) - return 0; - bytes = tail + iof_file_read(I->buf + tail, sizeof(uint8_t), *plength, I->iofile); - iof_file_unsync(I->iofile, poffset); - I->flags |= IOF_STOPPED; - *plength = 0; - I->pos = I->buf; - I->end = I->buf + bytes; - return bytes; -} - -static size_t filter_file_stream_reader (iof *I, iof_mode mode) -{ - stream_state *state; - state = iof_filter_state(stream_state *, I); - switch(mode) - { - case IOFREAD: - return file_stream_read(I, &state->length); - case IOFLOAD: - return file_stream_load(I, &state->length); - case IOFCLOSE: - iof_free(I); - return 0; - default: - return 0; - } -} - -static size_t filter_iofile_stream_reader (iof *I, iof_mode mode) -{ - stream_state *state; - state = iof_filter_state(stream_state *, I); - switch(mode) - { - case IOFREAD: - return iofile_stream_read(I, &state->length, &state->offset); - case IOFLOAD: - return iofile_stream_load(I, &state->length, &state->offset); - case IOFCLOSE: - iof_free(I); - return 0; - default: - return 0; - } -} - -iof * iof_filter_stream_reader (FILE *file, size_t offset, size_t length) -{ - iof *I; - stream_state *state; - I = iof_filter_reader(filter_file_stream_reader, sizeof(stream_state), &state); - iof_setup_file(I, file); - stream_state_init(state, offset, length); - fseek(file, (long)offset, SEEK_SET); // or perhaps it should be call in file_stream_read(), like iof_file_sync()? - return I; -} - -iof * iof_filter_stream_coreader (iof_file *iofile, size_t offset, size_t length) -{ - iof *I; - stream_state *state; - if (!iof_file_reopen(iofile)) - return NULL; - I = iof_filter_reader(filter_iofile_stream_reader, sizeof(stream_state), &state); - iof_setup_iofile(I, iofile); - stream_state_init(state, offset, length); - return I; -} - -static size_t file_stream_write (iof *O, size_t *plength, int flush) -{ - size_t bytes; - if ((bytes = iof_size(O)) > 0) - { - if (bytes != fwrite(O->buf, sizeof(uint8_t), bytes, O->file)) - { - *plength += bytes; - return 0; - } - } - if (flush) - fflush(O->file); - *plength += bytes; - O->end = O->buf + O->space; // remains intact - O->pos = O->buf; - return O->space; -} - -static size_t iofile_stream_write (iof *O, size_t *plength, size_t *poffset, int flush) -{ - size_t bytes; - if ((bytes = iof_size(O)) > 0) - { - iof_file_sync(O->iofile, poffset); - if (bytes != iof_file_write(O->buf, sizeof(uint8_t), bytes, O->iofile)) - { - *plength += bytes; - iof_file_unsync(O->iofile, poffset); - return 0; - } - } - if (flush) - iof_file_flush(O->iofile); - *plength += bytes; - O->end = O->buf + O->space; // remains intact - O->pos = O->buf; - return O->space; -} - -static size_t filter_file_stream_writer (iof *O, iof_mode mode) -{ - stream_state *state; - state = iof_filter_state(stream_state *, O); - switch (mode) - { - case IOFWRITE: - return file_stream_write(O, &state->length, 0); - case IOFFLUSH: - return file_stream_write(O, &state->length, 1); - case IOFCLOSE: - file_stream_write(O, &state->length, 1); - iof_free(O); - return 0; - default: - return 0; - } -} - -static size_t filter_iofile_stream_writer (iof *O, iof_mode mode) -{ - stream_state *state; - state = iof_filter_state(stream_state *, O); - switch (mode) - { - case IOFWRITE: - return iofile_stream_write(O, &state->length, &state->offset, 0); - case IOFFLUSH: - return iofile_stream_write(O, &state->length, &state->offset, 1); - case IOFCLOSE: - iofile_stream_write(O, &state->length, &state->offset, 1); - iof_free(O); - return 0; - default: - return 0; - } -} - -iof * iof_filter_stream_writer (FILE *file) -{ - iof *O; - stream_state *state; - O = iof_filter_writer(filter_file_stream_writer, sizeof(stream_state), &state); - iof_setup_file(O, file); - stream_state_init(state, 0, 0); - return O; -} - -iof * iof_filter_stream_cowriter (iof_file *iofile, size_t offset) -{ - iof *O; - stream_state *state; - O = iof_filter_writer(filter_iofile_stream_writer, sizeof(stream_state), &state); - iof_setup_iofile(O, iofile); - stream_state_init(state, offset, 0); - return O; -} - -/* very specific for images; get input from already created strem filter, exchange the filter but keep the buffer */ - -FILE * iof_filter_file_reader_source (iof *I, size_t *poffset, size_t *plength) -{ - stream_state *sstate; - file_state *fstate; - if (I->more == filter_file_stream_reader) // I is the result of iof_filter_stream_reader() - { - sstate = iof_filter_state(stream_state *, I); - *poffset = sstate->offset; - *plength = sstate->length; // might be 0 but it is ok for file readers - return I->file; - } - if (I->more == filter_file_reader) - { - fstate = iof_filter_state(file_state *, I); - *poffset = fstate->offset; - *plength = fstate->length; // might be 0 but it is ok for file readers - return I->file; - } - return NULL; -} - -iof_file * iof_filter_file_coreader_source (iof *I, size_t *poffset, size_t *plength) -{ - stream_state *sstate; - file_state *fstate; - if (I->more == filter_iofile_stream_reader) // I is the result of iof_filter_stream_coreader() - { - sstate = iof_filter_state(stream_state *, I); - *poffset = sstate->offset; - *plength = sstate->length; - return I->iofile; - } - if (I->more == filter_iofile_reader) - { - fstate = iof_filter_state(file_state *, I); - *poffset = fstate->offset; - *plength = fstate->length; - return I->iofile; - } - return NULL; -} - -iof * iof_filter_reader_replacement (iof *P, iof_handler handler, size_t statesize, void **pstate) -{ // called after iof_filter_file_reader_source(), no need to check if F is filter from iof heap and if has buffer from iof heap - iof *F; - F = iof_filter_reader_with_buffer(handler, statesize, pstate, P->buf, P->space); - F->flags |= IOF_BUFFER_HEAP; - //iof_reader_buffer(P, NULL, 0); - //P->flags &= ~IOF_BUFFER_HEAP; - iof_filter_free(P); - return F; -} - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Build/source/texk/web2c/luatexdir/luapplib/util/utilsha.c-OK b/Build/source/texk/web2c/luatexdir/luapplib/util/utilsha.c-OK deleted file mode 100644 index a4dc6865a82..00000000000 --- a/Build/source/texk/web2c/luatexdir/luapplib/util/utilsha.c-OK +++ /dev/null @@ -1,1198 +0,0 @@ -/* sha2 implementation by Aaron D. Gifford (http://www.aarongifford.com) */ - -#define BYTE_ORDER LITTLE_ENDIAN - -/* begin of sha2.c */ - -/* - * FILE: sha2.c - * AUTHOR: Aaron D. Gifford - http://www.aarongifford.com/ - * - * Copyright (c) 2000-2001, Aaron D. Gifford - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the copyright holder nor the names of contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTOR(S) ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTOR(S) BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $Id: sha2.c,v 1.1 2001/11/08 00:01:51 adg Exp adg $ - */ - -#include <string.h> /* memcpy()/memset() or bcopy()/bzero() */ -#include <assert.h> /* assert() */ -//#include "sha2.h" -#include "utilsha.h" - -/* - * ASSERT NOTE: - * Some sanity checking code is included using assert(). On my FreeBSD - * system, this additional code can be removed by compiling with NDEBUG - * defined. Check your own systems manpage on assert() to see how to - * compile WITHOUT the sanity checking code on your system. - * - * UNROLLED TRANSFORM LOOP NOTE: - * You can define SHA2_UNROLL_TRANSFORM to use the unrolled transform - * loop version for the hash transform rounds (defined using macros - * later in this file). Either define on the command line, for example: - * - * cc -DSHA2_UNROLL_TRANSFORM -o sha2 sha2.c sha2prog.c - * - * or define below: - * - * #define SHA2_UNROLL_TRANSFORM - * - */ - - -/*** SHA-256/384/512 Machine Architecture Definitions *****************/ -/* - * BYTE_ORDER NOTE: - * - * Please make sure that your system defines BYTE_ORDER. If your - * architecture is little-endian, make sure it also defines - * LITTLE_ENDIAN and that the two (BYTE_ORDER and LITTLE_ENDIAN) are - * equivilent. - * - * If your system does not define the above, then you can do so by - * hand like this: - * - * #define LITTLE_ENDIAN 1234 - * #define BIG_ENDIAN 4321 - * - * And for little-endian machines, add: - * - * #define BYTE_ORDER LITTLE_ENDIAN - * - * Or for big-endian machines: - * - * #define BYTE_ORDER BIG_ENDIAN - * - * The FreeBSD machine this was written on defines BYTE_ORDER - * appropriately by including <sys/types.h> (which in turn includes - * <machine/endian.h> where the appropriate definitions are actually - * made). - */ -#if !defined(BYTE_ORDER) || (BYTE_ORDER != LITTLE_ENDIAN && BYTE_ORDER != BIG_ENDIAN) -#error Define BYTE_ORDER to be equal to either LITTLE_ENDIAN or BIG_ENDIAN -#endif - -/* - * Define the followingsha2_* types to types of the correct length on - * the native archtecture. Most BSD systems and Linux define u_intXX_t - * types. Machines with very recent ANSI C headers, can use the - * uintXX_t definintions from inttypes.h by defining SHA2_USE_INTTYPES_H - * during compile or in the sha.h header file. - * - * Machines that support neither u_intXX_t nor inttypes.h's uintXX_t - * will need to define these three typedefs below (and the appropriate - * ones in sha.h too) by hand according to their system architecture. - * - * Thank you, Jun-ichiro itojun Hagino, for suggesting using u_intXX_t - * types and pointing out recent ANSI C support for uintXX_t in inttypes.h. - * - * PJ: replace by uintX_t - */ - -//typedef uint8_t sha2_byte; /* Exactly 1 byte */ -//typedef uint32_t sha2_word32; /* Exactly 4 bytes */ -//typedef uint64_t sha2_word64; /* Exactly 8 bytes */ - -/*** SHA-256/384/512 Various Length Definitions ***********************/ -/* NOTE: Most of these are in sha2.h */ -#define SHA256_SHORT_BLOCK_LENGTH (SHA256_BLOCK_LENGTH - 8) -#define SHA384_SHORT_BLOCK_LENGTH (SHA384_BLOCK_LENGTH - 16) -#define SHA512_SHORT_BLOCK_LENGTH (SHA512_BLOCK_LENGTH - 16) - - -/*** ENDIAN REVERSAL MACROS *******************************************/ -#if BYTE_ORDER == LITTLE_ENDIAN -#define REVERSE32(w,x) { \ - uint32_t tmp = (w); \ - tmp = (tmp >> 16) | (tmp << 16); \ - (x) = ((tmp & 0xff00ff00UL) >> 8) | ((tmp & 0x00ff00ffUL) << 8); \ -} -#define REVERSE64(w,x) { \ - uint64_t tmp = (w); \ - tmp = (tmp >> 32) | (tmp << 32); \ - tmp = ((tmp & 0xff00ff00ff00ff00ULL) >> 8) | \ - ((tmp & 0x00ff00ff00ff00ffULL) << 8); \ - (x) = ((tmp & 0xffff0000ffff0000ULL) >> 16) | \ - ((tmp & 0x0000ffff0000ffffULL) << 16); \ -} -#endif /* BYTE_ORDER == LITTLE_ENDIAN */ - -/* - * Macro for incrementally adding the unsigned 64-bit integer n to the - * unsigned 128-bit integer (represented using a two-element array of - * 64-bit words): - */ -#define ADDINC128(w,n) { \ - (w)[0] += (uint64_t)(n); \ - if ((w)[0] < (n)) { \ - (w)[1]++; \ - } \ -} - -/* - * Macros for copying blocks of memory and for zeroing out ranges - * of memory. Using these macros makes it easy to switch from - * using memset()/memcpy() and using bzero()/bcopy(). - * - * Please define either SHA2_USE_MEMSET_MEMCPY or define - * SHA2_USE_BZERO_BCOPY depending on which function set you - * choose to use: - */ -#if !defined(SHA2_USE_MEMSET_MEMCPY) && !defined(SHA2_USE_BZERO_BCOPY) -/* Default to memset()/memcpy() if no option is specified */ -#define SHA2_USE_MEMSET_MEMCPY 1 -#endif -#if defined(SHA2_USE_MEMSET_MEMCPY) && defined(SHA2_USE_BZERO_BCOPY) -/* Abort with an error if BOTH options are defined */ -#error Define either SHA2_USE_MEMSET_MEMCPY or SHA2_USE_BZERO_BCOPY, not both! -#endif - -#ifdef SHA2_USE_MEMSET_MEMCPY -#define MEMSET_BZERO(p,l) memset((p), 0, (l)) -#define MEMCPY_BCOPY(d,s,l) memcpy((d), (s), (l)) -#endif -#ifdef SHA2_USE_BZERO_BCOPY -#define MEMSET_BZERO(p,l) bzero((p), (l)) -#define MEMCPY_BCOPY(d,s,l) bcopy((s), (d), (l)) -#endif - - -/*** THE SIX LOGICAL FUNCTIONS ****************************************/ -/* - * Bit shifting and rotation (used by the six SHA-XYZ logical functions: - * - * NOTE: The naming of R and S appears backwards here (R is a SHIFT and - * S is a ROTATION) because the SHA-256/384/512 description document - * (see http://csrc.nist.gov/cryptval/shs/sha256-384-512.pdf) uses this - * same "backwards" definition. - */ -/* Shift-right (used in SHA-256, SHA-384, and SHA-512): */ -#define R(b,x) ((x) >> (b)) -/* 32-bit Rotate-right (used in SHA-256): */ -#define S32(b,x) (((x) >> (b)) | ((x) << (32 - (b)))) -/* 64-bit Rotate-right (used in SHA-384 and SHA-512): */ -#define S64(b,x) (((x) >> (b)) | ((x) << (64 - (b)))) - -/* Two of six logical functions used in SHA-256, SHA-384, and SHA-512: */ -#define Ch(x,y,z) (((x) & (y)) ^ ((~(x)) & (z))) -#define Maj(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z))) - -/* Four of six logical functions used in SHA-256: */ -#define Sigma0_256(x) (S32(2, (x)) ^ S32(13, (x)) ^ S32(22, (x))) -#define Sigma1_256(x) (S32(6, (x)) ^ S32(11, (x)) ^ S32(25, (x))) -#define sigma0_256(x) (S32(7, (x)) ^ S32(18, (x)) ^ R(3 , (x))) -#define sigma1_256(x) (S32(17, (x)) ^ S32(19, (x)) ^ R(10, (x))) - -/* Four of six logical functions used in SHA-384 and SHA-512: */ -#define Sigma0_512(x) (S64(28, (x)) ^ S64(34, (x)) ^ S64(39, (x))) -#define Sigma1_512(x) (S64(14, (x)) ^ S64(18, (x)) ^ S64(41, (x))) -#define sigma0_512(x) (S64( 1, (x)) ^ S64( 8, (x)) ^ R( 7, (x))) -#define sigma1_512(x) (S64(19, (x)) ^ S64(61, (x)) ^ R( 6, (x))) - -/*** INTERNAL FUNCTION PROTOTYPES *************************************/ -/* NOTE: These should not be accessed directly from outside this - * library -- they are intended for private internal visibility/use - * only. - */ -static void SHA512_Last(SHA512_CTX*); -static void SHA256_Transform(SHA256_CTX*, const uint32_t*); -static void SHA512_Transform(SHA512_CTX*, const uint64_t*); - - -/*** SHA-XYZ INITIAL HASH VALUES AND CONSTANTS ************************/ -/* Hash constant words K for SHA-256: */ -static const uint32_t K256[64] = { - 0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, - 0x3956c25bUL, 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL, - 0xd807aa98UL, 0x12835b01UL, 0x243185beUL, 0x550c7dc3UL, - 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL, 0xc19bf174UL, - 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL, - 0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL, - 0x983e5152UL, 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL, - 0xc6e00bf3UL, 0xd5a79147UL, 0x06ca6351UL, 0x14292967UL, - 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL, 0x53380d13UL, - 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL, - 0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL, - 0xd192e819UL, 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL, - 0x19a4c116UL, 0x1e376c08UL, 0x2748774cUL, 0x34b0bcb5UL, - 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL, 0x682e6ff3UL, - 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL, - 0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL -}; - -/* Initial hash value H for SHA-256: */ -static const uint32_t sha256_initial_hash_value[8] = { - 0x6a09e667UL, - 0xbb67ae85UL, - 0x3c6ef372UL, - 0xa54ff53aUL, - 0x510e527fUL, - 0x9b05688cUL, - 0x1f83d9abUL, - 0x5be0cd19UL -}; - -/* Hash constant words K for SHA-384 and SHA-512: */ -static const uint64_t K512[80] = { - 0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL, - 0xb5c0fbcfec4d3b2fULL, 0xe9b5dba58189dbbcULL, - 0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL, - 0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL, - 0xd807aa98a3030242ULL, 0x12835b0145706fbeULL, - 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL, - 0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL, - 0x9bdc06a725c71235ULL, 0xc19bf174cf692694ULL, - 0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL, - 0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL, - 0x2de92c6f592b0275ULL, 0x4a7484aa6ea6e483ULL, - 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL, - 0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL, - 0xb00327c898fb213fULL, 0xbf597fc7beef0ee4ULL, - 0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL, - 0x06ca6351e003826fULL, 0x142929670a0e6e70ULL, - 0x27b70a8546d22ffcULL, 0x2e1b21385c26c926ULL, - 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL, - 0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL, - 0x81c2c92e47edaee6ULL, 0x92722c851482353bULL, - 0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL, - 0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL, - 0xd192e819d6ef5218ULL, 0xd69906245565a910ULL, - 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL, - 0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL, - 0x2748774cdf8eeb99ULL, 0x34b0bcb5e19b48a8ULL, - 0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL, - 0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL, - 0x748f82ee5defb2fcULL, 0x78a5636f43172f60ULL, - 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL, - 0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL, - 0xbef9a3f7b2c67915ULL, 0xc67178f2e372532bULL, - 0xca273eceea26619cULL, 0xd186b8c721c0c207ULL, - 0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL, - 0x06f067aa72176fbaULL, 0x0a637dc5a2c898a6ULL, - 0x113f9804bef90daeULL, 0x1b710b35131c471bULL, - 0x28db77f523047d84ULL, 0x32caab7b40c72493ULL, - 0x3c9ebe0a15c9bebcULL, 0x431d67c49c100d4cULL, - 0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL, - 0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL -}; - -/* Initial hash value H for SHA-384 */ -static const uint64_t sha384_initial_hash_value[8] = { - 0xcbbb9d5dc1059ed8ULL, - 0x629a292a367cd507ULL, - 0x9159015a3070dd17ULL, - 0x152fecd8f70e5939ULL, - 0x67332667ffc00b31ULL, - 0x8eb44a8768581511ULL, - 0xdb0c2e0d64f98fa7ULL, - 0x47b5481dbefa4fa4ULL -}; - -/* Initial hash value H for SHA-512 */ -static const uint64_t sha512_initial_hash_value[8] = { - 0x6a09e667f3bcc908ULL, - 0xbb67ae8584caa73bULL, - 0x3c6ef372fe94f82bULL, - 0xa54ff53a5f1d36f1ULL, - 0x510e527fade682d1ULL, - 0x9b05688c2b3e6c1fULL, - 0x1f83d9abfb41bd6bULL, - 0x5be0cd19137e2179ULL -}; - -/* - * Constant used by SHA256/384/512_End() functions for converting the - * digest to a readable hexadecimal character string: - */ - -//static const char *sha2_hex_digits = "0123456789abcdef"; // PJ - - -/*** SHA-256: *********************************************************/ -static void SHA256_Init(SHA256_CTX* context) { - if (context == (SHA256_CTX*)0) { - return; - } - MEMCPY_BCOPY(context->state, sha256_initial_hash_value, SHA256_DIGEST_LENGTH); - MEMSET_BZERO(context->buffer, SHA256_BLOCK_LENGTH); - context->bitcount = 0; -} - -#ifdef SHA2_UNROLL_TRANSFORM - -/* Unrolled SHA-256 round macros: */ - -#if BYTE_ORDER == LITTLE_ENDIAN - -#define ROUND256_0_TO_15(a,b,c,d,e,f,g,h) \ - REVERSE32(*data++, W256[j]); \ - T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + \ - K256[j] + W256[j]; \ - (d) += T1; \ - (h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \ - j++ - - -#else /* BYTE_ORDER == LITTLE_ENDIAN */ - -#define ROUND256_0_TO_15(a,b,c,d,e,f,g,h) \ - T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + \ - K256[j] + (W256[j] = *data++); \ - (d) += T1; \ - (h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \ - j++ - -#endif /* BYTE_ORDER == LITTLE_ENDIAN */ - -#define ROUND256(a,b,c,d,e,f,g,h) \ - s0 = W256[(j+1)&0x0f]; \ - s0 = sigma0_256(s0); \ - s1 = W256[(j+14)&0x0f]; \ - s1 = sigma1_256(s1); \ - T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + K256[j] + \ - (W256[j&0x0f] += s1 + W256[(j+9)&0x0f] + s0); \ - (d) += T1; \ - (h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \ - j++ - -void SHA256_Transform(SHA256_CTX* context, const uint32_t* data) { - uint32_t a, b, c, d, e, f, g, h, s0, s1; - uint32_t T1, *W256; - int j; - - W256 = (uint32_t*)context->buffer; - - /* Initialize registers with the prev. intermediate value */ - a = context->state[0]; - b = context->state[1]; - c = context->state[2]; - d = context->state[3]; - e = context->state[4]; - f = context->state[5]; - g = context->state[6]; - h = context->state[7]; - - j = 0; - do { - /* Rounds 0 to 15 (unrolled): */ - ROUND256_0_TO_15(a,b,c,d,e,f,g,h); - ROUND256_0_TO_15(h,a,b,c,d,e,f,g); - ROUND256_0_TO_15(g,h,a,b,c,d,e,f); - ROUND256_0_TO_15(f,g,h,a,b,c,d,e); - ROUND256_0_TO_15(e,f,g,h,a,b,c,d); - ROUND256_0_TO_15(d,e,f,g,h,a,b,c); - ROUND256_0_TO_15(c,d,e,f,g,h,a,b); - ROUND256_0_TO_15(b,c,d,e,f,g,h,a); - } while (j < 16); - - /* Now for the remaining rounds to 64: */ - do { - ROUND256(a,b,c,d,e,f,g,h); - ROUND256(h,a,b,c,d,e,f,g); - ROUND256(g,h,a,b,c,d,e,f); - ROUND256(f,g,h,a,b,c,d,e); - ROUND256(e,f,g,h,a,b,c,d); - ROUND256(d,e,f,g,h,a,b,c); - ROUND256(c,d,e,f,g,h,a,b); - ROUND256(b,c,d,e,f,g,h,a); - } while (j < 64); - - /* Compute the current intermediate hash value */ - context->state[0] += a; - context->state[1] += b; - context->state[2] += c; - context->state[3] += d; - context->state[4] += e; - context->state[5] += f; - context->state[6] += g; - context->state[7] += h; - - /* Clean up */ - a = b = c = d = e = f = g = h = T1 = 0; -} - -#else /* SHA2_UNROLL_TRANSFORM */ - -static void SHA256_Transform(SHA256_CTX* context, const uint32_t* data) { - uint32_t a, b, c, d, e, f, g, h, s0, s1; - uint32_t T1, T2, *W256; - int j; - - W256 = (uint32_t*)context->buffer; - - /* Initialize registers with the prev. intermediate value */ - a = context->state[0]; - b = context->state[1]; - c = context->state[2]; - d = context->state[3]; - e = context->state[4]; - f = context->state[5]; - g = context->state[6]; - h = context->state[7]; - - j = 0; - do { -#if BYTE_ORDER == LITTLE_ENDIAN - /* Copy data while converting to host byte order */ - REVERSE32(*data++,W256[j]); - /* Apply the SHA-256 compression function to update a..h */ - T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + W256[j]; -#else /* BYTE_ORDER == LITTLE_ENDIAN */ - /* Apply the SHA-256 compression function to update a..h with copy */ - T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + (W256[j] = *data++); -#endif /* BYTE_ORDER == LITTLE_ENDIAN */ - T2 = Sigma0_256(a) + Maj(a, b, c); - h = g; - g = f; - f = e; - e = d + T1; - d = c; - c = b; - b = a; - a = T1 + T2; - - j++; - } while (j < 16); - - do { - /* Part of the message block expansion: */ - s0 = W256[(j+1)&0x0f]; - s0 = sigma0_256(s0); - s1 = W256[(j+14)&0x0f]; - s1 = sigma1_256(s1); - - /* Apply the SHA-256 compression function to update a..h */ - T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + - (W256[j&0x0f] += s1 + W256[(j+9)&0x0f] + s0); - T2 = Sigma0_256(a) + Maj(a, b, c); - h = g; - g = f; - f = e; - e = d + T1; - d = c; - c = b; - b = a; - a = T1 + T2; - - j++; - } while (j < 64); - - /* Compute the current intermediate hash value */ - context->state[0] += a; - context->state[1] += b; - context->state[2] += c; - context->state[3] += d; - context->state[4] += e; - context->state[5] += f; - context->state[6] += g; - context->state[7] += h; - - /* Clean up */ - a = b = c = d = e = f = g = h = T1 = T2 = 0; -} - -#endif /* SHA2_UNROLL_TRANSFORM */ - -static void SHA256_Update(SHA256_CTX* context, const uint8_t *data, size_t len) { - unsigned int freespace, usedspace; - - if (len == 0) { - /* Calling with no data is valid - we do nothing */ - return; - } - - /* Sanity check: */ - assert(context != (SHA256_CTX*)0 && data != (uint8_t*)0); - - usedspace = (context->bitcount >> 3) % SHA256_BLOCK_LENGTH; - if (usedspace > 0) { - /* Calculate how much free space is available in the buffer */ - freespace = SHA256_BLOCK_LENGTH - usedspace; - - if (len >= freespace) { - /* Fill the buffer completely and process it */ - MEMCPY_BCOPY(&context->buffer[usedspace], data, freespace); - context->bitcount += freespace << 3; - len -= freespace; - data += freespace; - SHA256_Transform(context, (uint32_t*)context->buffer); - } else { - /* The buffer is not yet full */ - MEMCPY_BCOPY(&context->buffer[usedspace], data, len); - context->bitcount += len << 3; - /* Clean up: */ - usedspace = freespace = 0; - return; - } - } - while (len >= SHA256_BLOCK_LENGTH) { - /* Process as many complete blocks as we can */ - SHA256_Transform(context, (const uint32_t*)data); - context->bitcount += SHA256_BLOCK_LENGTH << 3; - len -= SHA256_BLOCK_LENGTH; - data += SHA256_BLOCK_LENGTH; - } - if (len > 0) { - /* There's left-overs, so save 'em */ - MEMCPY_BCOPY(context->buffer, data, len); - context->bitcount += len << 3; - } - /* Clean up: */ - usedspace = freespace = 0; -} - -static void SHA256_Final(uint8_t digest[], SHA256_CTX* context) { - uint32_t *d = (uint32_t*)digest; - unsigned int usedspace; - - /* Sanity check: */ - assert(context != (SHA256_CTX*)0); - - /* If no digest buffer is passed, we don't bother doing this: */ - if (digest != (uint8_t*)0) { - usedspace = (context->bitcount >> 3) % SHA256_BLOCK_LENGTH; -#if BYTE_ORDER == LITTLE_ENDIAN - /* Convert FROM host byte order */ - REVERSE64(context->bitcount,context->bitcount); -#endif - if (usedspace > 0) { - /* Begin padding with a 1 bit: */ - context->buffer[usedspace++] = 0x80; - - if (usedspace <= SHA256_SHORT_BLOCK_LENGTH) { - /* Set-up for the last transform: */ - MEMSET_BZERO(&context->buffer[usedspace], SHA256_SHORT_BLOCK_LENGTH - usedspace); - } else { - if (usedspace < SHA256_BLOCK_LENGTH) { - MEMSET_BZERO(&context->buffer[usedspace], SHA256_BLOCK_LENGTH - usedspace); - } - /* Do second-to-last transform: */ - SHA256_Transform(context, (uint32_t*)context->buffer); - - /* And set-up for the last transform: */ - MEMSET_BZERO(context->buffer, SHA256_SHORT_BLOCK_LENGTH); - } - } else { - /* Set-up for the last transform: */ - MEMSET_BZERO(context->buffer, SHA256_SHORT_BLOCK_LENGTH); - - /* Begin padding with a 1 bit: */ - *context->buffer = 0x80; - } - /* Set the bit count: */ - //*(uint64_t*)&context->buffer[SHA256_SHORT_BLOCK_LENGTH] = context->bitcount; // aliasing violation warning - context->buffer64[SHA256_SHORT_BLOCK_LENGTH / sizeof(uint64_t)] = context->bitcount; - - /* Final transform: */ - SHA256_Transform(context, (uint32_t*)context->buffer); - -#if BYTE_ORDER == LITTLE_ENDIAN - { - /* Convert TO host byte order */ - int j; - for (j = 0; j < 8; j++) { - REVERSE32(context->state[j],context->state[j]); - *d++ = context->state[j]; - } - } -#else - MEMCPY_BCOPY(d, context->state, SHA256_DIGEST_LENGTH); -#endif - } - - /* Clean up state data: */ - MEMSET_BZERO(context, sizeof(*context)); - usedspace = 0; -} - -/* -static char *SHA256_End(SHA256_CTX* context, char buffer[]) { - uint8_t digest[SHA256_DIGEST_LENGTH], *d = digest; - int i; - - / * Sanity check: * / - assert(context != (SHA256_CTX*)0); - - if (buffer != (char*)0) { - SHA256_Final(digest, context); - - for (i = 0; i < SHA256_DIGEST_LENGTH; i++) { - *buffer++ = sha2_hex_digits[(*d & 0xf0) >> 4]; - *buffer++ = sha2_hex_digits[*d & 0x0f]; - d++; - } - *buffer = (char)0; - } else { - MEMSET_BZERO(context, sizeof(context)); - } - MEMSET_BZERO(digest, SHA256_DIGEST_LENGTH); - return buffer; -} - -static char* SHA256_Data(const uint8_t* data, size_t len, char digest[SHA256_DIGEST_STRING_LENGTH]) { - SHA256_CTX context; - - SHA256_Init(&context); - SHA256_Update(&context, data, len); - return SHA256_End(&context, digest); -} -*/ - - -/*** SHA-512: *********************************************************/ -static void SHA512_Init(SHA512_CTX* context) { - if (context == (SHA512_CTX*)0) { - return; - } - MEMCPY_BCOPY(context->state, sha512_initial_hash_value, SHA512_DIGEST_LENGTH); - MEMSET_BZERO(context->buffer, SHA512_BLOCK_LENGTH); - context->bitcount[0] = context->bitcount[1] = 0; -} - -#ifdef SHA2_UNROLL_TRANSFORM - -/* Unrolled SHA-512 round macros: */ -#if BYTE_ORDER == LITTLE_ENDIAN - -#define ROUND512_0_TO_15(a,b,c,d,e,f,g,h) \ - REVERSE64(*data++, W512[j]); \ - T1 = (h) + Sigma1_512(e) + Ch((e), (f), (g)) + \ - K512[j] + W512[j]; \ - (d) += T1, \ - (h) = T1 + Sigma0_512(a) + Maj((a), (b), (c)), \ - j++ - - -#else /* BYTE_ORDER == LITTLE_ENDIAN */ - -#define ROUND512_0_TO_15(a,b,c,d,e,f,g,h) \ - T1 = (h) + Sigma1_512(e) + Ch((e), (f), (g)) + \ - K512[j] + (W512[j] = *data++); \ - (d) += T1; \ - (h) = T1 + Sigma0_512(a) + Maj((a), (b), (c)); \ - j++ - -#endif /* BYTE_ORDER == LITTLE_ENDIAN */ - -#define ROUND512(a,b,c,d,e,f,g,h) \ - s0 = W512[(j+1)&0x0f]; \ - s0 = sigma0_512(s0); \ - s1 = W512[(j+14)&0x0f]; \ - s1 = sigma1_512(s1); \ - T1 = (h) + Sigma1_512(e) + Ch((e), (f), (g)) + K512[j] + \ - (W512[j&0x0f] += s1 + W512[(j+9)&0x0f] + s0); \ - (d) += T1; \ - (h) = T1 + Sigma0_512(a) + Maj((a), (b), (c)); \ - j++ - -static void SHA512_Transform(SHA512_CTX* context, const uint64_t* data) { - uint64_t a, b, c, d, e, f, g, h, s0, s1; - uint64_t T1, *W512 = (uint64_t*)context->buffer; - int j; - - /* Initialize registers with the prev. intermediate value */ - a = context->state[0]; - b = context->state[1]; - c = context->state[2]; - d = context->state[3]; - e = context->state[4]; - f = context->state[5]; - g = context->state[6]; - h = context->state[7]; - - j = 0; - do { - ROUND512_0_TO_15(a,b,c,d,e,f,g,h); - ROUND512_0_TO_15(h,a,b,c,d,e,f,g); - ROUND512_0_TO_15(g,h,a,b,c,d,e,f); - ROUND512_0_TO_15(f,g,h,a,b,c,d,e); - ROUND512_0_TO_15(e,f,g,h,a,b,c,d); - ROUND512_0_TO_15(d,e,f,g,h,a,b,c); - ROUND512_0_TO_15(c,d,e,f,g,h,a,b); - ROUND512_0_TO_15(b,c,d,e,f,g,h,a); - } while (j < 16); - - /* Now for the remaining rounds up to 79: */ - do { - ROUND512(a,b,c,d,e,f,g,h); - ROUND512(h,a,b,c,d,e,f,g); - ROUND512(g,h,a,b,c,d,e,f); - ROUND512(f,g,h,a,b,c,d,e); - ROUND512(e,f,g,h,a,b,c,d); - ROUND512(d,e,f,g,h,a,b,c); - ROUND512(c,d,e,f,g,h,a,b); - ROUND512(b,c,d,e,f,g,h,a); - } while (j < 80); - - /* Compute the current intermediate hash value */ - context->state[0] += a; - context->state[1] += b; - context->state[2] += c; - context->state[3] += d; - context->state[4] += e; - context->state[5] += f; - context->state[6] += g; - context->state[7] += h; - - /* Clean up */ - a = b = c = d = e = f = g = h = T1 = 0; -} - -#else /* SHA2_UNROLL_TRANSFORM */ - -static void SHA512_Transform(SHA512_CTX* context, const uint64_t* data) { - uint64_t a, b, c, d, e, f, g, h, s0, s1; - uint64_t T1, T2, *W512 = (uint64_t*)context->buffer; - int j; - - /* Initialize registers with the prev. intermediate value */ - a = context->state[0]; - b = context->state[1]; - c = context->state[2]; - d = context->state[3]; - e = context->state[4]; - f = context->state[5]; - g = context->state[6]; - h = context->state[7]; - - j = 0; - do { -#if BYTE_ORDER == LITTLE_ENDIAN - /* Convert TO host byte order */ - REVERSE64(*data++, W512[j]); - /* Apply the SHA-512 compression function to update a..h */ - T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] + W512[j]; -#else /* BYTE_ORDER == LITTLE_ENDIAN */ - /* Apply the SHA-512 compression function to update a..h with copy */ - T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] + (W512[j] = *data++); -#endif /* BYTE_ORDER == LITTLE_ENDIAN */ - T2 = Sigma0_512(a) + Maj(a, b, c); - h = g; - g = f; - f = e; - e = d + T1; - d = c; - c = b; - b = a; - a = T1 + T2; - - j++; - } while (j < 16); - - do { - /* Part of the message block expansion: */ - s0 = W512[(j+1)&0x0f]; - s0 = sigma0_512(s0); - s1 = W512[(j+14)&0x0f]; - s1 = sigma1_512(s1); - - /* Apply the SHA-512 compression function to update a..h */ - T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] + - (W512[j&0x0f] += s1 + W512[(j+9)&0x0f] + s0); - T2 = Sigma0_512(a) + Maj(a, b, c); - h = g; - g = f; - f = e; - e = d + T1; - d = c; - c = b; - b = a; - a = T1 + T2; - - j++; - } while (j < 80); - - /* Compute the current intermediate hash value */ - context->state[0] += a; - context->state[1] += b; - context->state[2] += c; - context->state[3] += d; - context->state[4] += e; - context->state[5] += f; - context->state[6] += g; - context->state[7] += h; - - /* Clean up */ - a = b = c = d = e = f = g = h = T1 = T2 = 0; -} - -#endif /* SHA2_UNROLL_TRANSFORM */ - -static void SHA512_Update(SHA512_CTX* context, const uint8_t *data, size_t len) { - unsigned int freespace, usedspace; - - if (len == 0) { - /* Calling with no data is valid - we do nothing */ - return; - } - - /* Sanity check: */ - assert(context != (SHA512_CTX*)0 && data != (uint8_t*)0); - - usedspace = (context->bitcount[0] >> 3) % SHA512_BLOCK_LENGTH; - if (usedspace > 0) { - /* Calculate how much free space is available in the buffer */ - freespace = SHA512_BLOCK_LENGTH - usedspace; - - if (len >= freespace) { - /* Fill the buffer completely and process it */ - MEMCPY_BCOPY(&context->buffer[usedspace], data, freespace); - ADDINC128(context->bitcount, freespace << 3); - len -= freespace; - data += freespace; - SHA512_Transform(context, (uint64_t*)context->buffer); - } else { - /* The buffer is not yet full */ - MEMCPY_BCOPY(&context->buffer[usedspace], data, len); - ADDINC128(context->bitcount, len << 3); - /* Clean up: */ - usedspace = freespace = 0; - return; - } - } - while (len >= SHA512_BLOCK_LENGTH) { - /* Process as many complete blocks as we can */ - SHA512_Transform(context, (const uint64_t*)data); - ADDINC128(context->bitcount, SHA512_BLOCK_LENGTH << 3); - len -= SHA512_BLOCK_LENGTH; - data += SHA512_BLOCK_LENGTH; - } - if (len > 0) { - /* There's left-overs, so save 'em */ - MEMCPY_BCOPY(context->buffer, data, len); - ADDINC128(context->bitcount, len << 3); - } - /* Clean up: */ - usedspace = freespace = 0; -} - -static void SHA512_Last(SHA512_CTX* context) { - unsigned int usedspace; - - usedspace = (context->bitcount[0] >> 3) % SHA512_BLOCK_LENGTH; -#if BYTE_ORDER == LITTLE_ENDIAN - /* Convert FROM host byte order */ - REVERSE64(context->bitcount[0],context->bitcount[0]); - REVERSE64(context->bitcount[1],context->bitcount[1]); -#endif - if (usedspace > 0) { - /* Begin padding with a 1 bit: */ - context->buffer[usedspace++] = 0x80; - - if (usedspace <= SHA512_SHORT_BLOCK_LENGTH) { - /* Set-up for the last transform: */ - MEMSET_BZERO(&context->buffer[usedspace], SHA512_SHORT_BLOCK_LENGTH - usedspace); - } else { - if (usedspace < SHA512_BLOCK_LENGTH) { - MEMSET_BZERO(&context->buffer[usedspace], SHA512_BLOCK_LENGTH - usedspace); - } - /* Do second-to-last transform: */ - SHA512_Transform(context, (uint64_t*)context->buffer); - - /* And set-up for the last transform: */ - MEMSET_BZERO(context->buffer, SHA512_BLOCK_LENGTH - 2); - } - } else { - /* Prepare for final transform: */ - MEMSET_BZERO(context->buffer, SHA512_SHORT_BLOCK_LENGTH); - - /* Begin padding with a 1 bit: */ - *context->buffer = 0x80; - } - /* Store the length of input data (in bits): */ - //*(uint64_t*)&context->buffer[SHA512_SHORT_BLOCK_LENGTH] = context->bitcount[1]; // aliasing violation warning - //*(uint64_t*)&context->buffer[SHA512_SHORT_BLOCK_LENGTH+8] = context->bitcount[0]; - context->buffer64[SHA512_SHORT_BLOCK_LENGTH / sizeof(uint64_t)] = context->bitcount[1]; - context->buffer64[SHA512_SHORT_BLOCK_LENGTH / sizeof(uint64_t) + 1] = context->bitcount[0]; - - /* Final transform: */ - SHA512_Transform(context, (uint64_t*)context->buffer); -} - -static void SHA512_Final(uint8_t digest[], SHA512_CTX* context) { - uint64_t *d = (uint64_t*)digest; - - /* Sanity check: */ - assert(context != (SHA512_CTX*)0); - - /* If no digest buffer is passed, we don't bother doing this: */ - if (digest != (uint8_t*)0) { - SHA512_Last(context); - - /* Save the hash data for output: */ -#if BYTE_ORDER == LITTLE_ENDIAN - { - /* Convert TO host byte order */ - int j; - for (j = 0; j < 8; j++) { - REVERSE64(context->state[j],context->state[j]); - *d++ = context->state[j]; - } - } -#else - MEMCPY_BCOPY(d, context->state, SHA512_DIGEST_LENGTH); -#endif - } - - /* Zero out state data */ - MEMSET_BZERO(context, sizeof(*context)); -} - -/* -static char *SHA512_End(SHA512_CTX* context, char buffer[]) { - uint8_t digest[SHA512_DIGEST_LENGTH], *d = digest; - int i; - - / * Sanity check: * / - assert(context != (SHA512_CTX*)0); - - if (buffer != (char*)0) { - SHA512_Final(digest, context); - - for (i = 0; i < SHA512_DIGEST_LENGTH; i++) { - *buffer++ = sha2_hex_digits[(*d & 0xf0) >> 4]; - *buffer++ = sha2_hex_digits[*d & 0x0f]; - d++; - } - *buffer = (char)0; - } else { - MEMSET_BZERO(context, sizeof(context)); - } - MEMSET_BZERO(digest, SHA512_DIGEST_LENGTH); - return buffer; -} - -static char* SHA512_Data(const uint8_t* data, size_t len, char digest[SHA512_DIGEST_STRING_LENGTH]) { - SHA512_CTX context; - - SHA512_Init(&context); - SHA512_Update(&context, data, len); - return SHA512_End(&context, digest); -} -*/ - -/*** SHA-384: *********************************************************/ -static void SHA384_Init(SHA384_CTX* context) { - if (context == (SHA384_CTX*)0) { - return; - } - MEMCPY_BCOPY(context->state, sha384_initial_hash_value, SHA512_DIGEST_LENGTH); - MEMSET_BZERO(context->buffer, SHA384_BLOCK_LENGTH); - context->bitcount[0] = context->bitcount[1] = 0; -} - -static void SHA384_Update(SHA384_CTX* context, const uint8_t* data, size_t len) { - SHA512_Update((SHA512_CTX*)context, data, len); -} - -static void SHA384_Final(uint8_t digest[], SHA384_CTX* context) { - uint64_t *d = (uint64_t*)digest; - - /* Sanity check: */ - assert(context != (SHA384_CTX*)0); - - /* If no digest buffer is passed, we don't bother doing this: */ - if (digest != (uint8_t*)0) { - SHA512_Last((SHA512_CTX*)context); - - /* Save the hash data for output: */ -#if BYTE_ORDER == LITTLE_ENDIAN - { - /* Convert TO host byte order */ - int j; - for (j = 0; j < 6; j++) { - REVERSE64(context->state[j],context->state[j]); - *d++ = context->state[j]; - } - } -#else - MEMCPY_BCOPY(d, context->state, SHA384_DIGEST_LENGTH); -#endif - } - - /* Zero out state data */ - MEMSET_BZERO(context, sizeof(*context)); -} - -/* -static char *SHA384_End(SHA384_CTX* context, char buffer[]) { - uint8_t digest[SHA384_DIGEST_LENGTH], *d = digest; - int i; - - / * Sanity check: * / - assert(context != (SHA384_CTX*)0); - - if (buffer != (char*)0) { - SHA384_Final(digest, context); - - for (i = 0; i < SHA384_DIGEST_LENGTH; i++) { - *buffer++ = sha2_hex_digits[(*d & 0xf0) >> 4]; - *buffer++ = sha2_hex_digits[*d & 0x0f]; - d++; - } - *buffer = (char)0; - } else { - MEMSET_BZERO(context, sizeof(context)); - } - MEMSET_BZERO(digest, SHA384_DIGEST_LENGTH); - return buffer; -} - -static char* SHA384_Data(const uint8_t* data, size_t len, char digest[SHA384_DIGEST_STRING_LENGTH]) { - SHA384_CTX context; - - SHA384_Init(&context); - SHA384_Update(&context, data, len); - return SHA384_End(&context, digest); -} -*/ - -/* end of sha2.c */ - -void sha256_init (sha256_state *state) -{ - SHA256_Init(state); -} - -void sha384_init (sha384_state *state) -{ - SHA384_Init(state); -} - -void sha512_init (sha512_state *state) -{ - SHA512_Init(state); -} - - -void sha256_add (sha256_state *state, const void *data, size_t size) -{ - SHA256_Update(state, (const uint8_t *)data, size); -} - -void sha384_add (sha384_state *state, const void *data, size_t size) -{ - SHA384_Update(state, (const uint8_t *)data, size); -} - -void sha512_add (sha512_state *state, const void *data, size_t size) -{ - SHA512_Update(state, (const uint8_t *)data, size); -} - - -void sha256_put (sha256_state *state, uint8_t digest[SHA256_DIGEST_LENGTH]) -{ - SHA256_Final(digest, state); -} - -void sha384_put (sha384_state *state, uint8_t digest[SHA384_DIGEST_LENGTH]) -{ - SHA384_Final(digest, state); -} - -void sha512_put (sha384_state *state, uint8_t digest[SHA512_DIGEST_LENGTH]) -{ - SHA512_Final(digest, state); -} - - -void sha256 (const void *data, size_t size, uint8_t digest[SHA256_DIGEST_LENGTH]) -{ - sha256_state state; - SHA256_Init(&state); - SHA256_Update(&state, (const uint8_t *)data, size); - SHA256_Final(digest, &state); -} - -void sha384 (const void *data, size_t size, uint8_t digest[SHA384_DIGEST_LENGTH]) -{ - sha384_state state; - SHA384_Init(&state); - SHA384_Update(&state, (const uint8_t *)data, size); - SHA384_Final(digest, &state); -} - -void sha512 (const void *data, size_t size, uint8_t digest[SHA512_DIGEST_LENGTH]) -{ - sha512_state state; - SHA512_Init(&state); - SHA512_Update(&state, (const uint8_t *)data, size); - SHA512_Final(digest, &state); -} - -static sha256_state sha256state; -static sha384_state sha384state; -static sha512_state sha512state; - - -void sha256init (void) -{ - SHA256_Init(&sha256state); -} - -void sha384init (void) -{ - SHA384_Init(&sha384state); -} - -void sha512init (void) -{ - SHA512_Init(&sha512state); -} - - -void sha256add (const void *data, size_t size) -{ - SHA256_Update(&sha256state, (const uint8_t *)data, size); -} - -void sha384add (const void *data, size_t size) -{ - SHA384_Update(&sha384state, (const uint8_t *)data, size); -} - -void sha512add (const void *data, size_t size) -{ - SHA512_Update(&sha512state, (const uint8_t *)data, size); -} - - -void sha256put (uint8_t digest[SHA256_DIGEST_LENGTH]) -{ - SHA256_Final(digest, &sha256state); -} - -void sha384put (uint8_t digest[SHA384_DIGEST_LENGTH]) -{ - SHA384_Final(digest, &sha384state); -} - -void sha512put (uint8_t digest[SHA512_DIGEST_LENGTH]) -{ - SHA512_Final(digest, &sha512state); -} |