diff options
author | Takuji Tanaka <ttk@t-lab.opal.ne.jp> | 2023-12-23 11:54:37 +0000 |
---|---|---|
committer | Takuji Tanaka <ttk@t-lab.opal.ne.jp> | 2023-12-23 11:54:37 +0000 |
commit | c43df83550585e723134b779da84f7aa3abffe63 (patch) | |
tree | 690bd69bdf241c5456ca84875287a793839f291c /Build | |
parent | 642f1a5c13b63e3c5c634c6050d6a5689a0104f7 (diff) |
pplib: Convert newline from CRLF to LF
git-svn-id: svn://tug.org/texlive/trunk@69200 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Build')
14 files changed, 4289 insertions, 4283 deletions
diff --git a/Build/source/libs/pplib/ChangeLog b/Build/source/libs/pplib/ChangeLog index c42af621816..61229efcebc 100644 --- a/Build/source/libs/pplib/ChangeLog +++ b/Build/source/libs/pplib/ChangeLog @@ -1,3 +1,11 @@ +2023-12-23 TANAKA Takuji <ttk@t-lab.opal.ne.jp> + + * pplib-src/src/util/README.md, + pplib-src/doc/{ppapi-{1,2}.x,ppcode,pplib,ppnew}.rst, + pplib-src/doc/_build/html/_source/{ppapi-{1,2}.x,ppcode,pplib,ppnew}.rst.txt, + doc/_build/html/_static/pygments.css, .gitattributes: + Convert newline from CRLF to LF. + 2023-08-23 TANAKA Takuji <ttk@t-lab.opal.ne.jp> * pplib.test: Make easier to test on Windows. diff --git a/Build/source/libs/pplib/pplib-src/.gitattributes b/Build/source/libs/pplib/pplib-src/.gitattributes index 8d68adf9ae9..cc41365315b 100644 --- a/Build/source/libs/pplib/pplib-src/.gitattributes +++ b/Build/source/libs/pplib/pplib-src/.gitattributes @@ -2,9 +2,7 @@ *.h text=auto eol=lf Makefile text=auto eol=lf -*.rst binary *.png binary *.jpg binary -*.css binary *.html binary -*.js binary
\ No newline at end of file +*.js binary diff --git a/Build/source/libs/pplib/pplib-src/doc/_build/html/_sources/ppapi-1.x.rst.txt b/Build/source/libs/pplib/pplib-src/doc/_build/html/_sources/ppapi-1.x.rst.txt index df661a7b82d..000681acebe 100644 --- a/Build/source/libs/pplib/pplib-src/doc/_build/html/_sources/ppapi-1.x.rst.txt +++ b/Build/source/libs/pplib/pplib-src/doc/_build/html/_sources/ppapi-1.x.rst.txt @@ -1,937 +1,937 @@ -
-``pplib`` 1.x
-=============
-
-``pplib`` is a library for raw PDF access. It parses PDF documents and provides an interface to access document structures in C.
-
-C-API
-=====
-
-Types
------
-
-``pplib`` defines several C-types to represent PDF types:
-
-- ``ppint`` - signed integer (``int64_t``)
-- ``ppnum`` - real number (double)
-- ``ppname`` - PDF name
-- ``ppstring`` - PDF string
-- ``pparray`` - PDF array
-- ``ppdict`` - PDF dict
-- ``ppstream`` - PDF stream
-- ``ppref`` - PDF indirect reference
-- ``ppobj`` - a container of all above
-
-Among ``ppint`` and ``ppnum``, we also use ``ppuint`` - unsigned integer (machine word, alias to ``size_t``).
-
-Other API types:
-
-- ``ppdoc`` - PDF document
-- ``ppxref`` - cross-references table
-- ``ppcontext`` - ... later
-- ``pprect`` - rectangle
-- ``ppmatrix`` - matrix
-
-Integer, number, name and string are treated as simple types.
-Names and strings are actually C-structures, but exposed to API as typedefs to ``const char *``.
-Other types (array, dict, stream, reference, object container, xref, PDF) are C-structures,
-and you operate it their pointers. So when you declare a simple type variable you say::
-
- ppuint u;
- ppnum n;
- ppname name;
- ppstring string;
- ...
-
-And when you declare a compound type you operate on pointers::
-
- ppobj *obj;
- pparray *array;
- ppdict *dict;
- ppstream *stream;
- ppref *ref;
- ppdoc *pdf;
-
-Some of those C-types are defined in library header ``ppapi.h`` (complete types). Some others are incomplete
-(eg. you can't say ``sizeof(ppdoc)`` or ``sizeof(ppxref)``). This is to avoid unnecesary dependencies in
-the header. [At some points it's not clear to me what to hide and what to expose, will see.] The library itself
-uses ``pplib.h`` but for auxilary applications including a standalone ``ppapi.h`` header should be enough.
-
-``pplib`` was designed having **read-only** PDF access in mind. Even if some structure is completelly exposed,
-so that you can directly access its members, you should treat them as read-only. I don't make them ``const`` because
-then all variable declarations would need to be ``const``, which is annoying, and I'd need some trickery in the library
-internals to unconst. Besides, nothing is really const for C type casts.
-
-Object
-------
-
-A common container for all elementary PDF object types is ``ppobj`` structure. ``ppobj`` has a type identifier
-(integer) and union of values::
-
- struct ppobj {
- ppobjtp type;
- union {
- ppint integer;
- ppnum number;
- ppname name;
- ppstring string;
- pparray *array;
- ppdict *dict;
- ppstream *stream;
- ppref *ref;
- void *any;
- };
- };
-
-Object type is one of constants (enum)::
-
- PPNONE
- PPNULL
- PPBOOL
- PPINT
- PPNUM
- PPNAME
- PPSTRING
- PPARRAY
- PPDICT
- PPSTREAM
- PPREF
-
-The type determines the structure member you're allowed to access::
-
- ppobj *obj;
- ...
- switch (obj->type)
- {
- case PPNONE: // shouldn't actually happen, indicates some failure
- break;
- case PPNULL: // valid PDF null object, no value
- break;
- case PPBOOL: // do something with obj->integer (ppint), value 0 or 1
- break;
- case PPINT: // do something with obj->integer (ppint)
- break;
- case PPNUM: // do something with obj->number (ppnum)
- break;
- case PPNAME: // do something with obj->name (ppname)
- break;
- case PPSTRING: // do something with obj->string (ppstring)
- break;
- case PPARRAY: // do something with obj->array (pparray *)
- break;
- case PPDICT: // do something with obj->dict (ppdict *)
- break;
- case PPSTREAM: // do something with obj->stream (ppstream *)
- break;
- case PPREF: // do something with obj->ref (ppref *)
- break;
- }
-
-More often then not you know exactly what type of object value is expected, in which case
-you may use one of the following macros::
-
- // returns 1 if o->type is PPNULL
- int ppobj_get_null(o) \
-
- // if o->type is PPBOOL, sets int v to 0 or 1 and returns 1, 0 otherwise
- int ppobj_get_bool(o, v)
-
- // if o->type is PPINT, sets ppint v and returns 1, 0 otherwise
- int ppobj_get_int(o, v)
-
- // if o->type is PPINT and >= 0, sets ppuint v and returns 1, 0 otherwise
- int ppobj_get_uint(o, v)
-
- // if o->type is PPNUM or PPINT, sets ppnum v and returns 1, 0 otherwise
- int ppobj_get_num(o, v)
-
- // if o->type is PPNAME returns the name, NULL otherwise
- ppname ppobj_get_name(o)
-
- // if o->type is PPSTRING returns the string, NULL otherwise
- ppstring ppobj_get_string(o)
-
- // if o->type is PPARRAY returns the array, NULL otherwise
- pparray * ppobj_get_array(o)
-
- // if o->type is PPDICT returns the dict, NULL otherwise
- ppdict * ppobj_get_dict(o)
-
- // if o->type is PPSTREAM returns the stream, NULL otherwise
- ppstream * ppobj_get_stream(o)
-
- // if o->type is PPREF returns the reference, NULL otherwise
- ppref * ppobj_get_ref(o)
-
-Note the coercion from integer to real number, but not reverse. In practise, whenever you expect a real number,
-you should also handle integer (eg. '1' used instead of '1.0').
-
-It is a common case that the object is given as an indirect reference, but what you actually
-want is not the reference, but the object referred by it. Here is a helper for it::
-
- // if o->type is PPREF, returns what the reference points, otherwise returns o
- ppobj * ppobj_rget_obj(o)
-
-Also every ``ppobj_get_*`` macro has ``ppobj_rget_*`` counterpart that makes a check
-for the expected type, but if the object is PPREF, it jumps to the target object.
-So for example ``ppobj_rget_dict(obj)`` will return dict if ``obj`` is of type PPDICT
-or if it is of type PPREF and ``obj->ref`` hosts an object of type PPDICT.
-
-Names
------
-
-PDF names are represented as ``ppname``.
-I find it convenient to have ``ppname`` type pretending ``const char *``. This allows to use ``ppname``
-in all C-style string functions like ``printf("%s", name)``.
-
-Be aware, however, that ``ppname`` is actually a C-structure. It is perfectly ok to cast ``ppname`` to ``const char *``::
-
- ppname name;
- ...
- (const char *)name;
-
-But reverse is forbidden::
-
- const char *cstr = "cstring";
- ...
- (ppname)cstr; // expect segmentation fault soon
-
-For convenient use in C, names are ``'\0'`` terminated. But to get the length of name better always use
-``ppname_size()`` macro. ``ppname`` object knows its size, don't use ``strlen()``::
-
- size_t ppname_size(ppname name); // macro, returns length of name in bytes
-
-In current implementation names are not hashed anyhow, so name-to-name comparison is not smarter than ``memcmp()``.
-Use macros::
-
- int ppname_is(ppname name, "literal"); // to compare ppname with C-literal string
- int ppname_eq(ppname name, ppname other); // to compare ppname with a different name
-
-If you'll use ``pplib`` to parse contents streams, you may need to distinguish names from operators
-(more precisely executable names). Names in PDF are preceeded by '/', executable names aren't. In both
-cases PDF parser will produce ``ppname`` but can be distingushed with::
-
- int ppname_exec(ppname name); // returns non-zero if name is executable
-
-Names are kept in their raw form, with possible PDF specific escapes (in text below we call it **encoded** form).
-Leading '/' is omitted, though. One may need a decoded name, with no PDF escapes.
-A pair of functions provides a simple interface to switch between those two forms::
-
- ppname ppname_decoded (ppname name); // returns decoded (unescaped) form of the name
- ppname ppname_encoded (ppname name); // returns encoded (escaped) form of the name
-
-In pretty most cases PDF names contains only letters (no special characters, no escapes), so decoded and encoded forms are identical.
-In that case both functions simply return the argument. It is ok to call ``ppname_decoded()`` on already decoded form
-and ``ppname_encoded()`` on already encoded form. Both forms are produced by PDF objects parser, so accessing ``ppname`` alter ego
-in whatever direction needs no extra decoding or allocation costs.
-
-String
-------
-
-PDF strings have the same internal construction as names, so most of names description above applies to strings as well.
-``ppstring`` is a typedef of ``const char *``, roughly ``'\0'`` terminiated C-string. To get the size of the string::
-
- size_t ppstring_size(ppstring string); // macro, returns the length of the string in bytes
-
-Strings are provided in their raw form, preserving PDF specific escapes, but with no
-``()`` or ``<>`` delims. To distinguish plain strings from hex strings::
-
- int ppstring_hex(ppstring string); // macro, returns non zero if hex string
-
-Or if you prefer::
-
- switch (ppstring_type(string))
- {
- case PPSTRING_PLAIN: // literal string, surrounded by ``(`` and ``)`` in PDF
- break;
- case PPSTRING_BASE16: // hex string, surrounded by ``<`` and ``>`` in PDF
- break;
- case PPSTRING_BASE85: // base85 string surrounded by ``<~`` and ``~>`` in PDF
- break;
- }
-
-The last is actually Postscript specific, not used in PDF, but I think it might appear in contents streams...
-No matter how the string is given in PDF (plain or hex), here are two functions to
-switch between encoded and decoded strings forms::
-
- ppstring ppstring_decoded (ppstring string); // returns decoded string possibly with PDF escapes
- ppstring ppstring_encoded (ppstring string); // returns encoded string with no PDF escapes
-
-For hex strings, encoded form contains hex digits, while decoded form contains arbitrary bytes (the result of hex decoding).
-Plain strings usually contains printable ASCII characters, but they might contain any binary data.
-As with names, objects parser produces both forms. The raw form with PDF escapes (or raw hex form) is considered the main one.
-Eg. when you access ``obj->string`` you always get the encoded form. At any moment you can switch to its alter ego.
-
-No matter if the string is plain or hex, if its first two bytes (decoded) are UTF16 BOM, the string
-is considered unicode. ``ppstring`` object *knows* it is unicode or not::
-
- switch (ppstring_utf(string))
- {
- case PPSTRING_UTF16LE: // unicode string, utf16le
- break;
- case PPSTRING_UTF16BE: // unicode string, utf16be
- break;
- default: // no unicode
- }
-
-Or simply::
-
- if (ppstring_utf(string) != 0) {
- // handle unicode string
- }
-
-If the string is unicode, BOM remains the part of the string -- ``pplib`` parser does not strip it.
-Unicode or not, encoded or decoded, strings are always C-arrays of bytes and ``ppstring_size()``
-always returns the size in bytes.
-
-Array
------
-
-PDF arrays are represented as ``pparray`` type, which is C-array of ``ppobj`` structures.
-To get the size::
-
- size_t pparray_size(pparray *array) // macro, returns the number of array items
-
-To get ``ppobj *`` at a given index::
-
- ppobj * pparray_at(array, index) // macro, returns ppobj * (no index check)
- ppobj * pparray_get(array, index) // macro, returns ppobj * or NULL (with index check)
- ppobj * pparray_get_obj (pparray *array, size_t index); // function equiv to pparray_get()
-
-Iterating over array elements::
-
- pparray *array;
- size_t index, size;
- ppobj *obj;
- for (size = pparray_size(array), pparray_first(array, index, obj); index < size; pparray_next(index, obj))
- {
- // do something with index and obj
- }
-
-There is no magic first/next macros, just iteration over pointers. One could also use something like::
-
- for (index = 0, size = array->size; index < size; ++index)
- {
- obj = pparray_at(array, index);
- // do something with index and obj
- }
-
-When getting values from array and expecting a result of known type, use one of the following::
-
- int pparray_get_bool (pparray *array, size_t index, int *v); // get boolean value
- int pparray_get_int (pparray *array, size_t index, ppint *v); // get ppint value
- int pparray_get_uint (pparray *array, size_t index, ppuint *v); // get ppuint value
- int pparray_get_num (pparray *array, size_t index, ppnum *v); // get ppnum value
- ppname pparray_get_name (pparray *array, size_t index); // get ppname value
- ppstring pparray_get_string (pparray *array, size_t index); // get ppstring value
- pparray * pparray_get_array (pparray *array, size_t index); // get pparray * value
- ppdict * pparray_get_dict (pparray *array, size_t index); // get ppdict * value
- ppref * pparray_get_ref (pparray *array, size_t index); // get ppref * value
-
-As with ``ppobj_get_*`` suite, numeric types getters set the value of a given type and returns 1, if the type matches.
-Otherwise sets nothing and returns 0. Other getters return the value if the type matches, or NULL.
-
-Every function from ``pparray_get_*`` suite have its ``pparray_rget_*`` counterpart that
-that dereferences indirect objects (as explained for ``ppobj_rget_*`` getters). Note that
-there is no ``pparray_get_stream()`` function, as streams in PDF are always indirect.
-To get the stream from array use::
-
- ppstream * pparray_rget_stream (pparray *array, size_t index);
-
-Dict
-----
-
-PDF dicts are represented as ``ppdict`` structure, which is C-array of ``ppobj`` with parallel
-C-array of ``ppname`` pointers. To get the size of a dict::
-
- size_t ppdict_size(ppdict *dict) // macro, returns the number of key-val pairs
-
-To get the value at a given index (integer)::
-
- ppobj * ppdict_at(ppdict *dict, index) // macro, no index check
-
-To get the name (key) at a given index::
-
- ppname ppdict_key(ppdict *dict, index) // macro, no index check
-
-To iterate over dict key-val pairs::
-
- ppdict *dict;
- ppname *pkey;
- ppobj *obj;
-
- for (ppdict_first(dict, pkey, obj); *pkey != NULL; ppdict_next(pkey, obj))
- {
- // do something with *pkey and obj
- }
-
-There is no magic in first/next macros, just iteration through keys and values lists pointers.
-For convenient iteration, a list of keys is terminated with NULL, so in the code above ``*pkey != NULL``
-is used as the loop condition. One may also iterate via indices::
-
- ppdict *dict;
- size_t index, size;
- ppname key;
- ppobj *obj;
- for (index = 0, size = ppdict_size(dict); index < size; ++index)
- {
- key = ppdict_key(dict, index);
- obj = ppdict_at(dict, index);
- // do something with key and obj
- }
-
-To get the object associated with a given name, use one of the following::
-
- ppobj * ppdict_get_obj (ppdict *dict, const char *name);
- int ppdict_get_bool (ppdict *dict, const char *name, int *v);
- int ppdict_get_int (ppdict *dict, const char *name, ppint *v);
- int ppdict_get_uint (ppdict *dict, const char *name, ppuint *v);
- int ppdict_get_num (ppdict *dict, const char *name, ppnum *v);
- ppname ppdict_get_name (ppdict *dict, const char *name);
- ppstring ppdict_get_string (ppdict *dict, const char *name);
- pparray * ppdict_get_array (ppdict *dict, const char *name);
- ppdict * ppdict_get_dict (ppdict *dict, const char *name);
- ppref * ppdict_get_ref (ppdict *dict, const char *name);
-
-Note that all getters accepts ``const char *`` as key, so it is ok to say::
-
- ppdict_rget_dict(dict, "Resources");
-
-as well as::
-
- ppdic_rget_dict(dict, name); // ppname name
-
-Every ``ppdict_get_*`` getter has ``ppdict_rget_*`` counterpart that dereferences
-indirect objects if necessary. Note that there is no ``ppdict_get_stream()`` function,
-but there is::
-
- ppstream * ppdict_rget_stream (ppdict *dict, const char *name);
-
-So far dicts comes with no names mapping, so by-name dict accessors perform a linear search
-through the keys list. PDF dicts are usually small, so it is fast enough.
-Building names lookup for every dict in PDF makes no sense I think, as ``pplib`` applications
-will query just several dicts I guess.. However, some apps may extensively query
-resources, which may refer to hundreds of objects (eg. images). So some mapping for dicts
-is still considered.
-
-Stream
-------
-
-PDF streams are represented as ``ppstream`` objects. To get the stream dict::
-
- ppdict * ppstream_dict(ppstream *stream) // macro
-
-To read the stream data::
-
- uint8_t * ppstream_first (ppstream *stream, size_t *size, int decode);
- uint8_t * ppstream_next (ppstream *stream, size_t *size);
- void ppstream_done (ppstream *stream);
-
-Both ``first` and ``next`` functions return a chunk of stream data and sets the ``size`` of the chunk.
-``decode`` parameter tell the reader to decompress the stream (1) or return raw (0). A call to ``ppstream_next()``
-must be preceeded by ``ppstream_first()``. Once you're done with the stream, you have to call ``ppstream_done()``,
-no matter if the stream has been read to the end or not. The stream data iterator in use::
-
- uint8_t *data;
- size_t size;
- ppstream *stream;
- int decode = 1; // 1 - get decompressed, 0 - get raw
-
- for (data = ppstream_first(stream, &size, decode); data != NULL; data = ppstream_next(stream, &size))
- {
- // do something with data and its size
- }
- ppstream_done(stream);
-
-Every subsequent iterator call invalidates the previous reader output, so you have to utilize the returned chunk
-of data just after you ot that. So the following is wrong::
-
- data1 = ppstream_first(stream, &size, 1);
- data2 = ppstream_next(stream, &size);
- data3 = ppstream_next(stream, &size);
- some_output(data1, size);
- some_output(data2, size);
-
-The reader calls usually return the same pointer to internal buffer, just filled with a different data.
-``pplib`` allocates reasonably large buffer and fills that buffer on subsequent calls to the reader.
-
-If the source stream has no compression, using both ``decode == 1`` and ``decode == 0`` should give the same result.
-You can check if the stream is actually compressed with::
-
- ppstream_compressed(stream) // macro, returns non zero if /Filter is present
-
-It might be necessary to load the entire stream data at once::
-
- uint8_t * ppstream_all (ppstream *stream, size_t *size, int decode);
-
-If the initial buffer size is insufficient, it grows until the entire stream data is loaded. You must call
-``ppstream_done(stream)`` after using returned data.
-
-``ppstream_done()`` doesn't invalidate the stream object, it just closes its internal reader.
-The stream itself remains a valid object (eg. one can read it again if necessary),
-but the reader buffer is released. It is actually not freed but kept for future the reuse with that on some other stream,
-but you still need to mark it ready for reuse to avoid allocating a separate buffer for every stream you're going to read.
-
-Stream data readers will return ``NULL`` if you haven't close the previous reader process with ``ppstream_done()``. All below is wrong::
-
- data1 = ppstream_all(stream, &size, 1);
- data2 = ppstream_all(stream, &size, 1); // data2 == NULL
- // or
- data1 = ppstream_first(stream, &size, 1);
- data2 = ppstream_first(stream, &size, 1); // data2 == NULL
- // or
- data1 = ppstream_first(stream, &size, 1);
- data2 = ppstream_all(stream, &size, 1); // data2 == NULL
-
-To avoid unnecessary dependencies, ``pplib`` does not support image filters (``/DCT``, ``/JPX``, ``/JBIG``, ``/CCITT``).
-But it is ok to read the stream with ``decode`` set to 1 on such streams. ``pplib`` assumes that the image is the
-final/target stream form and just returns it as-is. Eg. in the case of JPEG (``/DCT`` filtered) image both calls should
-give the same results::
-
- ppstream_all(jpegstream, &jpegsize, 0); // don't decode, return what's there
- ppstream_all(jpegstream, &jpegsize, 1); // decode but found image filter, effectively the same
-
-A bit more about streams memory. As mentioned, ``pplib`` allocates buffers for stream readers. After ``ppstream_done()``,
-the stream no longer *owns* the buffer space. But the buffer may remain allocated, to be reused with future readers.
-``pplib`` keeps a pool of several buffers. This means, that when you use stream readers, ``pplib`` eats
-some memory (1MB or so) that is not freed, even if no streams are used. And even if you free all objects.
-If you suffer from this, you can optionally use a pair of functions::
-
- void ppstream_init_buffers (void);
- void ppstream_free_buffers (void);
-
-The first initializes buffers pool, unless done so far. Currently ``pplib`` cares of it before opening every stream reader,
-so it is not obligatory. The second frees a pool of buffers. The intended use is to call ``ppstream_init_buffers()`` once
-as kind of library initializer and to call ``ppstream_free_buffers()`` once, as the library finalizer.
-
-Filters
--------
-
-In version v1.00 (20190916) ``ppstream`` API has been extended with filters information.
-``ppstream`` knows its filter(s) and keps it as ``stream->filter``::
-
- // ppstream *stream;
- ppstream_filter *info = &stream->filter;
-
-``ppstream_filter`` is the following structure::
-
- typedef struct {
- ppstreamtp *filters; // c-array of filter identifiers (enum integers)
- ppdict **params; // c-array of ppdict pointers
- size_t count; // number of filters, length of the arrays (typically 1)
- } ppstream_filter;
-
-If ``count > 0`` then ``filters`` member is not NULL. Filters array keeps integer constants::
-
- PPSTREAM_BASE16 /* /ASCIIHexDecode */
- PPSTREAM_BASE85 /* /ASCII85Decode */
- PPSTREAM_RUNLENGTH /* /RunLengthDecode */
- PPSTREAM_FLATE /* /FlateDecode */
- PPSTREAM_LZW /* /LZWDecode */
- PPSTREAM_CCITT /* /CCITTFaxDecode */
- PPSTREAM_DCT /* /DCTDecode */
- PPSTREAM_JBIG2 /* /JBIG2Decode */
- PPSTREAM_JPX /* /JPXDecode */
- PPSTREAM_CRYPT /* /Crypt */
-
-Params array keeps corresponding filter parameters (``/DecodeParms``) if present. ``params`` member is not NULL
-if ``count > 0`` and the stream dict has ``/DecodeParms`` entry. Even if ``params`` is there,
-for every N-th filter, ``params[N]`` may be NULL (corresponding to PDF ``null``).
-
-``stream->filter`` keeps the source stream filter information, which may not correspond to the result of stream readers
-(``ppstream_first()``, ``ppstream_next()``, ``ppstream_all()``). The get the filters info relevant to the result from readers::
-
- void ppstream_filter_info (ppstream *stream, ppstream_filter *info, int decode);
-
-The function fills ``ppstream_filter`` structure according to the expected result from stream readers (example 3 shows
-how to use it to reconstruct ``/Filter`` and ``/DecodeParms`` when copying the stream to some other PDF).
-
-To convert filter identifier (``ppstreamtp``) to a corresponding PDF filter name::
-
- const char * ppstream_filter_name[];
-
-To covert ``ppname`` to filter identifier::
-
- int ppstream_filter_type (ppname filtername, ppstreamtp *filtertype);
- // returns 1 and sets filtertype if filtername is the proper filter name
-
-Additional information about the stream can be fetched from macros::
-
- ppstream_compressed(stream) /* stream->flags & (PPSTREAM_FILTER|PPSTREAM_IMAGE) */
- ppstream_filtered(stream) /* stream->flags & PPSTREAM_FILTER */
- ppstream_image(stream) /* stream->flags * PPSTREAM_IMAGE */
-
-``stream->flags`` is a binary sum of the following::
-
- PPSTREAM_FILTER /* set iff the stream filters list has one of: BASE16, BASE85, RUNLENGTH, FLATE, LZW */
- PPSTREAM_IMAGE /* set iff the stream filters list has one of: CCITT, DCT, JBIG2, JPX */
- PPSTREAM_ENCRYPTED /* set iff the stream is encrypted */
- PPSTREAM_ENCRYPTED_OWN /* set iff the stream has own CRYPT filter */
-
-Note that ``PPSTREAM_COMPRESSED`` is not there any longer, use ``ppstream_compressed()`` instead.
-And there is some more, see ``ppapi.h``.
-
-Ref
----
-
-Indirect objects are represented as ``ppref`` structure. To get the object that the
-reference refers to::
-
- ppobj * ppref_obj(ppref *ref) // macro
-
-``ppref`` structure also keeps the reference number and version, a pointer to cross reference table it belongs
-to and others, but I guess you won't need anything but the referenced object. ``pplib`` parser resolves references
-on-fly. So if there is a dict with indirect objects::
-
- <<
- /Type /Page
- /Resources 123 0 R
- ...
- >>
-
-the parser will produce ``ppdict`` with ``Resources`` key pointing the proper ``ppref *`` value.
-If you need more, access ``ppref`` members::
-
- struct ppref {
- ppobj object; // target object
- ppuint number, version; // identifiers
- size_t offset; // file offset (useless for you, may be zero for compressed objects)
- ppuint length; // the length of the original object data
- ppxref *xref; // cross reference table it belongs to
- };
-
-
-XRef
-----
-
-Cross reference table is exposed as ``ppxref`` (incomplete type, you can only oprate on its pointer).
-To get top document xref::
-
- ppxref * ppdoc_xref (ppdoc *pdf);
-
-To get previous (older) xref::
-
- ppxref * ppxref_prev (ppxref *xref);
-
-To find an object of a given refnumber::
-
- ppref * ppxref_find (ppxref *xref, ppuint refnumber);
-
-[Note: since pplib v0.98 in case of documents with incremental update, ``ppxref_find()`` returns
-the newest available version of a given object rather than the object in a given body.]
-
-PDF
----
-
-PDF document is represented as ``ppdoc`` structure (incomplete type, you can only operate on its pointer).
-To load a document from file::
-
- ppdoc * ppdoc_load (const char *filename);
-
-To load a document from memory data::
-
- ppdoc * ppdoc_mem (const void *data, size_t size);
-
-The data is assumed to be a buffer allocated with ``malloc`` - it is freed when destroying ``ppdoc``.
-
-Both loaders returns ``NULL`` on failure.
-
-To free ``ppdoc`` and all objects it refers to::
-
- void ppdoc_free (ppdoc *pdf);
-
-So far we haven't mention about any explicit object reclaimers. There are no dedicated ``free`` functions
-for other objects. You don't allocate or free objects yourself. ``ppdoc`` object is an owner of all
-beings it refers to. It also means that every object described so far is alive as long as the containing
-``ppdoc`` is alive.
-
-To access main PDF dicts::
-
- ppdict * ppdoc_trailer(ppdoc *pdf); // returns top xref trailer dict
- ppdict * ppdoc_catalog(ppdoc *pdf); // returns catalog referred from the trailer
- ppdict * ppdoc_info(ppdoc *pdf); // returns info dict referred from the trailer
-
-To get the PDF version::
-
- const char * ppdoc_version_string (ppdoc *pdf); // version string
- int ppdoc_version_number (ppdoc *pdf, int *minor); // minor and major numbers
-
-To get the file size of the source PDF document::
-
- size_t ppdoc_file_size (ppdoc *pdf);
-
-To get the number of objects in all xrefs::
-
- ppuint ppdoc_objects (ppdoc *pdf);
-
-To get the approx usage of memory::
-
- size_t ppdoc_memory (ppdoc *pdf, size_t *waste);
-
-Encryption
-----------
-
-``pplib`` handles encrypted (password protected) documents. If a document is encrypted, most of strings and streams are ciphered.
-In that form they are unreadable and rather useless, you can't even rewrite such strings/streams as-is to a different PDF output.
-It is a common practise to *protect* documents with an empty password. Such documents remain readable in Acrobat (just opens them without prompting
-for a password), but some features (eg. printing) may restricted by the application.
-
-When ``pplib`` detects encryption, it follows Acrobat approach and first tries an empty password. If it succeeds, ``pplib`` proceeeds normally, providing
-an access to decrypted strings and streams, as if they weren't ciphered. If the document is protected with non-empty password, ``pplib`` gives
-a way to provide a password and proceed. Until you provide a password, ``ppdoc`` object returned by ``ppdoc_load()`` function has all object wntries
-set to ``null``.
-
-After loading a document you should check encryption status with::
-
- ppcrypt_status ppdoc_crypt_status (ppdoc *pdf);
-
-``ppcrypt_status`` (integer) may have the following values:
-
- ``PPCRYPT_NONE`` - no encryption, go ahead
- ``PPCRYPT_DONE`` - encryption present but password succeeded, go ahead
- ``PPCRYPT_PASS`` - encryption present, need non-empty password
- ``PPCRYPT_FAIL`` - invalid or unsupported encryption (eg. undocumented in pdf spec)
-
-If a password is needed, you can provide one with::
-
- ppcrypt_status ppdoc_crypt_pass (ppdoc *pdf, const void *userpass, size_t userpasslength,
- const void *ownerpass, size_t ownerpasslength);
-
-Well, yes, there are actually two passwords in encrypted documents. Relation between them is obscure to me, but enough
-to know that having one of them is enough to decrypt the document. If you know the password, you probably mean
-``userpass``, in which case you should put ``NULL`` as ``ownerpass``. The function returns ``PPCRYPT_DONE`` if the password
-succeeds and the previous status otherwise. Your custom loader function may look like that::
-
- ppdoc *pdf;
- pdf = ppdoc_load("file.pdf");
- if (pdf == NULL)
- return NULL;
- switch (ppdoc_crypt_status(pdf))
- {
- case PPCRYPT_NONE:
- case PPCRYPT_DONE:
- return pdf;
- case PPCRYPT_PASS:
- if (ppdoc_crypt_pass(pdf, "dummy", 5, NULL, 0) == PPCRYPT_DONE ||
- ppdoc_crypt_pass(pdf, NULL, 0, "dummy", 5) == PPCRYPT_DONE)
- return pdf;
- printf("sorry, password needed\n");
- ppdoc_free(pdf);
- return NULL;
- case PPCRYPT_FAIL:
- printf("sorry, encryption failed\n");
- ppdoc_free(pdf);
- return NULL;
- }
-
-[If you get ``PPCRYPT_FAIL`` it might mean *I failed*, so treat as a bug.]
-
-If you'd like to know what permissions are given/restricted to encrypted document::
-
- ppint ppdoc_permissions (ppdoc *pdf);
-
-Returned value can be queried with the following binary flags (you can verify with Acrobat *File -> Properties -> Security* tab)::
-
- PPDOC_ALLOW_PRINT // printing
- PPDOC_ALLOW_MODIFY // filling form fields, signing, creating template pages
- PPDOC_ALLOW_COPY // copying, copying for accessibility
- PPDOC_ALLOW_ANNOTS // filling form fields, copying, signing
- PPDOC_ALLOW_EXTRACT // contents copying for accessibility
- PPDOC_ALLOW_ASSEMBLY // (no effect)
- PPDOC_ALLOW_PRINT_HIRES // (no effect)
-
-``pplib`` does absolutelly nothing with permissions, it cares only to decrypt the document. As mentioned, encryption applies to strings
-and streams. ``pplib`` decrypt strings when parsing document objects, so the result you get is *normal* (not ciphered).
-Streams are decrypted whenever you access them. Even if you ask for a raw stream data, you'll get a raw (compressed) stream, but decrypted.
-So except the check to ``ppdoc_crypt_status()``, you shouldn't bother about encryption.
-
-In encrypted documents most of streams are encrypted. To check if a given stream is encrypted::
-
- ppstream_encrypted(stream) // macro, returns non-zero if encrypted
-
-Encryption is independent from compression, don't confuse with ``ppstream_compressed()``
-
-Pages
------
-
-Several helpers to deal with pages. To get the number of pages::
-
- ppuint ppdoc_page_count (ppdoc *pdf);
-
-To access the root pages tree node::
-
- ppref * ppdoc_pages(ppdoc *pdf);
-
-To get the page reference at a given index::
-
- ppref * ppdoc_page (ppdoc *pdf, ppuint index);
-
-``index`` is a page number. First page has number 1. For index out of bounds ``ppdoc_page()`` returns NULL.
-Iterating over pages using index from 1 to ``ppdoc_page_count()`` and calling ``ppdoc_page()`` on each iteration
-would be suboptimal. Here is a dedicted iterator for this::
-
- ppref * ppdoc_first_page (ppdoc *pdf);
- ppref * ppdoc_next_page (ppdoc *pdf);
-
-The iterator in use::
-
- ppdoc *pdf;
- ppref *ref;
- ppdict *dict;
- int pageno;
-
- pdf = ppdoc_load("file.pdf");
- for (ref = ppdoc_first_page(pdf), pageno = 1; ref != NULL; ref = ppdoc_next_page(pdf), ++pageno)
- {
- dict = ppref_obj(obj)->dict; // take for granted it is a dict
- // do something with the page dict
- }
-
-Functions related to pages return ``ppref *`` ensured to contain dict object, so you don't need sanity
-type checks here.
-
-Contents
---------
-
-PDF page contents can be given as a stream or array of streams. Here is a convenience iterator over page
-contents streams::
-
- ppstream * ppcontents_first (ppdict *dict);
- ppstream * ppcontents_next (ppdict *dict, ppstream *stream);
-
-A complete example of contents stream parser use is given below (example 2).
-But before we get there, we need to introduce ``ppcontext`` object. Conceptually,
-``ppcontext`` is an owner (memory handler) of objects created on demand (beyond the ``ppdoc``).
-So far used only with contents stream parser, which might produce quite some data that we want
-to release just after used. To create a new context::
-
- pcontext * ppcontext_new (void);
-
-It initializes a new context and its internal memory heap, taking about 64kB on start. After that,
-the context is ready to produce objects (contents parsing functions below). Once objects produced
-from a given context are no longer needed::
-
- void ppcontext_done (ppcontext *context);
-
-It restores the context to its initial state, as after ``ppcontext_new()``. It means that the context
-is ready to produce another bunch of beings (in the example below, all objects from the next page contents).
-Once the context is not needed anymore::
-
- void ppcontext_free (ppcontext *context);
-
-Now, contents stream parser functions take the context as an argument. Iterator form of contents stream parser
-that allows to process the contents operator by operator::
-
- ppobj * ppcontents_first_op (ppcontext *context, ppstream *stream, size_t *psize, ppname *pname);
- ppobj * ppcontents_next_op (ppcontext *context, ppstream *stream, size_t *psize, ppname *pname);
-
-Returned ``ppobj *`` is a pointer to operands list. ``*psize`` is the number of operands on stack.
-The operator itself is stored as ``*pname``.
-
-To parse the entire contents stream at once with no stop at every operator::
-
- ppobj * ppcontents_parse (ppcontext *context, ppstream *stream, size_t *psize);
-
-Returns probably quite long list of all parsed objects (operands and operatos) in one piece.
-The number of objects is stored to ``*psize``.
-
-[Contents may contain so called inline images, that breaks a simple scheme of operands / operator syntax::
-
- BI <keyval pairs> ID <binary image data> EI
-
-Contents parser treats this genuine triplet as a single piece, producing two operands (dict and string)
-followed by ``EI`` operator name.]
-
-Boxes
------
-
-Boxes (rectangles) in PDF are roughly 4-number arrays, but with a special intent.
-``pplib`` provides a basic interface for these special arrays::
-
- typedef struct {
- ppnum lx, ly, rx, ry;
- } pprect;
-
-This type is used only by helper functions - PDF parser is not aware of the rectangle type.
-To convert ``pparray`` to ``pprect``::
-
- pprect * pparray_to_rect (pparray *array, pprect *rect); // returns rect or NULL
-
-In example::
-
- pprect rect;
- if (pparray_to_rect(array, &rect) != NULL)
- ; // do something with rect
-
-To get some image bounding box::
-
- pprect * ppdict_get_rect (ppdict *dict, const char *name, pprect *rect);
- // eg. ppdict_get_rect(imagedict, "BBox", &rect)
-
-To get some page box::
-
- pprect * ppdict_get_box (ppdict *dict, const char *name, pprect *rect);
- // eg. ppdict_get_box(pagedict, "MediaBox", &rect)
-
-The later not only checks the pagedict, but also goes through parent page nodes.
-
-Transforms
-----------
-
-Transformations are given as 6-number arrays, but with a special intent.
-``pplib`` provides a basic interface for these special arrays::
-
- typedef struct {
- ppnum xx, xy, yx, yy, x, y;
- } ppmatrix;
-
-This type is used only by helper functions - PDF parser is not aware of the matrix type.
-To convert ``pparray`` to ``ppmatrix``::
-
- ppmatrix * pparray_to_matrix (pparray *array, ppmatrix *matrix);
-
-In example::
-
- ppmatrix matrix;
- if (pparray_to_matrix(array, &matrix) != NULL)
- ; // do something with matrix
-
-To get the matrix from dict::
-
- ppmatrix * ppdict_get_matrix (ppdict *dict, const char *name, ppmatrix *matrix);
- // eg. ppdict_get_matrix(imagedict, "Matrix", &matrix)
-
-Errors handling
----------------
-
-``pplib`` is not verbose, but might happen that it needs to log some error message, eg. when parsing
-of some PDF boject fails due to invalid offsets. By default, ``pplib`` prints the message to stdout, eg.::
-
- invalid 123 0 R object at offset 123123
-
-To replace the default logger, you can provide your own::
-
- void pplog_callback (pplogger_callback logger, void *alien);
-
-``pplogger_callback`` is a function::
-
- void your_callback (const char *message, void *alien);
-
-In example, to redirect messages to stderr you may define a function::
-
- void your_callback (const char *message, void *alien)
- {
- fprintf((FILE *)alien, "\nooops: %s\n", message);
- }
-
-Then set the callback somewhere before loading documents::
-
- pplog_callback(your_callback, stderr);
-
-(example 2 uses that).
-
-To set the default log messages prefix, eg. ``pplib:``, use::
-
- int pplog_prefix (const char *prefix)
-
-Default is empty. The function succeeds if provided prefix is reasonably short (less then 32 bytes).
+ +``pplib`` 1.x +============= + +``pplib`` is a library for raw PDF access. It parses PDF documents and provides an interface to access document structures in C. + +C-API +===== + +Types +----- + +``pplib`` defines several C-types to represent PDF types: + +- ``ppint`` - signed integer (``int64_t``) +- ``ppnum`` - real number (double) +- ``ppname`` - PDF name +- ``ppstring`` - PDF string +- ``pparray`` - PDF array +- ``ppdict`` - PDF dict +- ``ppstream`` - PDF stream +- ``ppref`` - PDF indirect reference +- ``ppobj`` - a container of all above + +Among ``ppint`` and ``ppnum``, we also use ``ppuint`` - unsigned integer (machine word, alias to ``size_t``). + +Other API types: + +- ``ppdoc`` - PDF document +- ``ppxref`` - cross-references table +- ``ppcontext`` - ... later +- ``pprect`` - rectangle +- ``ppmatrix`` - matrix + +Integer, number, name and string are treated as simple types. +Names and strings are actually C-structures, but exposed to API as typedefs to ``const char *``. +Other types (array, dict, stream, reference, object container, xref, PDF) are C-structures, +and you operate it their pointers. So when you declare a simple type variable you say:: + + ppuint u; + ppnum n; + ppname name; + ppstring string; + ... + +And when you declare a compound type you operate on pointers:: + + ppobj *obj; + pparray *array; + ppdict *dict; + ppstream *stream; + ppref *ref; + ppdoc *pdf; + +Some of those C-types are defined in library header ``ppapi.h`` (complete types). Some others are incomplete +(eg. you can't say ``sizeof(ppdoc)`` or ``sizeof(ppxref)``). This is to avoid unnecesary dependencies in +the header. [At some points it's not clear to me what to hide and what to expose, will see.] The library itself +uses ``pplib.h`` but for auxilary applications including a standalone ``ppapi.h`` header should be enough. + +``pplib`` was designed having **read-only** PDF access in mind. Even if some structure is completelly exposed, +so that you can directly access its members, you should treat them as read-only. I don't make them ``const`` because +then all variable declarations would need to be ``const``, which is annoying, and I'd need some trickery in the library +internals to unconst. Besides, nothing is really const for C type casts. + +Object +------ + +A common container for all elementary PDF object types is ``ppobj`` structure. ``ppobj`` has a type identifier +(integer) and union of values:: + + struct ppobj { + ppobjtp type; + union { + ppint integer; + ppnum number; + ppname name; + ppstring string; + pparray *array; + ppdict *dict; + ppstream *stream; + ppref *ref; + void *any; + }; + }; + +Object type is one of constants (enum):: + + PPNONE + PPNULL + PPBOOL + PPINT + PPNUM + PPNAME + PPSTRING + PPARRAY + PPDICT + PPSTREAM + PPREF + +The type determines the structure member you're allowed to access:: + + ppobj *obj; + ... + switch (obj->type) + { + case PPNONE: // shouldn't actually happen, indicates some failure + break; + case PPNULL: // valid PDF null object, no value + break; + case PPBOOL: // do something with obj->integer (ppint), value 0 or 1 + break; + case PPINT: // do something with obj->integer (ppint) + break; + case PPNUM: // do something with obj->number (ppnum) + break; + case PPNAME: // do something with obj->name (ppname) + break; + case PPSTRING: // do something with obj->string (ppstring) + break; + case PPARRAY: // do something with obj->array (pparray *) + break; + case PPDICT: // do something with obj->dict (ppdict *) + break; + case PPSTREAM: // do something with obj->stream (ppstream *) + break; + case PPREF: // do something with obj->ref (ppref *) + break; + } + +More often then not you know exactly what type of object value is expected, in which case +you may use one of the following macros:: + + // returns 1 if o->type is PPNULL + int ppobj_get_null(o) \ + + // if o->type is PPBOOL, sets int v to 0 or 1 and returns 1, 0 otherwise + int ppobj_get_bool(o, v) + + // if o->type is PPINT, sets ppint v and returns 1, 0 otherwise + int ppobj_get_int(o, v) + + // if o->type is PPINT and >= 0, sets ppuint v and returns 1, 0 otherwise + int ppobj_get_uint(o, v) + + // if o->type is PPNUM or PPINT, sets ppnum v and returns 1, 0 otherwise + int ppobj_get_num(o, v) + + // if o->type is PPNAME returns the name, NULL otherwise + ppname ppobj_get_name(o) + + // if o->type is PPSTRING returns the string, NULL otherwise + ppstring ppobj_get_string(o) + + // if o->type is PPARRAY returns the array, NULL otherwise + pparray * ppobj_get_array(o) + + // if o->type is PPDICT returns the dict, NULL otherwise + ppdict * ppobj_get_dict(o) + + // if o->type is PPSTREAM returns the stream, NULL otherwise + ppstream * ppobj_get_stream(o) + + // if o->type is PPREF returns the reference, NULL otherwise + ppref * ppobj_get_ref(o) + +Note the coercion from integer to real number, but not reverse. In practise, whenever you expect a real number, +you should also handle integer (eg. '1' used instead of '1.0'). + +It is a common case that the object is given as an indirect reference, but what you actually +want is not the reference, but the object referred by it. Here is a helper for it:: + + // if o->type is PPREF, returns what the reference points, otherwise returns o + ppobj * ppobj_rget_obj(o) + +Also every ``ppobj_get_*`` macro has ``ppobj_rget_*`` counterpart that makes a check +for the expected type, but if the object is PPREF, it jumps to the target object. +So for example ``ppobj_rget_dict(obj)`` will return dict if ``obj`` is of type PPDICT +or if it is of type PPREF and ``obj->ref`` hosts an object of type PPDICT. + +Names +----- + +PDF names are represented as ``ppname``. +I find it convenient to have ``ppname`` type pretending ``const char *``. This allows to use ``ppname`` +in all C-style string functions like ``printf("%s", name)``. + +Be aware, however, that ``ppname`` is actually a C-structure. It is perfectly ok to cast ``ppname`` to ``const char *``:: + + ppname name; + ... + (const char *)name; + +But reverse is forbidden:: + + const char *cstr = "cstring"; + ... + (ppname)cstr; // expect segmentation fault soon + +For convenient use in C, names are ``'\0'`` terminated. But to get the length of name better always use +``ppname_size()`` macro. ``ppname`` object knows its size, don't use ``strlen()``:: + + size_t ppname_size(ppname name); // macro, returns length of name in bytes + +In current implementation names are not hashed anyhow, so name-to-name comparison is not smarter than ``memcmp()``. +Use macros:: + + int ppname_is(ppname name, "literal"); // to compare ppname with C-literal string + int ppname_eq(ppname name, ppname other); // to compare ppname with a different name + +If you'll use ``pplib`` to parse contents streams, you may need to distinguish names from operators +(more precisely executable names). Names in PDF are preceeded by '/', executable names aren't. In both +cases PDF parser will produce ``ppname`` but can be distingushed with:: + + int ppname_exec(ppname name); // returns non-zero if name is executable + +Names are kept in their raw form, with possible PDF specific escapes (in text below we call it **encoded** form). +Leading '/' is omitted, though. One may need a decoded name, with no PDF escapes. +A pair of functions provides a simple interface to switch between those two forms:: + + ppname ppname_decoded (ppname name); // returns decoded (unescaped) form of the name + ppname ppname_encoded (ppname name); // returns encoded (escaped) form of the name + +In pretty most cases PDF names contains only letters (no special characters, no escapes), so decoded and encoded forms are identical. +In that case both functions simply return the argument. It is ok to call ``ppname_decoded()`` on already decoded form +and ``ppname_encoded()`` on already encoded form. Both forms are produced by PDF objects parser, so accessing ``ppname`` alter ego +in whatever direction needs no extra decoding or allocation costs. + +String +------ + +PDF strings have the same internal construction as names, so most of names description above applies to strings as well. +``ppstring`` is a typedef of ``const char *``, roughly ``'\0'`` terminiated C-string. To get the size of the string:: + + size_t ppstring_size(ppstring string); // macro, returns the length of the string in bytes + +Strings are provided in their raw form, preserving PDF specific escapes, but with no +``()`` or ``<>`` delims. To distinguish plain strings from hex strings:: + + int ppstring_hex(ppstring string); // macro, returns non zero if hex string + +Or if you prefer:: + + switch (ppstring_type(string)) + { + case PPSTRING_PLAIN: // literal string, surrounded by ``(`` and ``)`` in PDF + break; + case PPSTRING_BASE16: // hex string, surrounded by ``<`` and ``>`` in PDF + break; + case PPSTRING_BASE85: // base85 string surrounded by ``<~`` and ``~>`` in PDF + break; + } + +The last is actually Postscript specific, not used in PDF, but I think it might appear in contents streams... +No matter how the string is given in PDF (plain or hex), here are two functions to +switch between encoded and decoded strings forms:: + + ppstring ppstring_decoded (ppstring string); // returns decoded string possibly with PDF escapes + ppstring ppstring_encoded (ppstring string); // returns encoded string with no PDF escapes + +For hex strings, encoded form contains hex digits, while decoded form contains arbitrary bytes (the result of hex decoding). +Plain strings usually contains printable ASCII characters, but they might contain any binary data. +As with names, objects parser produces both forms. The raw form with PDF escapes (or raw hex form) is considered the main one. +Eg. when you access ``obj->string`` you always get the encoded form. At any moment you can switch to its alter ego. + +No matter if the string is plain or hex, if its first two bytes (decoded) are UTF16 BOM, the string +is considered unicode. ``ppstring`` object *knows* it is unicode or not:: + + switch (ppstring_utf(string)) + { + case PPSTRING_UTF16LE: // unicode string, utf16le + break; + case PPSTRING_UTF16BE: // unicode string, utf16be + break; + default: // no unicode + } + +Or simply:: + + if (ppstring_utf(string) != 0) { + // handle unicode string + } + +If the string is unicode, BOM remains the part of the string -- ``pplib`` parser does not strip it. +Unicode or not, encoded or decoded, strings are always C-arrays of bytes and ``ppstring_size()`` +always returns the size in bytes. + +Array +----- + +PDF arrays are represented as ``pparray`` type, which is C-array of ``ppobj`` structures. +To get the size:: + + size_t pparray_size(pparray *array) // macro, returns the number of array items + +To get ``ppobj *`` at a given index:: + + ppobj * pparray_at(array, index) // macro, returns ppobj * (no index check) + ppobj * pparray_get(array, index) // macro, returns ppobj * or NULL (with index check) + ppobj * pparray_get_obj (pparray *array, size_t index); // function equiv to pparray_get() + +Iterating over array elements:: + + pparray *array; + size_t index, size; + ppobj *obj; + for (size = pparray_size(array), pparray_first(array, index, obj); index < size; pparray_next(index, obj)) + { + // do something with index and obj + } + +There is no magic first/next macros, just iteration over pointers. One could also use something like:: + + for (index = 0, size = array->size; index < size; ++index) + { + obj = pparray_at(array, index); + // do something with index and obj + } + +When getting values from array and expecting a result of known type, use one of the following:: + + int pparray_get_bool (pparray *array, size_t index, int *v); // get boolean value + int pparray_get_int (pparray *array, size_t index, ppint *v); // get ppint value + int pparray_get_uint (pparray *array, size_t index, ppuint *v); // get ppuint value + int pparray_get_num (pparray *array, size_t index, ppnum *v); // get ppnum value + ppname pparray_get_name (pparray *array, size_t index); // get ppname value + ppstring pparray_get_string (pparray *array, size_t index); // get ppstring value + pparray * pparray_get_array (pparray *array, size_t index); // get pparray * value + ppdict * pparray_get_dict (pparray *array, size_t index); // get ppdict * value + ppref * pparray_get_ref (pparray *array, size_t index); // get ppref * value + +As with ``ppobj_get_*`` suite, numeric types getters set the value of a given type and returns 1, if the type matches. +Otherwise sets nothing and returns 0. Other getters return the value if the type matches, or NULL. + +Every function from ``pparray_get_*`` suite have its ``pparray_rget_*`` counterpart that +that dereferences indirect objects (as explained for ``ppobj_rget_*`` getters). Note that +there is no ``pparray_get_stream()`` function, as streams in PDF are always indirect. +To get the stream from array use:: + + ppstream * pparray_rget_stream (pparray *array, size_t index); + +Dict +---- + +PDF dicts are represented as ``ppdict`` structure, which is C-array of ``ppobj`` with parallel +C-array of ``ppname`` pointers. To get the size of a dict:: + + size_t ppdict_size(ppdict *dict) // macro, returns the number of key-val pairs + +To get the value at a given index (integer):: + + ppobj * ppdict_at(ppdict *dict, index) // macro, no index check + +To get the name (key) at a given index:: + + ppname ppdict_key(ppdict *dict, index) // macro, no index check + +To iterate over dict key-val pairs:: + + ppdict *dict; + ppname *pkey; + ppobj *obj; + + for (ppdict_first(dict, pkey, obj); *pkey != NULL; ppdict_next(pkey, obj)) + { + // do something with *pkey and obj + } + +There is no magic in first/next macros, just iteration through keys and values lists pointers. +For convenient iteration, a list of keys is terminated with NULL, so in the code above ``*pkey != NULL`` +is used as the loop condition. One may also iterate via indices:: + + ppdict *dict; + size_t index, size; + ppname key; + ppobj *obj; + for (index = 0, size = ppdict_size(dict); index < size; ++index) + { + key = ppdict_key(dict, index); + obj = ppdict_at(dict, index); + // do something with key and obj + } + +To get the object associated with a given name, use one of the following:: + + ppobj * ppdict_get_obj (ppdict *dict, const char *name); + int ppdict_get_bool (ppdict *dict, const char *name, int *v); + int ppdict_get_int (ppdict *dict, const char *name, ppint *v); + int ppdict_get_uint (ppdict *dict, const char *name, ppuint *v); + int ppdict_get_num (ppdict *dict, const char *name, ppnum *v); + ppname ppdict_get_name (ppdict *dict, const char *name); + ppstring ppdict_get_string (ppdict *dict, const char *name); + pparray * ppdict_get_array (ppdict *dict, const char *name); + ppdict * ppdict_get_dict (ppdict *dict, const char *name); + ppref * ppdict_get_ref (ppdict *dict, const char *name); + +Note that all getters accepts ``const char *`` as key, so it is ok to say:: + + ppdict_rget_dict(dict, "Resources"); + +as well as:: + + ppdic_rget_dict(dict, name); // ppname name + +Every ``ppdict_get_*`` getter has ``ppdict_rget_*`` counterpart that dereferences +indirect objects if necessary. Note that there is no ``ppdict_get_stream()`` function, +but there is:: + + ppstream * ppdict_rget_stream (ppdict *dict, const char *name); + +So far dicts comes with no names mapping, so by-name dict accessors perform a linear search +through the keys list. PDF dicts are usually small, so it is fast enough. +Building names lookup for every dict in PDF makes no sense I think, as ``pplib`` applications +will query just several dicts I guess.. However, some apps may extensively query +resources, which may refer to hundreds of objects (eg. images). So some mapping for dicts +is still considered. + +Stream +------ + +PDF streams are represented as ``ppstream`` objects. To get the stream dict:: + + ppdict * ppstream_dict(ppstream *stream) // macro + +To read the stream data:: + + uint8_t * ppstream_first (ppstream *stream, size_t *size, int decode); + uint8_t * ppstream_next (ppstream *stream, size_t *size); + void ppstream_done (ppstream *stream); + +Both ``first` and ``next`` functions return a chunk of stream data and sets the ``size`` of the chunk. +``decode`` parameter tell the reader to decompress the stream (1) or return raw (0). A call to ``ppstream_next()`` +must be preceeded by ``ppstream_first()``. Once you're done with the stream, you have to call ``ppstream_done()``, +no matter if the stream has been read to the end or not. The stream data iterator in use:: + + uint8_t *data; + size_t size; + ppstream *stream; + int decode = 1; // 1 - get decompressed, 0 - get raw + + for (data = ppstream_first(stream, &size, decode); data != NULL; data = ppstream_next(stream, &size)) + { + // do something with data and its size + } + ppstream_done(stream); + +Every subsequent iterator call invalidates the previous reader output, so you have to utilize the returned chunk +of data just after you ot that. So the following is wrong:: + + data1 = ppstream_first(stream, &size, 1); + data2 = ppstream_next(stream, &size); + data3 = ppstream_next(stream, &size); + some_output(data1, size); + some_output(data2, size); + +The reader calls usually return the same pointer to internal buffer, just filled with a different data. +``pplib`` allocates reasonably large buffer and fills that buffer on subsequent calls to the reader. + +If the source stream has no compression, using both ``decode == 1`` and ``decode == 0`` should give the same result. +You can check if the stream is actually compressed with:: + + ppstream_compressed(stream) // macro, returns non zero if /Filter is present + +It might be necessary to load the entire stream data at once:: + + uint8_t * ppstream_all (ppstream *stream, size_t *size, int decode); + +If the initial buffer size is insufficient, it grows until the entire stream data is loaded. You must call +``ppstream_done(stream)`` after using returned data. + +``ppstream_done()`` doesn't invalidate the stream object, it just closes its internal reader. +The stream itself remains a valid object (eg. one can read it again if necessary), +but the reader buffer is released. It is actually not freed but kept for future the reuse with that on some other stream, +but you still need to mark it ready for reuse to avoid allocating a separate buffer for every stream you're going to read. + +Stream data readers will return ``NULL`` if you haven't close the previous reader process with ``ppstream_done()``. All below is wrong:: + + data1 = ppstream_all(stream, &size, 1); + data2 = ppstream_all(stream, &size, 1); // data2 == NULL + // or + data1 = ppstream_first(stream, &size, 1); + data2 = ppstream_first(stream, &size, 1); // data2 == NULL + // or + data1 = ppstream_first(stream, &size, 1); + data2 = ppstream_all(stream, &size, 1); // data2 == NULL + +To avoid unnecessary dependencies, ``pplib`` does not support image filters (``/DCT``, ``/JPX``, ``/JBIG``, ``/CCITT``). +But it is ok to read the stream with ``decode`` set to 1 on such streams. ``pplib`` assumes that the image is the +final/target stream form and just returns it as-is. Eg. in the case of JPEG (``/DCT`` filtered) image both calls should +give the same results:: + + ppstream_all(jpegstream, &jpegsize, 0); // don't decode, return what's there + ppstream_all(jpegstream, &jpegsize, 1); // decode but found image filter, effectively the same + +A bit more about streams memory. As mentioned, ``pplib`` allocates buffers for stream readers. After ``ppstream_done()``, +the stream no longer *owns* the buffer space. But the buffer may remain allocated, to be reused with future readers. +``pplib`` keeps a pool of several buffers. This means, that when you use stream readers, ``pplib`` eats +some memory (1MB or so) that is not freed, even if no streams are used. And even if you free all objects. +If you suffer from this, you can optionally use a pair of functions:: + + void ppstream_init_buffers (void); + void ppstream_free_buffers (void); + +The first initializes buffers pool, unless done so far. Currently ``pplib`` cares of it before opening every stream reader, +so it is not obligatory. The second frees a pool of buffers. The intended use is to call ``ppstream_init_buffers()`` once +as kind of library initializer and to call ``ppstream_free_buffers()`` once, as the library finalizer. + +Filters +------- + +In version v1.00 (20190916) ``ppstream`` API has been extended with filters information. +``ppstream`` knows its filter(s) and keps it as ``stream->filter``:: + + // ppstream *stream; + ppstream_filter *info = &stream->filter; + +``ppstream_filter`` is the following structure:: + + typedef struct { + ppstreamtp *filters; // c-array of filter identifiers (enum integers) + ppdict **params; // c-array of ppdict pointers + size_t count; // number of filters, length of the arrays (typically 1) + } ppstream_filter; + +If ``count > 0`` then ``filters`` member is not NULL. Filters array keeps integer constants:: + + PPSTREAM_BASE16 /* /ASCIIHexDecode */ + PPSTREAM_BASE85 /* /ASCII85Decode */ + PPSTREAM_RUNLENGTH /* /RunLengthDecode */ + PPSTREAM_FLATE /* /FlateDecode */ + PPSTREAM_LZW /* /LZWDecode */ + PPSTREAM_CCITT /* /CCITTFaxDecode */ + PPSTREAM_DCT /* /DCTDecode */ + PPSTREAM_JBIG2 /* /JBIG2Decode */ + PPSTREAM_JPX /* /JPXDecode */ + PPSTREAM_CRYPT /* /Crypt */ + +Params array keeps corresponding filter parameters (``/DecodeParms``) if present. ``params`` member is not NULL +if ``count > 0`` and the stream dict has ``/DecodeParms`` entry. Even if ``params`` is there, +for every N-th filter, ``params[N]`` may be NULL (corresponding to PDF ``null``). + +``stream->filter`` keeps the source stream filter information, which may not correspond to the result of stream readers +(``ppstream_first()``, ``ppstream_next()``, ``ppstream_all()``). The get the filters info relevant to the result from readers:: + + void ppstream_filter_info (ppstream *stream, ppstream_filter *info, int decode); + +The function fills ``ppstream_filter`` structure according to the expected result from stream readers (example 3 shows +how to use it to reconstruct ``/Filter`` and ``/DecodeParms`` when copying the stream to some other PDF). + +To convert filter identifier (``ppstreamtp``) to a corresponding PDF filter name:: + + const char * ppstream_filter_name[]; + +To covert ``ppname`` to filter identifier:: + + int ppstream_filter_type (ppname filtername, ppstreamtp *filtertype); + // returns 1 and sets filtertype if filtername is the proper filter name + +Additional information about the stream can be fetched from macros:: + + ppstream_compressed(stream) /* stream->flags & (PPSTREAM_FILTER|PPSTREAM_IMAGE) */ + ppstream_filtered(stream) /* stream->flags & PPSTREAM_FILTER */ + ppstream_image(stream) /* stream->flags * PPSTREAM_IMAGE */ + +``stream->flags`` is a binary sum of the following:: + + PPSTREAM_FILTER /* set iff the stream filters list has one of: BASE16, BASE85, RUNLENGTH, FLATE, LZW */ + PPSTREAM_IMAGE /* set iff the stream filters list has one of: CCITT, DCT, JBIG2, JPX */ + PPSTREAM_ENCRYPTED /* set iff the stream is encrypted */ + PPSTREAM_ENCRYPTED_OWN /* set iff the stream has own CRYPT filter */ + +Note that ``PPSTREAM_COMPRESSED`` is not there any longer, use ``ppstream_compressed()`` instead. +And there is some more, see ``ppapi.h``. + +Ref +--- + +Indirect objects are represented as ``ppref`` structure. To get the object that the +reference refers to:: + + ppobj * ppref_obj(ppref *ref) // macro + +``ppref`` structure also keeps the reference number and version, a pointer to cross reference table it belongs +to and others, but I guess you won't need anything but the referenced object. ``pplib`` parser resolves references +on-fly. So if there is a dict with indirect objects:: + + << + /Type /Page + /Resources 123 0 R + ... + >> + +the parser will produce ``ppdict`` with ``Resources`` key pointing the proper ``ppref *`` value. +If you need more, access ``ppref`` members:: + + struct ppref { + ppobj object; // target object + ppuint number, version; // identifiers + size_t offset; // file offset (useless for you, may be zero for compressed objects) + ppuint length; // the length of the original object data + ppxref *xref; // cross reference table it belongs to + }; + + +XRef +---- + +Cross reference table is exposed as ``ppxref`` (incomplete type, you can only oprate on its pointer). +To get top document xref:: + + ppxref * ppdoc_xref (ppdoc *pdf); + +To get previous (older) xref:: + + ppxref * ppxref_prev (ppxref *xref); + +To find an object of a given refnumber:: + + ppref * ppxref_find (ppxref *xref, ppuint refnumber); + +[Note: since pplib v0.98 in case of documents with incremental update, ``ppxref_find()`` returns +the newest available version of a given object rather than the object in a given body.] + +PDF +--- + +PDF document is represented as ``ppdoc`` structure (incomplete type, you can only operate on its pointer). +To load a document from file:: + + ppdoc * ppdoc_load (const char *filename); + +To load a document from memory data:: + + ppdoc * ppdoc_mem (const void *data, size_t size); + +The data is assumed to be a buffer allocated with ``malloc`` - it is freed when destroying ``ppdoc``. + +Both loaders returns ``NULL`` on failure. + +To free ``ppdoc`` and all objects it refers to:: + + void ppdoc_free (ppdoc *pdf); + +So far we haven't mention about any explicit object reclaimers. There are no dedicated ``free`` functions +for other objects. You don't allocate or free objects yourself. ``ppdoc`` object is an owner of all +beings it refers to. It also means that every object described so far is alive as long as the containing +``ppdoc`` is alive. + +To access main PDF dicts:: + + ppdict * ppdoc_trailer(ppdoc *pdf); // returns top xref trailer dict + ppdict * ppdoc_catalog(ppdoc *pdf); // returns catalog referred from the trailer + ppdict * ppdoc_info(ppdoc *pdf); // returns info dict referred from the trailer + +To get the PDF version:: + + const char * ppdoc_version_string (ppdoc *pdf); // version string + int ppdoc_version_number (ppdoc *pdf, int *minor); // minor and major numbers + +To get the file size of the source PDF document:: + + size_t ppdoc_file_size (ppdoc *pdf); + +To get the number of objects in all xrefs:: + + ppuint ppdoc_objects (ppdoc *pdf); + +To get the approx usage of memory:: + + size_t ppdoc_memory (ppdoc *pdf, size_t *waste); + +Encryption +---------- + +``pplib`` handles encrypted (password protected) documents. If a document is encrypted, most of strings and streams are ciphered. +In that form they are unreadable and rather useless, you can't even rewrite such strings/streams as-is to a different PDF output. +It is a common practise to *protect* documents with an empty password. Such documents remain readable in Acrobat (just opens them without prompting +for a password), but some features (eg. printing) may restricted by the application. + +When ``pplib`` detects encryption, it follows Acrobat approach and first tries an empty password. If it succeeds, ``pplib`` proceeeds normally, providing +an access to decrypted strings and streams, as if they weren't ciphered. If the document is protected with non-empty password, ``pplib`` gives +a way to provide a password and proceed. Until you provide a password, ``ppdoc`` object returned by ``ppdoc_load()`` function has all object wntries +set to ``null``. + +After loading a document you should check encryption status with:: + + ppcrypt_status ppdoc_crypt_status (ppdoc *pdf); + +``ppcrypt_status`` (integer) may have the following values: + + ``PPCRYPT_NONE`` - no encryption, go ahead + ``PPCRYPT_DONE`` - encryption present but password succeeded, go ahead + ``PPCRYPT_PASS`` - encryption present, need non-empty password + ``PPCRYPT_FAIL`` - invalid or unsupported encryption (eg. undocumented in pdf spec) + +If a password is needed, you can provide one with:: + + ppcrypt_status ppdoc_crypt_pass (ppdoc *pdf, const void *userpass, size_t userpasslength, + const void *ownerpass, size_t ownerpasslength); + +Well, yes, there are actually two passwords in encrypted documents. Relation between them is obscure to me, but enough +to know that having one of them is enough to decrypt the document. If you know the password, you probably mean +``userpass``, in which case you should put ``NULL`` as ``ownerpass``. The function returns ``PPCRYPT_DONE`` if the password +succeeds and the previous status otherwise. Your custom loader function may look like that:: + + ppdoc *pdf; + pdf = ppdoc_load("file.pdf"); + if (pdf == NULL) + return NULL; + switch (ppdoc_crypt_status(pdf)) + { + case PPCRYPT_NONE: + case PPCRYPT_DONE: + return pdf; + case PPCRYPT_PASS: + if (ppdoc_crypt_pass(pdf, "dummy", 5, NULL, 0) == PPCRYPT_DONE || + ppdoc_crypt_pass(pdf, NULL, 0, "dummy", 5) == PPCRYPT_DONE) + return pdf; + printf("sorry, password needed\n"); + ppdoc_free(pdf); + return NULL; + case PPCRYPT_FAIL: + printf("sorry, encryption failed\n"); + ppdoc_free(pdf); + return NULL; + } + +[If you get ``PPCRYPT_FAIL`` it might mean *I failed*, so treat as a bug.] + +If you'd like to know what permissions are given/restricted to encrypted document:: + + ppint ppdoc_permissions (ppdoc *pdf); + +Returned value can be queried with the following binary flags (you can verify with Acrobat *File -> Properties -> Security* tab):: + + PPDOC_ALLOW_PRINT // printing + PPDOC_ALLOW_MODIFY // filling form fields, signing, creating template pages + PPDOC_ALLOW_COPY // copying, copying for accessibility + PPDOC_ALLOW_ANNOTS // filling form fields, copying, signing + PPDOC_ALLOW_EXTRACT // contents copying for accessibility + PPDOC_ALLOW_ASSEMBLY // (no effect) + PPDOC_ALLOW_PRINT_HIRES // (no effect) + +``pplib`` does absolutelly nothing with permissions, it cares only to decrypt the document. As mentioned, encryption applies to strings +and streams. ``pplib`` decrypt strings when parsing document objects, so the result you get is *normal* (not ciphered). +Streams are decrypted whenever you access them. Even if you ask for a raw stream data, you'll get a raw (compressed) stream, but decrypted. +So except the check to ``ppdoc_crypt_status()``, you shouldn't bother about encryption. + +In encrypted documents most of streams are encrypted. To check if a given stream is encrypted:: + + ppstream_encrypted(stream) // macro, returns non-zero if encrypted + +Encryption is independent from compression, don't confuse with ``ppstream_compressed()`` + +Pages +----- + +Several helpers to deal with pages. To get the number of pages:: + + ppuint ppdoc_page_count (ppdoc *pdf); + +To access the root pages tree node:: + + ppref * ppdoc_pages(ppdoc *pdf); + +To get the page reference at a given index:: + + ppref * ppdoc_page (ppdoc *pdf, ppuint index); + +``index`` is a page number. First page has number 1. For index out of bounds ``ppdoc_page()`` returns NULL. +Iterating over pages using index from 1 to ``ppdoc_page_count()`` and calling ``ppdoc_page()`` on each iteration +would be suboptimal. Here is a dedicted iterator for this:: + + ppref * ppdoc_first_page (ppdoc *pdf); + ppref * ppdoc_next_page (ppdoc *pdf); + +The iterator in use:: + + ppdoc *pdf; + ppref *ref; + ppdict *dict; + int pageno; + + pdf = ppdoc_load("file.pdf"); + for (ref = ppdoc_first_page(pdf), pageno = 1; ref != NULL; ref = ppdoc_next_page(pdf), ++pageno) + { + dict = ppref_obj(obj)->dict; // take for granted it is a dict + // do something with the page dict + } + +Functions related to pages return ``ppref *`` ensured to contain dict object, so you don't need sanity +type checks here. + +Contents +-------- + +PDF page contents can be given as a stream or array of streams. Here is a convenience iterator over page +contents streams:: + + ppstream * ppcontents_first (ppdict *dict); + ppstream * ppcontents_next (ppdict *dict, ppstream *stream); + +A complete example of contents stream parser use is given below (example 2). +But before we get there, we need to introduce ``ppcontext`` object. Conceptually, +``ppcontext`` is an owner (memory handler) of objects created on demand (beyond the ``ppdoc``). +So far used only with contents stream parser, which might produce quite some data that we want +to release just after used. To create a new context:: + + pcontext * ppcontext_new (void); + +It initializes a new context and its internal memory heap, taking about 64kB on start. After that, +the context is ready to produce objects (contents parsing functions below). Once objects produced +from a given context are no longer needed:: + + void ppcontext_done (ppcontext *context); + +It restores the context to its initial state, as after ``ppcontext_new()``. It means that the context +is ready to produce another bunch of beings (in the example below, all objects from the next page contents). +Once the context is not needed anymore:: + + void ppcontext_free (ppcontext *context); + +Now, contents stream parser functions take the context as an argument. Iterator form of contents stream parser +that allows to process the contents operator by operator:: + + ppobj * ppcontents_first_op (ppcontext *context, ppstream *stream, size_t *psize, ppname *pname); + ppobj * ppcontents_next_op (ppcontext *context, ppstream *stream, size_t *psize, ppname *pname); + +Returned ``ppobj *`` is a pointer to operands list. ``*psize`` is the number of operands on stack. +The operator itself is stored as ``*pname``. + +To parse the entire contents stream at once with no stop at every operator:: + + ppobj * ppcontents_parse (ppcontext *context, ppstream *stream, size_t *psize); + +Returns probably quite long list of all parsed objects (operands and operatos) in one piece. +The number of objects is stored to ``*psize``. + +[Contents may contain so called inline images, that breaks a simple scheme of operands / operator syntax:: + + BI <keyval pairs> ID <binary image data> EI + +Contents parser treats this genuine triplet as a single piece, producing two operands (dict and string) +followed by ``EI`` operator name.] + +Boxes +----- + +Boxes (rectangles) in PDF are roughly 4-number arrays, but with a special intent. +``pplib`` provides a basic interface for these special arrays:: + + typedef struct { + ppnum lx, ly, rx, ry; + } pprect; + +This type is used only by helper functions - PDF parser is not aware of the rectangle type. +To convert ``pparray`` to ``pprect``:: + + pprect * pparray_to_rect (pparray *array, pprect *rect); // returns rect or NULL + +In example:: + + pprect rect; + if (pparray_to_rect(array, &rect) != NULL) + ; // do something with rect + +To get some image bounding box:: + + pprect * ppdict_get_rect (ppdict *dict, const char *name, pprect *rect); + // eg. ppdict_get_rect(imagedict, "BBox", &rect) + +To get some page box:: + + pprect * ppdict_get_box (ppdict *dict, const char *name, pprect *rect); + // eg. ppdict_get_box(pagedict, "MediaBox", &rect) + +The later not only checks the pagedict, but also goes through parent page nodes. + +Transforms +---------- + +Transformations are given as 6-number arrays, but with a special intent. +``pplib`` provides a basic interface for these special arrays:: + + typedef struct { + ppnum xx, xy, yx, yy, x, y; + } ppmatrix; + +This type is used only by helper functions - PDF parser is not aware of the matrix type. +To convert ``pparray`` to ``ppmatrix``:: + + ppmatrix * pparray_to_matrix (pparray *array, ppmatrix *matrix); + +In example:: + + ppmatrix matrix; + if (pparray_to_matrix(array, &matrix) != NULL) + ; // do something with matrix + +To get the matrix from dict:: + + ppmatrix * ppdict_get_matrix (ppdict *dict, const char *name, ppmatrix *matrix); + // eg. ppdict_get_matrix(imagedict, "Matrix", &matrix) + +Errors handling +--------------- + +``pplib`` is not verbose, but might happen that it needs to log some error message, eg. when parsing +of some PDF boject fails due to invalid offsets. By default, ``pplib`` prints the message to stdout, eg.:: + + invalid 123 0 R object at offset 123123 + +To replace the default logger, you can provide your own:: + + void pplog_callback (pplogger_callback logger, void *alien); + +``pplogger_callback`` is a function:: + + void your_callback (const char *message, void *alien); + +In example, to redirect messages to stderr you may define a function:: + + void your_callback (const char *message, void *alien) + { + fprintf((FILE *)alien, "\nooops: %s\n", message); + } + +Then set the callback somewhere before loading documents:: + + pplog_callback(your_callback, stderr); + +(example 2 uses that). + +To set the default log messages prefix, eg. ``pplib:``, use:: + + int pplog_prefix (const char *prefix) + +Default is empty. The function succeeds if provided prefix is reasonably short (less then 32 bytes). diff --git a/Build/source/libs/pplib/pplib-src/doc/_build/html/_sources/ppapi-2.x.rst.txt b/Build/source/libs/pplib/pplib-src/doc/_build/html/_sources/ppapi-2.x.rst.txt index c6779145a56..f04c10b514c 100644 --- a/Build/source/libs/pplib/pplib-src/doc/_build/html/_sources/ppapi-2.x.rst.txt +++ b/Build/source/libs/pplib/pplib-src/doc/_build/html/_sources/ppapi-2.x.rst.txt @@ -1,946 +1,946 @@ -
-``pplib`` 2.x
-=============
-
-``pplib`` is a library for raw PDF access. It parses PDF documents and provides an interface to access document structures in C.
-
-C-API
-=====
-
-Types
------
-
-``pplib`` defines several C-types to represent PDF types:
-
-- ``ppbyte`` - char
-- ``ppint`` - signed integer (``int64_t``)
-- ``ppnum`` - real number (double)
-- ``ppname`` - PDF name
-- ``ppstring`` - PDF string
-- ``pparray`` - PDF array
-- ``ppdict`` - PDF dict
-- ``ppstream`` - PDF stream
-- ``ppref`` - PDF indirect reference
-- ``ppobj`` - a container of all above
-
-Among ``ppint`` and ``ppnum``, we also use ``ppuint`` - unsigned integer (machine word, alias to ``size_t``).
-
-Other API types:
-
-- ``ppdoc`` - PDF document
-- ``ppxref`` - cross-references table
-- ``ppcontext`` - ... later
-- ``pprect`` - rectangle
-- ``ppmatrix`` - matrix
-
-Integer and number are as simple types. Names and strings used to be aliases to ``char *``
-in ``pplib 1.x``, now they are structures; all related API functions operate on pointers.
-Other types (array, dict, stream, reference, object container, xref, doc) are C-structures,
-and you operate it their pointers. So when you declare a simple type variable you say::
-
- ppuint u;
- ppnum n;
- ...
-
-And when you declare a compound type you operate on pointers::
-
- ppobj *obj;
- ppname *name;
- ppstring *string;
- pparray *array;
- ppdict *dict;
- ppstream *stream;
- ppref *ref;
- ppdoc *pdf;
-
-Most of those C-types are defined in library header ``ppapi.h`` (complete types). Some others are incomplete
-(eg. you can't say ``sizeof(ppdoc)`` or ``sizeof(ppxref)``). This is to avoid unnecesary dependencies in
-the header. The library itself uses ``pplib.h`` header but for auxilary applications including a standalone
-``ppapi.h`` header should be enough.
-
-``pplib`` was designed having **read-only** PDF access in mind. Even if some structure is completelly exposed,
-so that you can directly access its members, you should treat them as read-only. I don't make them ``const`` because
-then all variable declarations would need to be ``const``, which is annoying, and I'd need some trickery in the library
-internals to unconst. Besides, nothing is really const for C type casts.
-
-Object
-------
-
-A common container for all elementary PDF object types is ``ppobj`` structure. ``ppobj`` has a type identifier
-(integer) and union of values::
-
- struct ppobj {
- ppobjtp type;
- union {
- ppint integer;
- ppnum number;
- ppname *name;
- ppstring *string;
- pparray *array;
- ppdict *dict;
- ppstream *stream;
- ppref *ref;
- void *any;
- };
- };
-
-Object type is one of constants (enum)::
-
- PPNONE
- PPNULL
- PPBOOL
- PPINT
- PPNUM
- PPNAME
- PPSTRING
- PPARRAY
- PPDICT
- PPSTREAM
- PPREF
-
-The type determines the structure member you're allowed to access::
-
- ppobj *obj;
- ...
- switch (obj->type)
- {
- case PPNONE: // shouldn't actually happen, indicates some failure
- break;
- case PPNULL: // valid PDF null object, no value
- break;
- case PPBOOL: // do something with obj->integer (ppint), value 0 or 1
- break;
- case PPINT: // do something with obj->integer (ppint)
- break;
- case PPNUM: // do something with obj->number (ppnum)
- break;
- case PPNAME: // do something with obj->name (ppname *)
- break;
- case PPSTRING: // do something with obj->string (ppstring *)
- break;
- case PPARRAY: // do something with obj->array (pparray *)
- break;
- case PPDICT: // do something with obj->dict (ppdict *)
- break;
- case PPSTREAM: // do something with obj->stream (ppstream *)
- break;
- case PPREF: // do something with obj->ref (ppref *)
- break;
- }
-
-More often then not you know exactly what type of object value is expected, in which case
-you may use one of the following macros::
-
- // returns 1 if o->type is PPNULL
- int ppobj_get_null(o) \
-
- // if o->type is PPBOOL, sets int v to 0 or 1 and returns 1, 0 otherwise
- int ppobj_get_bool(o, v)
-
- // if o->type is PPINT, sets ppint v and returns 1, 0 otherwise
- int ppobj_get_int(o, v)
-
- // if o->type is PPINT and >= 0, sets ppuint v and returns 1, 0 otherwise
- int ppobj_get_uint(o, v)
-
- // if o->type is PPNUM or PPINT, sets ppnum v and returns 1, 0 otherwise
- int ppobj_get_num(o, v)
-
- // if o->type is PPNAME returns the name, NULL otherwise
- ppname * ppobj_get_name(o)
-
- // if o->type is PPSTRING returns the string, NULL otherwise
- ppstring * ppobj_get_string(o)
-
- // if o->type is PPARRAY returns the array, NULL otherwise
- pparray * ppobj_get_array(o)
-
- // if o->type is PPDICT returns the dict, NULL otherwise
- ppdict * ppobj_get_dict(o)
-
- // if o->type is PPSTREAM returns the stream, NULL otherwise
- ppstream * ppobj_get_stream(o)
-
- // if o->type is PPREF returns the reference, NULL otherwise
- ppref * ppobj_get_ref(o)
-
-Note the coercion from integer to real number, but not reverse. In practise, whenever you expect a real number,
-you should also handle integer (eg. '1' used instead of '1.0' is pretty common in PDF).
-
-It is a common case that the object is given as an indirect reference, but what you actually
-want is not the reference, but the object referred by it. Here is a helper for it::
-
- // if o->type is PPREF, returns what the reference points, otherwise returns o
- ppobj * ppobj_rget_obj(o)
-
-Also every ``ppobj_get_*`` macro has ``ppobj_rget_*`` counterpart that makes a check
-for the expected type, but if the object is PPREF, it jumps to the target object.
-So for example ``ppobj_rget_dict(obj)`` will return dict if ``obj`` is of type PPDICT
-or if it is of type PPREF and ``obj->ref`` hosts an object of type PPDICT.
-
-Names
------
-
-PDF names are represented as ``ppname`` pointer (``ppname`` used to be an alias to ``char *``, now it is a structure).
-To access the name data::
-
- ppbyte * ppname_data(name) // name->data, bytes array
-
-For convenient use in C, names are ``'\0'`` terminated. But to get the length of name better always use
-``ppname_size()`` macro. ``ppname`` object knows its size, don't use ``strlen()``::
-
- size_t ppname_size(ppname name); // name->size, the length of name in bytes
-
-In current implementation names are not hashed anyhow, so name-to-name comparison is not smarter than ``memcmp()``.
-Use macros::
-
- int ppname_is(ppname name, "literal"); // to compare ppname with C-literal string
- int ppname_eq(ppname name, ppname other); // to compare ppname with a different name
-
-If you use ``pplib`` to parse contents streams, you may need to distinguish names from operators
-(more precisely executable names). Names in PDF are preceeded by '/', executable names aren't. In both
-cases PDF parser will produce ``ppname`` but the result can be distingushed with::
-
- int ppname_exec(ppname name); // macro, returns non-zero if the name is executable
-
-Names are kept in their raw form, with possible PDF specific escapes (in text below we call it **encoded** form).
-Leading '/' is omitted. One may need a decoded name, with no PDF escapes.
-A pair of functions provides a simple interface to switch between those two forms::
-
- // these helpers rely on name->alterego member
- ppname * ppname_decoded (ppname *name); // returns decoded (unescaped) form of the name
- ppname * ppname_encoded (ppname *name); // returns encoded (escaped) form of the name
- ppbyte * ppname_decoded_data (ppname *name);
- ppbyte * ppname_encoded_data (ppname *name);
-
-In pretty most cases a PDF name contains only letters (no special characters, no escapes), so decoded and encoded forms are identical.
-In that case both functions simply return the argument. It is ok to call ``ppname_decoded()`` on already decoded form
-and ``ppname_encoded()`` on already encoded form. Both forms are produced by PDF objects parser, so accessing ``ppname`` alter ego
-in whatever direction needs no extra decoding or allocation costs (the cost is paid by parser).
-
-String
-------
-
-PDF strings have the same internal construction as names, so most of names description above applies to strings as well.
-``ppstring`` is a structure (used to be an alias to ``char *``). ``string->data`` is ``\0``-terminated c-array of ``ppbytes``.
-To get the data::
-
- ppbyte * ppstring_data(ppstring *string); // string->data, macro
-
-To get the size of the string::
-
- size_t ppstring_size(ppstring *string); // macro, returns the length of the string in bytes
-
-Strings are provided in their raw form, preserving PDF specific escapes, but with no
-``()`` or ``<>`` delims. To distinguish plain strings from hex strings::
-
- int ppstring_hex(ppstring string); // macro, returns non zero if hex string
-
-Or if you prefer::
-
- switch (ppstring_type(string))
- {
- case PPSTRING_PLAIN: // literal string, surrounded by ``(`` and ``)`` in PDF
- break;
- case PPSTRING_BASE16: // hex string, surrounded by ``<`` and ``>`` in PDF
- break;
- case PPSTRING_BASE85: // base85 string surrounded by ``<~`` and ``~>`` in PDF
- break;
- }
-
-The last is actually Postscript specific, not used in PDF, but I think it might appear in contents streams...
-No matter how the string is given in PDF (plain or hex), here are two functions to
-switch between encoded and decoded strings forms::
-
- ppstring * ppstring_decoded (ppstring *string); // returns decoded string possibly with PDF escapes
- ppstring * ppstring_encoded (ppstring *string); // returns encoded string with no PDF escapes
- ppbyte * ppstring_decoded_data (ppstring *string);
- ppbyte * ppstring_encoded_data (ppstring *string);
-
-For hex strings, encoded form contains hex digits, while decoded form contains arbitrary bytes (the result of hex decoding).
-Plain strings usually contains printable ASCII characters, but they might contain any binary data.
-As with names, objects parser produces both forms. The raw form with PDF escapes (or raw hex form) the main one.
-Eg. when you access ``obj->string`` you always get the encoded form. At any moment you can switch to its alter ego.
-
-No matter if the string is plain or hex, if its first two bytes (decoded) are UTF16 BOM, the string is unicode.
-``ppstring`` object *knows* it is unicode or not::
-
- switch (ppstring_utf(string))
- {
- case PPSTRING_UTF16LE: // unicode string, utf16le
- break;
- case PPSTRING_UTF16BE: // unicode string, utf16be
- break;
- default: // no unicode
- }
-
-Or simply::
-
- if (ppstring_utf(string) != 0) {
- // handle unicode string
- }
-
-If the string is unicode, BOM remains the part of the string -- ``pplib`` parser does not strip it.
-Unicode or not, encoded or decoded, strings are always C-arrays of bytes and ``ppstring_size()``
-always returns the size in bytes.
-
-Array
------
-
-PDF arrays are represented as ``pparray`` type, which is C-array of ``ppobj`` structures.
-To get the size::
-
- size_t pparray_size(pparray *array) // macro, returns the number of array items
-
-To get ``ppobj *`` at a given index::
-
- ppobj * pparray_at(array, index) // macro, returns ppobj * (no index check)
- ppobj * pparray_get(array, index) // macro, returns ppobj * or NULL (with index check)
- ppobj * pparray_get_obj (pparray *array, size_t index); // function equiv to pparray_get()
-
-Iterating over array elements::
-
- pparray *array;
- size_t index, size;
- ppobj *obj;
- for (size = pparray_size(array), pparray_first(array, index, obj); index < size; pparray_next(index, obj))
- {
- // do something with index and obj
- }
-
-There is no magic first/next macros, just iteration over pointers. One could also use something like::
-
- for (index = 0, size = array->size; index < size; ++index)
- {
- obj = pparray_at(array, index);
- // do something with index and obj
- }
-
-When getting values from array and expecting a result of known type, use one of the following::
-
- int pparray_get_bool (pparray *array, size_t index, int *v); // get boolean value
- int pparray_get_int (pparray *array, size_t index, ppint *v); // get ppint value
- int pparray_get_uint (pparray *array, size_t index, ppuint *v); // get ppuint value
- int pparray_get_num (pparray *array, size_t index, ppnum *v); // get ppnum value
- ppname * pparray_get_name (pparray *array, size_t index); // get ppname * value
- ppstring * pparray_get_string (pparray *array, size_t index); // get ppstring * value
- pparray * pparray_get_array (pparray *array, size_t index); // get pparray * value
- ppdict * pparray_get_dict (pparray *array, size_t index); // get ppdict * value
- ppref * pparray_get_ref (pparray *array, size_t index); // get ppref * value
-
-As with ``ppobj_get_*`` suite, numeric types getters set the value of a given type and returns 1, if the type matches.
-Otherwise sets nothing and returns 0. Other getters return the value if the type matches, or NULL.
-
-Every function from ``pparray_get_*`` suite have its ``pparray_rget_*`` counterpart
-that dereferences indirect objects (as explained for ``ppobj_rget_*`` getters). Note that
-there is no ``pparray_get_stream()`` function, as streams in PDF are always indirect
-(may only reside in ``ref->object.stream``). To get the stream from array use::
-
- ppstream * pparray_rget_stream (pparray *array, size_t index);
-
-Dict
-----
-
-PDF dicts are represented as ``ppdict`` structure, which is C-array of ``ppobj`` with parallel
-C-array of ``ppname`` pointers. To get the size of a dict::
-
- size_t ppdict_size(ppdict *dict) // macro, returns the number of key-val pairs
-
-To get the value at a given index (integer)::
-
- ppobj * ppdict_at(ppdict *dict, index) // macro, no index bounds check
-
-To get the name (key) at a given index::
-
- ppname * ppdict_key(ppdict *dict, index) // macro, no index bounds check
-
-To iterate over dict key-val pairs::
-
- ppdict *dict;
- ppname **pkey;
- ppobj *obj;
-
- for (ppdict_first(dict, pkey, obj); *pkey != NULL; ppdict_next(pkey, obj))
- {
- // do something with *pkey and obj
- }
-
-There is no magic in first/next macros, just iteration through keys and values lists pointers.
-For convenient iteration, a list of keys is terminated with NULL, so in the code above ``*pkey != NULL``
-is used as the loop condition. One may also iterate via indices::
-
- ppdict *dict;
- size_t index, size;
- ppname *key;
- ppobj *obj;
- for (index = 0, size = ppdict_size(dict); index < size; ++index)
- {
- key = ppdict_key(dict, index);
- obj = ppdict_at(dict, index);
- // do something with key and obj
- }
-
-To get the object associated with a given name, use one of the following::
-
- ppobj * ppdict_get_obj (ppdict *dict, const char *name);
- int ppdict_get_bool (ppdict *dict, const char *name, int *v);
- int ppdict_get_int (ppdict *dict, const char *name, ppint *v);
- int ppdict_get_uint (ppdict *dict, const char *name, ppuint *v);
- int ppdict_get_num (ppdict *dict, const char *name, ppnum *v);
- ppname ppdict_get_name (ppdict *dict, const char *name);
- ppstring ppdict_get_string (ppdict *dict, const char *name);
- pparray * ppdict_get_array (ppdict *dict, const char *name);
- ppdict * ppdict_get_dict (ppdict *dict, const char *name);
- ppref * ppdict_get_ref (ppdict *dict, const char *name);
-
-Note that all getters accepts ``const char *`` as key, so it is ok to say::
-
- ppdict_rget_dict(dict, "Resources");
-
-(the most common use I guess). But to use ``ppname`` object as a key, one have to
-use data member::
-
- ppdic_rget_dict(dict, name->data); // ppname *name
-
-Every ``ppdict_get_*`` getter has ``ppdict_rget_*`` counterpart that dereferences
-indirect objects if necessary. Note that there is no ``ppdict_get_stream()`` function,
-but there is::
-
- ppstream * ppdict_rget_stream (ppdict *dict, const char *name);
-
-So far dicts comes with no names mapping, so by-name dict accessors perform a linear search
-through the keys list. PDF dicts are usually small.
-
-Stream
-------
-
-PDF streams are represented as ``ppstream`` objects. To get the stream dict::
-
- ppdict * ppstream_dict(ppstream *stream) // macro
-
-To read the stream data::
-
- uint8_t * ppstream_first (ppstream *stream, size_t *size, int decode);
- uint8_t * ppstream_next (ppstream *stream, size_t *size);
- void ppstream_done (ppstream *stream);
-
-Both ``first` and ``next`` functions return a chunk of stream data and sets the ``size`` of the chunk.
-``decode`` parameter tell the reader to decompress the stream (1) or return raw (0). A call to ``ppstream_next()``
-must be preceeded by ``ppstream_first()``. Once you're done with the stream, you have to call ``ppstream_done()``,
-no matter if the stream has been read to the end or not. The stream data iterator in use::
-
- uint8_t *data;
- size_t size;
- ppstream *stream;
- int decode = 1; // 1 - get decompressed, 0 - get raw
-
- for (data = ppstream_first(stream, &size, decode); data != NULL; data = ppstream_next(stream, &size))
- {
- // do something with data and its size
- }
- ppstream_done(stream);
-
-Every subsequent iterator call invalidates the previous reader output, so you have to utilize the returned chunk
-of data just after you ot that. So the following is wrong::
-
- data1 = ppstream_first(stream, &size, 1);
- data2 = ppstream_next(stream, &size);
- data3 = ppstream_next(stream, &size);
- some_output(data1, size);
- some_output(data2, size);
-
-The reader calls usually return the same pointer to internal buffer, just filled with a different data.
-``pplib`` allocates reasonably large buffer and fills that buffer on subsequent calls to the reader.
-
-If the source stream has no compression, using both ``decode == 1`` and ``decode == 0`` should give the same result.
-You can check if the stream is actually compressed with::
-
- ppstream_compressed(stream) // macro, returns non zero if /Filter is present
-
-It might be necessary to load the entire stream data at once::
-
- uint8_t * ppstream_all (ppstream *stream, size_t *size, int decode);
-
-If the initial buffer size is insufficient, it grows until the entire stream data is loaded. You must call
-``ppstream_done(stream)`` after using returned data.
-
-``ppstream_done()`` doesn't invalidate the stream object, it just closes its internal reader.
-The stream itself remains a valid object (eg. one can read it again if necessary),
-but the reader buffer is released. It is actually not freed but kept for future the reuse with that on some other stream,
-but you still need to mark it ready for reuse to avoid allocating a separate buffer for every stream you're going to read.
-
-Stream data readers will return ``NULL`` if you haven't close the previous reader process with ``ppstream_done()``. All below is wrong::
-
- data1 = ppstream_all(stream, &size, 1);
- data2 = ppstream_all(stream, &size, 1); // data2 == NULL
- // or
- data1 = ppstream_first(stream, &size, 1);
- data2 = ppstream_first(stream, &size, 1); // data2 == NULL
- // or
- data1 = ppstream_first(stream, &size, 1);
- data2 = ppstream_all(stream, &size, 1); // data2 == NULL
-
-To avoid unnecessary dependencies, ``pplib`` does not support image filters (``/DCT``, ``/JPX``, ``/JBIG``, ``/CCITT``).
-But it is ok to read the stream with ``decode`` set to 1 on such streams. ``pplib`` assumes that the image is the
-final/target stream form and just returns it as-is. Eg. in the case of JPEG (``/DCT`` filtered) image both calls should
-give the same results::
-
- ppstream_all(jpegstream, &jpegsize, 0); // don't decode, return what's there
- ppstream_all(jpegstream, &jpegsize, 1); // decode but found image filter, effectively the same
-
-A bit more about streams memory. As mentioned, ``pplib`` allocates buffers for stream readers. After ``ppstream_done()``,
-the stream no longer *owns* the buffer space. But the buffer may remain allocated, to be reused with future readers.
-``pplib`` keeps a pool of several buffers. This means, that when you use stream readers, ``pplib`` eats
-some memory (1MB or so) that is not freed, even if no streams are used. And even if you free all objects.
-If you suffer from this, you can optionally use a pair of functions::
-
- void ppstream_init_buffers (void);
- void ppstream_free_buffers (void);
-
-The first initializes buffers pool, unless done so far. Currently ``pplib`` cares of it before opening every stream reader,
-so it is not obligatory. The second frees a pool of buffers. The intended use is to call ``ppstream_init_buffers()`` once
-as kind of library initializer and to call ``ppstream_free_buffers()`` once, as the library finalizer.
-
-Filters
--------
-
-``ppstream`` knows its filter(s) and keps it as ``stream->filter``::
-
- // ppstream *stream;
- ppstream_filter *info = &stream->filter;
-
-``ppstream_filter`` is the following structure::
-
- typedef struct {
- ppstreamtp *filters; // c-array of filter identifiers (enum integers)
- ppdict **params; // c-array of ppdict pointers
- size_t count; // number of filters, length of the arrays (typically 1)
- } ppstream_filter;
-
-If ``count > 0`` then ``filters`` member is not NULL. Filters array keeps integer constants::
-
- PPSTREAM_BASE16 /* /ASCIIHexDecode */
- PPSTREAM_BASE85 /* /ASCII85Decode */
- PPSTREAM_RUNLENGTH /* /RunLengthDecode */
- PPSTREAM_FLATE /* /FlateDecode */
- PPSTREAM_LZW /* /LZWDecode */
- PPSTREAM_CCITT /* /CCITTFaxDecode */
- PPSTREAM_DCT /* /DCTDecode */
- PPSTREAM_JBIG2 /* /JBIG2Decode */
- PPSTREAM_JPX /* /JPXDecode */
- PPSTREAM_CRYPT /* /Crypt */
-
-Params array keeps corresponding filter parameters (``/DecodeParms``) if present. ``params`` member is not NULL
-if ``count > 0`` and the stream dict has ``/DecodeParms`` entry. Even if ``params`` is there,
-for every N-th filter, ``params[N]`` may be NULL (corresponding to PDF ``null``).
-
-``stream->filter`` keeps the source stream filter information, which may not correspond to the result of stream readers
-(``ppstream_first()``, ``ppstream_next()``, ``ppstream_all()``). The get the filters info relevant to the result from readers::
-
- void ppstream_filter_info (ppstream *stream, ppstream_filter *info, int decode);
-
-The function fills ``ppstream_filter`` structure according to the expected result from stream readers (example 3 shows
-how to use it to reconstruct ``/Filter`` and ``/DecodeParms`` when copying the stream to some other PDF).
-
-To convert filter identifier (``ppstreamtp``) to a corresponding PDF filter name::
-
- const char * ppstream_filter_name[];
-
-To covert ``ppname`` to filter identifier::
-
- int ppstream_filter_type (ppname filtername, ppstreamtp *filtertype);
- // returns 1 and sets filtertype if filtername is the proper filter name
-
-Additional information about the stream can be fetched from macros::
-
- ppstream_compressed(stream) /* stream->flags & (PPSTREAM_FILTER|PPSTREAM_IMAGE) */
- ppstream_filtered(stream) /* stream->flags & PPSTREAM_FILTER */
- ppstream_image(stream) /* stream->flags * PPSTREAM_IMAGE */
-
-``stream->flags`` is a binary sum of the following::
-
- PPSTREAM_FILTER /* set iff the stream filters list has one of: BASE16, BASE85, RUNLENGTH, FLATE, LZW */
- PPSTREAM_IMAGE /* set iff the stream filters list has one of: CCITT, DCT, JBIG2, JPX */
- PPSTREAM_ENCRYPTED /* set iff the stream is encrypted */
- PPSTREAM_ENCRYPTED_OWN /* set iff the stream has own CRYPT filter */
-
-Note that ``PPSTREAM_COMPRESSED`` is not there any longer, use ``ppstream_compressed()`` instead.
-And there is some more, see ``ppapi.h``.
-
-Ref
----
-
-Indirect objects are represented as ``ppref`` structure. To get the object that the
-reference refers to::
-
- ppobj * ppref_obj(ppref *ref) // macro
-
-``ppref`` structure also keeps the reference number and version, a pointer to cross reference table it belongs
-to and others, but I guess you won't need anything but the referenced object. ``pplib`` parser resolves references
-on-fly. So if there is a dict with indirect objects::
-
- <<
- /Type /Page
- /Resources 123 0 R
- ...
- >>
-
-the parser will produce ``ppdict`` with ``Resources`` key pointing the proper ``ppref *`` value.
-If you need more, access ``ppref`` members::
-
- struct ppref {
- ppobj object; // target object
- ppuint number, version; // identifiers
- size_t offset; // file offset (useless for you, may be zero for compressed objects)
- ppuint length; // the length of the original object data
- ppxref *xref; // cross reference table it belongs to
- };
-
-
-XRef
-----
-
-Cross reference table is exposed as ``ppxref`` (incomplete type, you can only oprate on its pointer).
-To get top document xref::
-
- ppxref * ppdoc_xref (ppdoc *pdf);
-
-To get previous (older) xref::
-
- ppxref * ppxref_prev (ppxref *xref);
-
-To find an object of a given refnumber::
-
- ppref * ppxref_find (ppxref *xref, ppuint refnumber);
-
-[Note: since pplib v0.98 in case of documents with incremental update, ``ppxref_find()`` returns
-the newest available version of a given object rather than the object in a given body.]
-
-PDF
----
-
-PDF document is represented as ``ppdoc`` structure (incomplete type, you can only operate on its pointer).
-To load a document from file::
-
- ppdoc * ppdoc_load (const char *filename);
-
-To load a document from file handle::
-
- ppdoc * ppdoc_filehandle (FILE *file, int closefile); // closefile 1 to fclose() on end
-
-To load a document from memory data::
-
- ppdoc * ppdoc_mem (const void *data, size_t size);
-
-The data is assumed to be a buffer allocated with ``malloc`` - it is freed when destroying ``ppdoc``.
-
-Both loaders returns ``NULL`` on failure.
-
-To free ``ppdoc`` and all objects it refers to::
-
- void ppdoc_free (ppdoc *pdf);
-
-So far we haven't mention about any explicit object reclaimers. There are no dedicated ``free`` functions
-for other objects. You don't allocate or free objects yourself. ``ppdoc`` object is an owner of all
-beings it refers to. It also means that every object described so far is alive as long as the containing
-``ppdoc`` is alive.
-
-To access main PDF dicts::
-
- ppdict * ppdoc_trailer(ppdoc *pdf); // returns top xref trailer dict
- ppdict * ppdoc_catalog(ppdoc *pdf); // returns catalog referred from the trailer
- ppdict * ppdoc_info(ppdoc *pdf); // returns info dict referred from the trailer
-
-To get the PDF version::
-
- const char * ppdoc_version_string (ppdoc *pdf); // version string
- int ppdoc_version_number (ppdoc *pdf, int *minor); // minor and major numbers
-
-To get the file size of the source PDF document::
-
- size_t ppdoc_file_size (ppdoc *pdf);
-
-To get the number of objects in all xrefs::
-
- ppuint ppdoc_objects (ppdoc *pdf);
-
-To get the approx usage of memory::
-
- size_t ppdoc_memory (ppdoc *pdf, size_t *waste);
-
-Encryption
-----------
-
-``pplib`` handles encrypted (password protected) documents. If a document is encrypted, most of strings and streams are ciphered.
-In that form they are unreadable and rather useless, you can't even rewrite such strings/streams as-is to a different PDF output.
-It is a common practise to *protect* documents with an empty password. Such documents remain readable in Acrobat (just opens them without prompting
-for a password), but some features (eg. printing) may restricted by the application.
-
-When ``pplib`` detects encryption, it follows Acrobat approach and first tries an empty password. If it succeeds, ``pplib`` proceeeds normally, providing
-an access to decrypted strings and streams, as if they weren't ciphered. If the document is protected with non-empty password, you have to call
-``ppdoc_crypt_pass()``. Until you provide a password, ``ppdoc`` object returned by ``ppdoc_load()`` function has all object entries set to ``null``.
-
-Once the document is loaded, encryption status can be checked with::
-
- ppcrypt_status ppdoc_crypt_status (ppdoc *pdf);
-
-``ppcrypt_status`` (enum) may have the following values:
-
- ``PPCRYPT_NONE`` - no encryption, go ahead
- ``PPCRYPT_DONE`` - encryption present but password succeeded, go ahead
- ``PPCRYPT_PASS`` - encryption present, need non-empty password
- ``PPCRYPT_FAIL`` - invalid or unsupported encryption (eg. undocumented in pdf spec)
-
-If a password is needed, you can provide one with::
-
- ppcrypt_status ppdoc_crypt_pass (ppdoc *pdf, const void *userpass, size_t userpasslength,
- const void *ownerpass, size_t ownerpasslength);
-
-Providing one of two is enough to decrypt the document.
-It is ok to use the same password for owner and user -- ``pplib`` will try both.
-
-The function returns ``PPCRYPT_DONE`` if the password succeeds and the previous crypt status otherwise.
-
-Your custom loader function may look like that::
-
- ppdoc *pdf;
- pdf = ppdoc_load("file.pdf");
- if (pdf == NULL)
- return NULL;
- switch (ppdoc_crypt_status(pdf))
- {
- case PPCRYPT_NONE:
- case PPCRYPT_DONE:
- return pdf;
- case PPCRYPT_PASS:
- if (ppdoc_crypt_pass(pdf, "dummy", 5, "dummy", 5) == PPCRYPT_DONE)
- return pdf;
- printf("sorry, password needed\n");
- ppdoc_free(pdf);
- return NULL;
- case PPCRYPT_FAIL:
- printf("sorry, encryption failed\n");
- ppdoc_free(pdf);
- return NULL;
- }
-
-See ``pplib`` tests suite for a complete code.
-
-If you'd like to know what permissions are given/restricted to encrypted document::
-
- ppint ppdoc_permissions (ppdoc *pdf);
-
-Returned value can be queried with the following binary flags (you can verify with Acrobat *File -> Properties -> Security* tab)::
-
- PPDOC_ALLOW_PRINT // printing
- PPDOC_ALLOW_MODIFY // filling form fields, signing, creating template pages
- PPDOC_ALLOW_COPY // copying, copying for accessibility
- PPDOC_ALLOW_ANNOTS // filling form fields, copying, signing
- PPDOC_ALLOW_EXTRACT // contents copying for accessibility
- PPDOC_ALLOW_ASSEMBLY // (no effect)
- PPDOC_ALLOW_PRINT_HIRES // (no effect)
-
-``pplib`` does absolutelly nothing with permissions, it cares only to decrypt the document. As mentioned, encryption applies to strings
-and streams. ``pplib`` decrypt strings when parsing document objects, so the result you get is *normal* (not ciphered).
-Streams are decrypted whenever you access them. Even if you ask for a raw stream data, you'll get a raw (compressed) stream, but decrypted.
-So except the check to ``ppdoc_crypt_status()``, you shouldn't bother about encryption.
-
-In encrypted documents most of streams are encrypted. To check if a given stream is encrypted::
-
- ppstream_encrypted(stream) // macro, returns non-zero if encrypted
-
-Encryption is independent from compression, don't confuse with ``ppstream_compressed()``
-
-.. caution::
- Starting from ``pplib v2.10`` all passwords should be passed as ``UTF-8``.
- Earlier PDF encryption algorithms (/V 1..4, PDF 1.7) were based on ``PdfDocEncoding``.
- Newer algorithms (/V 5, PDF 1.8-2.0) expect Unicode encoded as ``UTF-8``.
- ``pplib`` API now expects ``UTF-8`` and if opening documents with older encryption methods,
- it tries to make a conversion to 8-bit encoding. In earlier versions ``pplib`` didn't
- make any password preprocessing, treating them as raw byte arrays.
- So in case of passwords with fancy characters, it may behave differently.
-
-Pages
------
-
-Several helpers to deal with pages. To get the number of pages::
-
- ppuint ppdoc_page_count (ppdoc *pdf);
-
-To access the root pages tree node::
-
- ppref * ppdoc_pages(ppdoc *pdf);
-
-To get the page reference at a given index::
-
- ppref * ppdoc_page (ppdoc *pdf, ppuint index);
-
-``index`` is a page number. First page has number 1. For index out of bounds ``ppdoc_page()`` returns NULL.
-Iterating over pages using index from 1 to ``ppdoc_page_count()`` and calling ``ppdoc_page()`` on each iteration
-would be suboptimal. Here is a dedicted iterator for this::
-
- ppref * ppdoc_first_page (ppdoc *pdf);
- ppref * ppdoc_next_page (ppdoc *pdf);
-
-The iterator in use::
-
- ppdoc *pdf;
- ppref *ref;
- ppdict *dict;
- int pageno;
-
- pdf = ppdoc_load("file.pdf");
- for (ref = ppdoc_first_page(pdf), pageno = 1; ref != NULL; ref = ppdoc_next_page(pdf), ++pageno)
- {
- dict = ppref_obj(obj)->dict; // take for granted it is a dict
- // do something with the page dict
- }
-
-Functions related to pages return ``ppref *`` ensured to contain dict object, so you don't need sanity
-type checks here.
-
-Contents
---------
-
-PDF page contents can be given as a stream or array of streams. Here is a convenience iterator over page
-contents streams::
-
- ppstream * ppcontents_first (ppdict *dict);
- ppstream * ppcontents_next (ppdict *dict, ppstream *stream);
-
-A complete example of contents stream parser use is given below (example 2).
-But before we get there, we need to introduce ``ppcontext`` object. Conceptually,
-``ppcontext`` is an owner (memory handler) of objects created on demand (beyond the ``ppdoc``).
-So far used only with contents stream parser, which might produce quite some data that we want
-to release just after used. To create a new context::
-
- pcontext * ppcontext_new (void);
-
-It initializes a new context and its internal memory heap, taking about 64kB on start. After that,
-the context is ready to produce objects (contents parsing functions below). Once objects produced
-from a given context are no longer needed::
-
- void ppcontext_done (ppcontext *context);
-
-It restores the context to its initial state, as after ``ppcontext_new()``. It means that the context
-is ready to produce another bunch of beings (in the example below, all objects from the next page contents).
-Once the context is not needed anymore::
-
- void ppcontext_free (ppcontext *context);
-
-Now, contents stream parser functions take the context as an argument. Iterator form of contents stream parser
-that allows to process the contents operator by operator::
-
- ppobj * ppcontents_first_op (ppcontext *context, ppstream *stream, size_t *psize, ppname *pname);
- ppobj * ppcontents_next_op (ppcontext *context, ppstream *stream, size_t *psize, ppname *pname);
-
-Returned ``ppobj *`` is a pointer to operands list. ``*psize`` is the number of operands on stack.
-The operator itself is stored as ``*pname``.
-
-To parse the entire contents stream at once with no stop at every operator::
-
- ppobj * ppcontents_parse (ppcontext *context, ppstream *stream, size_t *psize);
-
-Returns probably quite long list of all parsed objects (operands and operatos) in one piece.
-The number of objects is stored to ``*psize``.
-
-[Contents may contain so called inline images, that breaks a simple scheme of operands / operator syntax::
-
- BI <keyval pairs> ID <binary image data> EI
-
-Contents parser treats this genuine triplet as a single piece, producing two operands (dict and string)
-followed by ``EI`` operator name.]
-
-Boxes
------
-
-Boxes (rectangles) in PDF are roughly 4-number arrays, but with a special intent.
-``pplib`` provides a basic interface for these special arrays::
-
- typedef struct {
- ppnum lx, ly, rx, ry;
- } pprect;
-
-This type is used only by helper functions - PDF parser is not aware of the rectangle type.
-To convert ``pparray`` to ``pprect``::
-
- pprect * pparray_to_rect (pparray *array, pprect *rect); // returns rect or NULL
-
-In example::
-
- pprect rect;
- if (pparray_to_rect(array, &rect) != NULL)
- ; // do something with rect
-
-To get some image bounding box::
-
- pprect * ppdict_get_rect (ppdict *dict, const char *name, pprect *rect);
- // eg. ppdict_get_rect(imagedict, "BBox", &rect)
-
-To get some page box::
-
- pprect * ppdict_get_box (ppdict *dict, const char *name, pprect *rect);
- // eg. ppdict_get_box(pagedict, "MediaBox", &rect)
-
-The later not only checks the pagedict, but also goes through parent page nodes.
-
-Transforms
-----------
-
-Transformations are given as 6-number arrays, but with a special intent.
-``pplib`` provides a basic interface for these special arrays::
-
- typedef struct {
- ppnum xx, xy, yx, yy, x, y;
- } ppmatrix;
-
-This type is used only by helper functions - PDF parser is not aware of the matrix type.
-To convert ``pparray`` to ``ppmatrix``::
-
- ppmatrix * pparray_to_matrix (pparray *array, ppmatrix *matrix);
-
-In example::
-
- ppmatrix matrix;
- if (pparray_to_matrix(array, &matrix) != NULL)
- ; // do something with matrix
-
-To get the matrix from dict::
-
- ppmatrix * ppdict_get_matrix (ppdict *dict, const char *name, ppmatrix *matrix);
- // eg. ppdict_get_matrix(imagedict, "Matrix", &matrix)
-
-Errors handling
----------------
-
-``pplib`` is not verbose, but might happen that it needs to log some error message, eg. when parsing
-of some PDF boject fails due to invalid offsets. By default, ``pplib`` prints the message to stdout, eg.::
-
- invalid 123 0 R object at offset 123123
-
-To replace the default logger, you can provide your own::
-
- void pplog_callback (pplogger_callback logger, void *alien);
-
-``pplogger_callback`` is a function::
-
- void your_callback (const char *message, void *alien);
-
-In example, to redirect messages to stderr you may define a function::
-
- void your_callback (const char *message, void *alien)
- {
- fprintf((FILE *)alien, "\nooops: %s\n", message);
- }
-
-Then set the callback somewhere before loading documents::
-
- pplog_callback(your_callback, stderr);
-
-(example 2 uses that).
-
-To set the default log messages prefix, eg. ``pplib:``, use::
-
- int pplog_prefix (const char *prefix)
-
-Default is empty. The function succeeds if provided prefix is reasonably short (less then 32 bytes).
+ +``pplib`` 2.x +============= + +``pplib`` is a library for raw PDF access. It parses PDF documents and provides an interface to access document structures in C. + +C-API +===== + +Types +----- + +``pplib`` defines several C-types to represent PDF types: + +- ``ppbyte`` - char +- ``ppint`` - signed integer (``int64_t``) +- ``ppnum`` - real number (double) +- ``ppname`` - PDF name +- ``ppstring`` - PDF string +- ``pparray`` - PDF array +- ``ppdict`` - PDF dict +- ``ppstream`` - PDF stream +- ``ppref`` - PDF indirect reference +- ``ppobj`` - a container of all above + +Among ``ppint`` and ``ppnum``, we also use ``ppuint`` - unsigned integer (machine word, alias to ``size_t``). + +Other API types: + +- ``ppdoc`` - PDF document +- ``ppxref`` - cross-references table +- ``ppcontext`` - ... later +- ``pprect`` - rectangle +- ``ppmatrix`` - matrix + +Integer and number are as simple types. Names and strings used to be aliases to ``char *`` +in ``pplib 1.x``, now they are structures; all related API functions operate on pointers. +Other types (array, dict, stream, reference, object container, xref, doc) are C-structures, +and you operate it their pointers. So when you declare a simple type variable you say:: + + ppuint u; + ppnum n; + ... + +And when you declare a compound type you operate on pointers:: + + ppobj *obj; + ppname *name; + ppstring *string; + pparray *array; + ppdict *dict; + ppstream *stream; + ppref *ref; + ppdoc *pdf; + +Most of those C-types are defined in library header ``ppapi.h`` (complete types). Some others are incomplete +(eg. you can't say ``sizeof(ppdoc)`` or ``sizeof(ppxref)``). This is to avoid unnecesary dependencies in +the header. The library itself uses ``pplib.h`` header but for auxilary applications including a standalone +``ppapi.h`` header should be enough. + +``pplib`` was designed having **read-only** PDF access in mind. Even if some structure is completelly exposed, +so that you can directly access its members, you should treat them as read-only. I don't make them ``const`` because +then all variable declarations would need to be ``const``, which is annoying, and I'd need some trickery in the library +internals to unconst. Besides, nothing is really const for C type casts. + +Object +------ + +A common container for all elementary PDF object types is ``ppobj`` structure. ``ppobj`` has a type identifier +(integer) and union of values:: + + struct ppobj { + ppobjtp type; + union { + ppint integer; + ppnum number; + ppname *name; + ppstring *string; + pparray *array; + ppdict *dict; + ppstream *stream; + ppref *ref; + void *any; + }; + }; + +Object type is one of constants (enum):: + + PPNONE + PPNULL + PPBOOL + PPINT + PPNUM + PPNAME + PPSTRING + PPARRAY + PPDICT + PPSTREAM + PPREF + +The type determines the structure member you're allowed to access:: + + ppobj *obj; + ... + switch (obj->type) + { + case PPNONE: // shouldn't actually happen, indicates some failure + break; + case PPNULL: // valid PDF null object, no value + break; + case PPBOOL: // do something with obj->integer (ppint), value 0 or 1 + break; + case PPINT: // do something with obj->integer (ppint) + break; + case PPNUM: // do something with obj->number (ppnum) + break; + case PPNAME: // do something with obj->name (ppname *) + break; + case PPSTRING: // do something with obj->string (ppstring *) + break; + case PPARRAY: // do something with obj->array (pparray *) + break; + case PPDICT: // do something with obj->dict (ppdict *) + break; + case PPSTREAM: // do something with obj->stream (ppstream *) + break; + case PPREF: // do something with obj->ref (ppref *) + break; + } + +More often then not you know exactly what type of object value is expected, in which case +you may use one of the following macros:: + + // returns 1 if o->type is PPNULL + int ppobj_get_null(o) \ + + // if o->type is PPBOOL, sets int v to 0 or 1 and returns 1, 0 otherwise + int ppobj_get_bool(o, v) + + // if o->type is PPINT, sets ppint v and returns 1, 0 otherwise + int ppobj_get_int(o, v) + + // if o->type is PPINT and >= 0, sets ppuint v and returns 1, 0 otherwise + int ppobj_get_uint(o, v) + + // if o->type is PPNUM or PPINT, sets ppnum v and returns 1, 0 otherwise + int ppobj_get_num(o, v) + + // if o->type is PPNAME returns the name, NULL otherwise + ppname * ppobj_get_name(o) + + // if o->type is PPSTRING returns the string, NULL otherwise + ppstring * ppobj_get_string(o) + + // if o->type is PPARRAY returns the array, NULL otherwise + pparray * ppobj_get_array(o) + + // if o->type is PPDICT returns the dict, NULL otherwise + ppdict * ppobj_get_dict(o) + + // if o->type is PPSTREAM returns the stream, NULL otherwise + ppstream * ppobj_get_stream(o) + + // if o->type is PPREF returns the reference, NULL otherwise + ppref * ppobj_get_ref(o) + +Note the coercion from integer to real number, but not reverse. In practise, whenever you expect a real number, +you should also handle integer (eg. '1' used instead of '1.0' is pretty common in PDF). + +It is a common case that the object is given as an indirect reference, but what you actually +want is not the reference, but the object referred by it. Here is a helper for it:: + + // if o->type is PPREF, returns what the reference points, otherwise returns o + ppobj * ppobj_rget_obj(o) + +Also every ``ppobj_get_*`` macro has ``ppobj_rget_*`` counterpart that makes a check +for the expected type, but if the object is PPREF, it jumps to the target object. +So for example ``ppobj_rget_dict(obj)`` will return dict if ``obj`` is of type PPDICT +or if it is of type PPREF and ``obj->ref`` hosts an object of type PPDICT. + +Names +----- + +PDF names are represented as ``ppname`` pointer (``ppname`` used to be an alias to ``char *``, now it is a structure). +To access the name data:: + + ppbyte * ppname_data(name) // name->data, bytes array + +For convenient use in C, names are ``'\0'`` terminated. But to get the length of name better always use +``ppname_size()`` macro. ``ppname`` object knows its size, don't use ``strlen()``:: + + size_t ppname_size(ppname name); // name->size, the length of name in bytes + +In current implementation names are not hashed anyhow, so name-to-name comparison is not smarter than ``memcmp()``. +Use macros:: + + int ppname_is(ppname name, "literal"); // to compare ppname with C-literal string + int ppname_eq(ppname name, ppname other); // to compare ppname with a different name + +If you use ``pplib`` to parse contents streams, you may need to distinguish names from operators +(more precisely executable names). Names in PDF are preceeded by '/', executable names aren't. In both +cases PDF parser will produce ``ppname`` but the result can be distingushed with:: + + int ppname_exec(ppname name); // macro, returns non-zero if the name is executable + +Names are kept in their raw form, with possible PDF specific escapes (in text below we call it **encoded** form). +Leading '/' is omitted. One may need a decoded name, with no PDF escapes. +A pair of functions provides a simple interface to switch between those two forms:: + + // these helpers rely on name->alterego member + ppname * ppname_decoded (ppname *name); // returns decoded (unescaped) form of the name + ppname * ppname_encoded (ppname *name); // returns encoded (escaped) form of the name + ppbyte * ppname_decoded_data (ppname *name); + ppbyte * ppname_encoded_data (ppname *name); + +In pretty most cases a PDF name contains only letters (no special characters, no escapes), so decoded and encoded forms are identical. +In that case both functions simply return the argument. It is ok to call ``ppname_decoded()`` on already decoded form +and ``ppname_encoded()`` on already encoded form. Both forms are produced by PDF objects parser, so accessing ``ppname`` alter ego +in whatever direction needs no extra decoding or allocation costs (the cost is paid by parser). + +String +------ + +PDF strings have the same internal construction as names, so most of names description above applies to strings as well. +``ppstring`` is a structure (used to be an alias to ``char *``). ``string->data`` is ``\0``-terminated c-array of ``ppbytes``. +To get the data:: + + ppbyte * ppstring_data(ppstring *string); // string->data, macro + +To get the size of the string:: + + size_t ppstring_size(ppstring *string); // macro, returns the length of the string in bytes + +Strings are provided in their raw form, preserving PDF specific escapes, but with no +``()`` or ``<>`` delims. To distinguish plain strings from hex strings:: + + int ppstring_hex(ppstring string); // macro, returns non zero if hex string + +Or if you prefer:: + + switch (ppstring_type(string)) + { + case PPSTRING_PLAIN: // literal string, surrounded by ``(`` and ``)`` in PDF + break; + case PPSTRING_BASE16: // hex string, surrounded by ``<`` and ``>`` in PDF + break; + case PPSTRING_BASE85: // base85 string surrounded by ``<~`` and ``~>`` in PDF + break; + } + +The last is actually Postscript specific, not used in PDF, but I think it might appear in contents streams... +No matter how the string is given in PDF (plain or hex), here are two functions to +switch between encoded and decoded strings forms:: + + ppstring * ppstring_decoded (ppstring *string); // returns decoded string possibly with PDF escapes + ppstring * ppstring_encoded (ppstring *string); // returns encoded string with no PDF escapes + ppbyte * ppstring_decoded_data (ppstring *string); + ppbyte * ppstring_encoded_data (ppstring *string); + +For hex strings, encoded form contains hex digits, while decoded form contains arbitrary bytes (the result of hex decoding). +Plain strings usually contains printable ASCII characters, but they might contain any binary data. +As with names, objects parser produces both forms. The raw form with PDF escapes (or raw hex form) the main one. +Eg. when you access ``obj->string`` you always get the encoded form. At any moment you can switch to its alter ego. + +No matter if the string is plain or hex, if its first two bytes (decoded) are UTF16 BOM, the string is unicode. +``ppstring`` object *knows* it is unicode or not:: + + switch (ppstring_utf(string)) + { + case PPSTRING_UTF16LE: // unicode string, utf16le + break; + case PPSTRING_UTF16BE: // unicode string, utf16be + break; + default: // no unicode + } + +Or simply:: + + if (ppstring_utf(string) != 0) { + // handle unicode string + } + +If the string is unicode, BOM remains the part of the string -- ``pplib`` parser does not strip it. +Unicode or not, encoded or decoded, strings are always C-arrays of bytes and ``ppstring_size()`` +always returns the size in bytes. + +Array +----- + +PDF arrays are represented as ``pparray`` type, which is C-array of ``ppobj`` structures. +To get the size:: + + size_t pparray_size(pparray *array) // macro, returns the number of array items + +To get ``ppobj *`` at a given index:: + + ppobj * pparray_at(array, index) // macro, returns ppobj * (no index check) + ppobj * pparray_get(array, index) // macro, returns ppobj * or NULL (with index check) + ppobj * pparray_get_obj (pparray *array, size_t index); // function equiv to pparray_get() + +Iterating over array elements:: + + pparray *array; + size_t index, size; + ppobj *obj; + for (size = pparray_size(array), pparray_first(array, index, obj); index < size; pparray_next(index, obj)) + { + // do something with index and obj + } + +There is no magic first/next macros, just iteration over pointers. One could also use something like:: + + for (index = 0, size = array->size; index < size; ++index) + { + obj = pparray_at(array, index); + // do something with index and obj + } + +When getting values from array and expecting a result of known type, use one of the following:: + + int pparray_get_bool (pparray *array, size_t index, int *v); // get boolean value + int pparray_get_int (pparray *array, size_t index, ppint *v); // get ppint value + int pparray_get_uint (pparray *array, size_t index, ppuint *v); // get ppuint value + int pparray_get_num (pparray *array, size_t index, ppnum *v); // get ppnum value + ppname * pparray_get_name (pparray *array, size_t index); // get ppname * value + ppstring * pparray_get_string (pparray *array, size_t index); // get ppstring * value + pparray * pparray_get_array (pparray *array, size_t index); // get pparray * value + ppdict * pparray_get_dict (pparray *array, size_t index); // get ppdict * value + ppref * pparray_get_ref (pparray *array, size_t index); // get ppref * value + +As with ``ppobj_get_*`` suite, numeric types getters set the value of a given type and returns 1, if the type matches. +Otherwise sets nothing and returns 0. Other getters return the value if the type matches, or NULL. + +Every function from ``pparray_get_*`` suite have its ``pparray_rget_*`` counterpart +that dereferences indirect objects (as explained for ``ppobj_rget_*`` getters). Note that +there is no ``pparray_get_stream()`` function, as streams in PDF are always indirect +(may only reside in ``ref->object.stream``). To get the stream from array use:: + + ppstream * pparray_rget_stream (pparray *array, size_t index); + +Dict +---- + +PDF dicts are represented as ``ppdict`` structure, which is C-array of ``ppobj`` with parallel +C-array of ``ppname`` pointers. To get the size of a dict:: + + size_t ppdict_size(ppdict *dict) // macro, returns the number of key-val pairs + +To get the value at a given index (integer):: + + ppobj * ppdict_at(ppdict *dict, index) // macro, no index bounds check + +To get the name (key) at a given index:: + + ppname * ppdict_key(ppdict *dict, index) // macro, no index bounds check + +To iterate over dict key-val pairs:: + + ppdict *dict; + ppname **pkey; + ppobj *obj; + + for (ppdict_first(dict, pkey, obj); *pkey != NULL; ppdict_next(pkey, obj)) + { + // do something with *pkey and obj + } + +There is no magic in first/next macros, just iteration through keys and values lists pointers. +For convenient iteration, a list of keys is terminated with NULL, so in the code above ``*pkey != NULL`` +is used as the loop condition. One may also iterate via indices:: + + ppdict *dict; + size_t index, size; + ppname *key; + ppobj *obj; + for (index = 0, size = ppdict_size(dict); index < size; ++index) + { + key = ppdict_key(dict, index); + obj = ppdict_at(dict, index); + // do something with key and obj + } + +To get the object associated with a given name, use one of the following:: + + ppobj * ppdict_get_obj (ppdict *dict, const char *name); + int ppdict_get_bool (ppdict *dict, const char *name, int *v); + int ppdict_get_int (ppdict *dict, const char *name, ppint *v); + int ppdict_get_uint (ppdict *dict, const char *name, ppuint *v); + int ppdict_get_num (ppdict *dict, const char *name, ppnum *v); + ppname ppdict_get_name (ppdict *dict, const char *name); + ppstring ppdict_get_string (ppdict *dict, const char *name); + pparray * ppdict_get_array (ppdict *dict, const char *name); + ppdict * ppdict_get_dict (ppdict *dict, const char *name); + ppref * ppdict_get_ref (ppdict *dict, const char *name); + +Note that all getters accepts ``const char *`` as key, so it is ok to say:: + + ppdict_rget_dict(dict, "Resources"); + +(the most common use I guess). But to use ``ppname`` object as a key, one have to +use data member:: + + ppdic_rget_dict(dict, name->data); // ppname *name + +Every ``ppdict_get_*`` getter has ``ppdict_rget_*`` counterpart that dereferences +indirect objects if necessary. Note that there is no ``ppdict_get_stream()`` function, +but there is:: + + ppstream * ppdict_rget_stream (ppdict *dict, const char *name); + +So far dicts comes with no names mapping, so by-name dict accessors perform a linear search +through the keys list. PDF dicts are usually small. + +Stream +------ + +PDF streams are represented as ``ppstream`` objects. To get the stream dict:: + + ppdict * ppstream_dict(ppstream *stream) // macro + +To read the stream data:: + + uint8_t * ppstream_first (ppstream *stream, size_t *size, int decode); + uint8_t * ppstream_next (ppstream *stream, size_t *size); + void ppstream_done (ppstream *stream); + +Both ``first` and ``next`` functions return a chunk of stream data and sets the ``size`` of the chunk. +``decode`` parameter tell the reader to decompress the stream (1) or return raw (0). A call to ``ppstream_next()`` +must be preceeded by ``ppstream_first()``. Once you're done with the stream, you have to call ``ppstream_done()``, +no matter if the stream has been read to the end or not. The stream data iterator in use:: + + uint8_t *data; + size_t size; + ppstream *stream; + int decode = 1; // 1 - get decompressed, 0 - get raw + + for (data = ppstream_first(stream, &size, decode); data != NULL; data = ppstream_next(stream, &size)) + { + // do something with data and its size + } + ppstream_done(stream); + +Every subsequent iterator call invalidates the previous reader output, so you have to utilize the returned chunk +of data just after you ot that. So the following is wrong:: + + data1 = ppstream_first(stream, &size, 1); + data2 = ppstream_next(stream, &size); + data3 = ppstream_next(stream, &size); + some_output(data1, size); + some_output(data2, size); + +The reader calls usually return the same pointer to internal buffer, just filled with a different data. +``pplib`` allocates reasonably large buffer and fills that buffer on subsequent calls to the reader. + +If the source stream has no compression, using both ``decode == 1`` and ``decode == 0`` should give the same result. +You can check if the stream is actually compressed with:: + + ppstream_compressed(stream) // macro, returns non zero if /Filter is present + +It might be necessary to load the entire stream data at once:: + + uint8_t * ppstream_all (ppstream *stream, size_t *size, int decode); + +If the initial buffer size is insufficient, it grows until the entire stream data is loaded. You must call +``ppstream_done(stream)`` after using returned data. + +``ppstream_done()`` doesn't invalidate the stream object, it just closes its internal reader. +The stream itself remains a valid object (eg. one can read it again if necessary), +but the reader buffer is released. It is actually not freed but kept for future the reuse with that on some other stream, +but you still need to mark it ready for reuse to avoid allocating a separate buffer for every stream you're going to read. + +Stream data readers will return ``NULL`` if you haven't close the previous reader process with ``ppstream_done()``. All below is wrong:: + + data1 = ppstream_all(stream, &size, 1); + data2 = ppstream_all(stream, &size, 1); // data2 == NULL + // or + data1 = ppstream_first(stream, &size, 1); + data2 = ppstream_first(stream, &size, 1); // data2 == NULL + // or + data1 = ppstream_first(stream, &size, 1); + data2 = ppstream_all(stream, &size, 1); // data2 == NULL + +To avoid unnecessary dependencies, ``pplib`` does not support image filters (``/DCT``, ``/JPX``, ``/JBIG``, ``/CCITT``). +But it is ok to read the stream with ``decode`` set to 1 on such streams. ``pplib`` assumes that the image is the +final/target stream form and just returns it as-is. Eg. in the case of JPEG (``/DCT`` filtered) image both calls should +give the same results:: + + ppstream_all(jpegstream, &jpegsize, 0); // don't decode, return what's there + ppstream_all(jpegstream, &jpegsize, 1); // decode but found image filter, effectively the same + +A bit more about streams memory. As mentioned, ``pplib`` allocates buffers for stream readers. After ``ppstream_done()``, +the stream no longer *owns* the buffer space. But the buffer may remain allocated, to be reused with future readers. +``pplib`` keeps a pool of several buffers. This means, that when you use stream readers, ``pplib`` eats +some memory (1MB or so) that is not freed, even if no streams are used. And even if you free all objects. +If you suffer from this, you can optionally use a pair of functions:: + + void ppstream_init_buffers (void); + void ppstream_free_buffers (void); + +The first initializes buffers pool, unless done so far. Currently ``pplib`` cares of it before opening every stream reader, +so it is not obligatory. The second frees a pool of buffers. The intended use is to call ``ppstream_init_buffers()`` once +as kind of library initializer and to call ``ppstream_free_buffers()`` once, as the library finalizer. + +Filters +------- + +``ppstream`` knows its filter(s) and keps it as ``stream->filter``:: + + // ppstream *stream; + ppstream_filter *info = &stream->filter; + +``ppstream_filter`` is the following structure:: + + typedef struct { + ppstreamtp *filters; // c-array of filter identifiers (enum integers) + ppdict **params; // c-array of ppdict pointers + size_t count; // number of filters, length of the arrays (typically 1) + } ppstream_filter; + +If ``count > 0`` then ``filters`` member is not NULL. Filters array keeps integer constants:: + + PPSTREAM_BASE16 /* /ASCIIHexDecode */ + PPSTREAM_BASE85 /* /ASCII85Decode */ + PPSTREAM_RUNLENGTH /* /RunLengthDecode */ + PPSTREAM_FLATE /* /FlateDecode */ + PPSTREAM_LZW /* /LZWDecode */ + PPSTREAM_CCITT /* /CCITTFaxDecode */ + PPSTREAM_DCT /* /DCTDecode */ + PPSTREAM_JBIG2 /* /JBIG2Decode */ + PPSTREAM_JPX /* /JPXDecode */ + PPSTREAM_CRYPT /* /Crypt */ + +Params array keeps corresponding filter parameters (``/DecodeParms``) if present. ``params`` member is not NULL +if ``count > 0`` and the stream dict has ``/DecodeParms`` entry. Even if ``params`` is there, +for every N-th filter, ``params[N]`` may be NULL (corresponding to PDF ``null``). + +``stream->filter`` keeps the source stream filter information, which may not correspond to the result of stream readers +(``ppstream_first()``, ``ppstream_next()``, ``ppstream_all()``). The get the filters info relevant to the result from readers:: + + void ppstream_filter_info (ppstream *stream, ppstream_filter *info, int decode); + +The function fills ``ppstream_filter`` structure according to the expected result from stream readers (example 3 shows +how to use it to reconstruct ``/Filter`` and ``/DecodeParms`` when copying the stream to some other PDF). + +To convert filter identifier (``ppstreamtp``) to a corresponding PDF filter name:: + + const char * ppstream_filter_name[]; + +To covert ``ppname`` to filter identifier:: + + int ppstream_filter_type (ppname filtername, ppstreamtp *filtertype); + // returns 1 and sets filtertype if filtername is the proper filter name + +Additional information about the stream can be fetched from macros:: + + ppstream_compressed(stream) /* stream->flags & (PPSTREAM_FILTER|PPSTREAM_IMAGE) */ + ppstream_filtered(stream) /* stream->flags & PPSTREAM_FILTER */ + ppstream_image(stream) /* stream->flags * PPSTREAM_IMAGE */ + +``stream->flags`` is a binary sum of the following:: + + PPSTREAM_FILTER /* set iff the stream filters list has one of: BASE16, BASE85, RUNLENGTH, FLATE, LZW */ + PPSTREAM_IMAGE /* set iff the stream filters list has one of: CCITT, DCT, JBIG2, JPX */ + PPSTREAM_ENCRYPTED /* set iff the stream is encrypted */ + PPSTREAM_ENCRYPTED_OWN /* set iff the stream has own CRYPT filter */ + +Note that ``PPSTREAM_COMPRESSED`` is not there any longer, use ``ppstream_compressed()`` instead. +And there is some more, see ``ppapi.h``. + +Ref +--- + +Indirect objects are represented as ``ppref`` structure. To get the object that the +reference refers to:: + + ppobj * ppref_obj(ppref *ref) // macro + +``ppref`` structure also keeps the reference number and version, a pointer to cross reference table it belongs +to and others, but I guess you won't need anything but the referenced object. ``pplib`` parser resolves references +on-fly. So if there is a dict with indirect objects:: + + << + /Type /Page + /Resources 123 0 R + ... + >> + +the parser will produce ``ppdict`` with ``Resources`` key pointing the proper ``ppref *`` value. +If you need more, access ``ppref`` members:: + + struct ppref { + ppobj object; // target object + ppuint number, version; // identifiers + size_t offset; // file offset (useless for you, may be zero for compressed objects) + ppuint length; // the length of the original object data + ppxref *xref; // cross reference table it belongs to + }; + + +XRef +---- + +Cross reference table is exposed as ``ppxref`` (incomplete type, you can only oprate on its pointer). +To get top document xref:: + + ppxref * ppdoc_xref (ppdoc *pdf); + +To get previous (older) xref:: + + ppxref * ppxref_prev (ppxref *xref); + +To find an object of a given refnumber:: + + ppref * ppxref_find (ppxref *xref, ppuint refnumber); + +[Note: since pplib v0.98 in case of documents with incremental update, ``ppxref_find()`` returns +the newest available version of a given object rather than the object in a given body.] + +PDF +--- + +PDF document is represented as ``ppdoc`` structure (incomplete type, you can only operate on its pointer). +To load a document from file:: + + ppdoc * ppdoc_load (const char *filename); + +To load a document from file handle:: + + ppdoc * ppdoc_filehandle (FILE *file, int closefile); // closefile 1 to fclose() on end + +To load a document from memory data:: + + ppdoc * ppdoc_mem (const void *data, size_t size); + +The data is assumed to be a buffer allocated with ``malloc`` - it is freed when destroying ``ppdoc``. + +Both loaders returns ``NULL`` on failure. + +To free ``ppdoc`` and all objects it refers to:: + + void ppdoc_free (ppdoc *pdf); + +So far we haven't mention about any explicit object reclaimers. There are no dedicated ``free`` functions +for other objects. You don't allocate or free objects yourself. ``ppdoc`` object is an owner of all +beings it refers to. It also means that every object described so far is alive as long as the containing +``ppdoc`` is alive. + +To access main PDF dicts:: + + ppdict * ppdoc_trailer(ppdoc *pdf); // returns top xref trailer dict + ppdict * ppdoc_catalog(ppdoc *pdf); // returns catalog referred from the trailer + ppdict * ppdoc_info(ppdoc *pdf); // returns info dict referred from the trailer + +To get the PDF version:: + + const char * ppdoc_version_string (ppdoc *pdf); // version string + int ppdoc_version_number (ppdoc *pdf, int *minor); // minor and major numbers + +To get the file size of the source PDF document:: + + size_t ppdoc_file_size (ppdoc *pdf); + +To get the number of objects in all xrefs:: + + ppuint ppdoc_objects (ppdoc *pdf); + +To get the approx usage of memory:: + + size_t ppdoc_memory (ppdoc *pdf, size_t *waste); + +Encryption +---------- + +``pplib`` handles encrypted (password protected) documents. If a document is encrypted, most of strings and streams are ciphered. +In that form they are unreadable and rather useless, you can't even rewrite such strings/streams as-is to a different PDF output. +It is a common practise to *protect* documents with an empty password. Such documents remain readable in Acrobat (just opens them without prompting +for a password), but some features (eg. printing) may restricted by the application. + +When ``pplib`` detects encryption, it follows Acrobat approach and first tries an empty password. If it succeeds, ``pplib`` proceeeds normally, providing +an access to decrypted strings and streams, as if they weren't ciphered. If the document is protected with non-empty password, you have to call +``ppdoc_crypt_pass()``. Until you provide a password, ``ppdoc`` object returned by ``ppdoc_load()`` function has all object entries set to ``null``. + +Once the document is loaded, encryption status can be checked with:: + + ppcrypt_status ppdoc_crypt_status (ppdoc *pdf); + +``ppcrypt_status`` (enum) may have the following values: + + ``PPCRYPT_NONE`` - no encryption, go ahead + ``PPCRYPT_DONE`` - encryption present but password succeeded, go ahead + ``PPCRYPT_PASS`` - encryption present, need non-empty password + ``PPCRYPT_FAIL`` - invalid or unsupported encryption (eg. undocumented in pdf spec) + +If a password is needed, you can provide one with:: + + ppcrypt_status ppdoc_crypt_pass (ppdoc *pdf, const void *userpass, size_t userpasslength, + const void *ownerpass, size_t ownerpasslength); + +Providing one of two is enough to decrypt the document. +It is ok to use the same password for owner and user -- ``pplib`` will try both. + +The function returns ``PPCRYPT_DONE`` if the password succeeds and the previous crypt status otherwise. + +Your custom loader function may look like that:: + + ppdoc *pdf; + pdf = ppdoc_load("file.pdf"); + if (pdf == NULL) + return NULL; + switch (ppdoc_crypt_status(pdf)) + { + case PPCRYPT_NONE: + case PPCRYPT_DONE: + return pdf; + case PPCRYPT_PASS: + if (ppdoc_crypt_pass(pdf, "dummy", 5, "dummy", 5) == PPCRYPT_DONE) + return pdf; + printf("sorry, password needed\n"); + ppdoc_free(pdf); + return NULL; + case PPCRYPT_FAIL: + printf("sorry, encryption failed\n"); + ppdoc_free(pdf); + return NULL; + } + +See ``pplib`` tests suite for a complete code. + +If you'd like to know what permissions are given/restricted to encrypted document:: + + ppint ppdoc_permissions (ppdoc *pdf); + +Returned value can be queried with the following binary flags (you can verify with Acrobat *File -> Properties -> Security* tab):: + + PPDOC_ALLOW_PRINT // printing + PPDOC_ALLOW_MODIFY // filling form fields, signing, creating template pages + PPDOC_ALLOW_COPY // copying, copying for accessibility + PPDOC_ALLOW_ANNOTS // filling form fields, copying, signing + PPDOC_ALLOW_EXTRACT // contents copying for accessibility + PPDOC_ALLOW_ASSEMBLY // (no effect) + PPDOC_ALLOW_PRINT_HIRES // (no effect) + +``pplib`` does absolutelly nothing with permissions, it cares only to decrypt the document. As mentioned, encryption applies to strings +and streams. ``pplib`` decrypt strings when parsing document objects, so the result you get is *normal* (not ciphered). +Streams are decrypted whenever you access them. Even if you ask for a raw stream data, you'll get a raw (compressed) stream, but decrypted. +So except the check to ``ppdoc_crypt_status()``, you shouldn't bother about encryption. + +In encrypted documents most of streams are encrypted. To check if a given stream is encrypted:: + + ppstream_encrypted(stream) // macro, returns non-zero if encrypted + +Encryption is independent from compression, don't confuse with ``ppstream_compressed()`` + +.. caution:: + Starting from ``pplib v2.10`` all passwords should be passed as ``UTF-8``. + Earlier PDF encryption algorithms (/V 1..4, PDF 1.7) were based on ``PdfDocEncoding``. + Newer algorithms (/V 5, PDF 1.8-2.0) expect Unicode encoded as ``UTF-8``. + ``pplib`` API now expects ``UTF-8`` and if opening documents with older encryption methods, + it tries to make a conversion to 8-bit encoding. In earlier versions ``pplib`` didn't + make any password preprocessing, treating them as raw byte arrays. + So in case of passwords with fancy characters, it may behave differently. + +Pages +----- + +Several helpers to deal with pages. To get the number of pages:: + + ppuint ppdoc_page_count (ppdoc *pdf); + +To access the root pages tree node:: + + ppref * ppdoc_pages(ppdoc *pdf); + +To get the page reference at a given index:: + + ppref * ppdoc_page (ppdoc *pdf, ppuint index); + +``index`` is a page number. First page has number 1. For index out of bounds ``ppdoc_page()`` returns NULL. +Iterating over pages using index from 1 to ``ppdoc_page_count()`` and calling ``ppdoc_page()`` on each iteration +would be suboptimal. Here is a dedicted iterator for this:: + + ppref * ppdoc_first_page (ppdoc *pdf); + ppref * ppdoc_next_page (ppdoc *pdf); + +The iterator in use:: + + ppdoc *pdf; + ppref *ref; + ppdict *dict; + int pageno; + + pdf = ppdoc_load("file.pdf"); + for (ref = ppdoc_first_page(pdf), pageno = 1; ref != NULL; ref = ppdoc_next_page(pdf), ++pageno) + { + dict = ppref_obj(obj)->dict; // take for granted it is a dict + // do something with the page dict + } + +Functions related to pages return ``ppref *`` ensured to contain dict object, so you don't need sanity +type checks here. + +Contents +-------- + +PDF page contents can be given as a stream or array of streams. Here is a convenience iterator over page +contents streams:: + + ppstream * ppcontents_first (ppdict *dict); + ppstream * ppcontents_next (ppdict *dict, ppstream *stream); + +A complete example of contents stream parser use is given below (example 2). +But before we get there, we need to introduce ``ppcontext`` object. Conceptually, +``ppcontext`` is an owner (memory handler) of objects created on demand (beyond the ``ppdoc``). +So far used only with contents stream parser, which might produce quite some data that we want +to release just after used. To create a new context:: + + pcontext * ppcontext_new (void); + +It initializes a new context and its internal memory heap, taking about 64kB on start. After that, +the context is ready to produce objects (contents parsing functions below). Once objects produced +from a given context are no longer needed:: + + void ppcontext_done (ppcontext *context); + +It restores the context to its initial state, as after ``ppcontext_new()``. It means that the context +is ready to produce another bunch of beings (in the example below, all objects from the next page contents). +Once the context is not needed anymore:: + + void ppcontext_free (ppcontext *context); + +Now, contents stream parser functions take the context as an argument. Iterator form of contents stream parser +that allows to process the contents operator by operator:: + + ppobj * ppcontents_first_op (ppcontext *context, ppstream *stream, size_t *psize, ppname *pname); + ppobj * ppcontents_next_op (ppcontext *context, ppstream *stream, size_t *psize, ppname *pname); + +Returned ``ppobj *`` is a pointer to operands list. ``*psize`` is the number of operands on stack. +The operator itself is stored as ``*pname``. + +To parse the entire contents stream at once with no stop at every operator:: + + ppobj * ppcontents_parse (ppcontext *context, ppstream *stream, size_t *psize); + +Returns probably quite long list of all parsed objects (operands and operatos) in one piece. +The number of objects is stored to ``*psize``. + +[Contents may contain so called inline images, that breaks a simple scheme of operands / operator syntax:: + + BI <keyval pairs> ID <binary image data> EI + +Contents parser treats this genuine triplet as a single piece, producing two operands (dict and string) +followed by ``EI`` operator name.] + +Boxes +----- + +Boxes (rectangles) in PDF are roughly 4-number arrays, but with a special intent. +``pplib`` provides a basic interface for these special arrays:: + + typedef struct { + ppnum lx, ly, rx, ry; + } pprect; + +This type is used only by helper functions - PDF parser is not aware of the rectangle type. +To convert ``pparray`` to ``pprect``:: + + pprect * pparray_to_rect (pparray *array, pprect *rect); // returns rect or NULL + +In example:: + + pprect rect; + if (pparray_to_rect(array, &rect) != NULL) + ; // do something with rect + +To get some image bounding box:: + + pprect * ppdict_get_rect (ppdict *dict, const char *name, pprect *rect); + // eg. ppdict_get_rect(imagedict, "BBox", &rect) + +To get some page box:: + + pprect * ppdict_get_box (ppdict *dict, const char *name, pprect *rect); + // eg. ppdict_get_box(pagedict, "MediaBox", &rect) + +The later not only checks the pagedict, but also goes through parent page nodes. + +Transforms +---------- + +Transformations are given as 6-number arrays, but with a special intent. +``pplib`` provides a basic interface for these special arrays:: + + typedef struct { + ppnum xx, xy, yx, yy, x, y; + } ppmatrix; + +This type is used only by helper functions - PDF parser is not aware of the matrix type. +To convert ``pparray`` to ``ppmatrix``:: + + ppmatrix * pparray_to_matrix (pparray *array, ppmatrix *matrix); + +In example:: + + ppmatrix matrix; + if (pparray_to_matrix(array, &matrix) != NULL) + ; // do something with matrix + +To get the matrix from dict:: + + ppmatrix * ppdict_get_matrix (ppdict *dict, const char *name, ppmatrix *matrix); + // eg. ppdict_get_matrix(imagedict, "Matrix", &matrix) + +Errors handling +--------------- + +``pplib`` is not verbose, but might happen that it needs to log some error message, eg. when parsing +of some PDF boject fails due to invalid offsets. By default, ``pplib`` prints the message to stdout, eg.:: + + invalid 123 0 R object at offset 123123 + +To replace the default logger, you can provide your own:: + + void pplog_callback (pplogger_callback logger, void *alien); + +``pplogger_callback`` is a function:: + + void your_callback (const char *message, void *alien); + +In example, to redirect messages to stderr you may define a function:: + + void your_callback (const char *message, void *alien) + { + fprintf((FILE *)alien, "\nooops: %s\n", message); + } + +Then set the callback somewhere before loading documents:: + + pplog_callback(your_callback, stderr); + +(example 2 uses that). + +To set the default log messages prefix, eg. ``pplib:``, use:: + + int pplog_prefix (const char *prefix) + +Default is empty. The function succeeds if provided prefix is reasonably short (less then 32 bytes). diff --git a/Build/source/libs/pplib/pplib-src/doc/_build/html/_sources/ppcode.rst.txt b/Build/source/libs/pplib/pplib-src/doc/_build/html/_sources/ppcode.rst.txt index e9f6dc7adbd..37a062e94be 100644 --- a/Build/source/libs/pplib/pplib-src/doc/_build/html/_sources/ppcode.rst.txt +++ b/Build/source/libs/pplib/pplib-src/doc/_build/html/_sources/ppcode.rst.txt @@ -1,101 +1,101 @@ -Examples
-========
-
-Example 1
----------
-
-.. literalinclude:: ../src/pptest1.c
-
-Example 2
----------
-
-.. literalinclude:: ../src/pptest2.c
-
-Example 3
----------
-
-.. literalinclude:: ../src/pptest3.c
-
-ppapi.h
--------
-
-.. literalinclude:: ../src/ppapi.h
-
-
-Changes
-=======
-
-v0.97
------
-First release integrated with luatex sources, plus portability changes from Luigi.
-
-v0.98
------
-Changed references resolving in case of incremental updates; tech notes ppxref_find() in ppxref.c.
-
-v0.99
------
-Fixed streams handling; null characters should NOT be gobbled after "stream" keyword
-
-v1.00
------
-Fixed streams handling (Luigi); object streams updated before other streams
-Revised streams handling, ppstream API extended
-
-v1.01
------
-Fixed names handling (thanks Hans); digits after '#' weren't skipped
-
-v1.02
------
-Fixed page finder (thanks Luigi)
-
-v1.03
------
-Fixed TIFF predictor (thanks folks)
-
-v1.04
------
-Fixed TIFF predictor for ARM
-
-v1.05
------
-Attempt to fix parsing inline images crap
-
-v2.00
------
-Deep rework on allocators.
-Deep rework on strings and names.
-
-v2.01
------
-Fixed invalid stream buffer handling; ``iof_discard()`` no longer reclaims the source (``filter->next``) filter.
-Sanity alignment adjustments in ``iof_heap``.
-
-v2.02
------
-Fixed incorrect encoding of strings alterego with octal escaping, thanks Luigi.
-On Hans request added ``ppdoc_filehandle()`` function and ``ppdoc_file()`` macro for loading ppdoc from ``FILE *``.
-
-v2.03
------
-Fixed alloc/free of ``ppdoc`` heap; ``ppdoc`` is now mallocated, no longer taken from its own heap. Again, thanks Luigi.
-Fixed warnings about dereferencing type-puned pointers, and some others.
-
-v2.04
------
-Byte lookups for names/strings loaders are now int8_t, as char might be signed.
-ppdoc_first_page() / ppdoc_next_page() iterator now handles a case when /Kids array is empty.
-Fixed generating keys for encrypted streams; ppstring_internal() returns the string of the proper size.
-More stream tests in pptest3.c.
-Some rework on md5 and sha2.
-
-v2.05
------
-uint8_t instead of ppbyte in internals; ppbyte intent is "the most natural 8-bit integer", so it is 'char',
-but internally we almost always need uint8_t (char may be signed or not..)
-
-v2.10
------
-Rework on encryption; algorithms /V5 /R6.
-Passwords passed to ppdoc_crypt_pass() should be UTF-8 (backward incompatible).
+Examples +======== + +Example 1 +--------- + +.. literalinclude:: ../src/pptest1.c + +Example 2 +--------- + +.. literalinclude:: ../src/pptest2.c + +Example 3 +--------- + +.. literalinclude:: ../src/pptest3.c + +ppapi.h +------- + +.. literalinclude:: ../src/ppapi.h + + +Changes +======= + +v0.97 +----- +First release integrated with luatex sources, plus portability changes from Luigi. + +v0.98 +----- +Changed references resolving in case of incremental updates; tech notes ppxref_find() in ppxref.c. + +v0.99 +----- +Fixed streams handling; null characters should NOT be gobbled after "stream" keyword + +v1.00 +----- +Fixed streams handling (Luigi); object streams updated before other streams +Revised streams handling, ppstream API extended + +v1.01 +----- +Fixed names handling (thanks Hans); digits after '#' weren't skipped + +v1.02 +----- +Fixed page finder (thanks Luigi) + +v1.03 +----- +Fixed TIFF predictor (thanks folks) + +v1.04 +----- +Fixed TIFF predictor for ARM + +v1.05 +----- +Attempt to fix parsing inline images crap + +v2.00 +----- +Deep rework on allocators. +Deep rework on strings and names. + +v2.01 +----- +Fixed invalid stream buffer handling; ``iof_discard()`` no longer reclaims the source (``filter->next``) filter. +Sanity alignment adjustments in ``iof_heap``. + +v2.02 +----- +Fixed incorrect encoding of strings alterego with octal escaping, thanks Luigi. +On Hans request added ``ppdoc_filehandle()`` function and ``ppdoc_file()`` macro for loading ppdoc from ``FILE *``. + +v2.03 +----- +Fixed alloc/free of ``ppdoc`` heap; ``ppdoc`` is now mallocated, no longer taken from its own heap. Again, thanks Luigi. +Fixed warnings about dereferencing type-puned pointers, and some others. + +v2.04 +----- +Byte lookups for names/strings loaders are now int8_t, as char might be signed. +ppdoc_first_page() / ppdoc_next_page() iterator now handles a case when /Kids array is empty. +Fixed generating keys for encrypted streams; ppstring_internal() returns the string of the proper size. +More stream tests in pptest3.c. +Some rework on md5 and sha2. + +v2.05 +----- +uint8_t instead of ppbyte in internals; ppbyte intent is "the most natural 8-bit integer", so it is 'char', +but internally we almost always need uint8_t (char may be signed or not..) + +v2.10 +----- +Rework on encryption; algorithms /V5 /R6. +Passwords passed to ppdoc_crypt_pass() should be UTF-8 (backward incompatible). diff --git a/Build/source/libs/pplib/pplib-src/doc/_build/html/_sources/pplib.rst.txt b/Build/source/libs/pplib/pplib-src/doc/_build/html/_sources/pplib.rst.txt index 763dc79cf62..b1eb82a1ebd 100644 --- a/Build/source/libs/pplib/pplib-src/doc/_build/html/_sources/pplib.rst.txt +++ b/Build/source/libs/pplib/pplib-src/doc/_build/html/_sources/pplib.rst.txt @@ -1,15 +1,15 @@ -.. pplib documentation master file, created by
- sphinx-quickstart on Thu Jun 07 14:23:51 2018.
- You can adapt this file completely to your liking, but it should at least
- contain the root `toctree` directive.
-
-pplib
-=====
-
-.. toctree::
- :maxdepth: 2
-
- ppnew
- ppapi-2.x
- ppapi-1.x
- ppcode
+.. pplib documentation master file, created by + sphinx-quickstart on Thu Jun 07 14:23:51 2018. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +pplib +===== + +.. toctree:: + :maxdepth: 2 + + ppnew + ppapi-2.x + ppapi-1.x + ppcode diff --git a/Build/source/libs/pplib/pplib-src/doc/_build/html/_sources/ppnew.rst.txt b/Build/source/libs/pplib/pplib-src/doc/_build/html/_sources/ppnew.rst.txt index 4a0a3b42887..b72d46bdac5 100644 --- a/Build/source/libs/pplib/pplib-src/doc/_build/html/_sources/ppnew.rst.txt +++ b/Build/source/libs/pplib/pplib-src/doc/_build/html/_sources/ppnew.rst.txt @@ -1,103 +1,103 @@ -
-1.x vs 2.x
-==========
-
-Allocation
-----------
-
-Allocation mechanisms has been revised. All objects are still allocated from a private storage (called heap),
-but now the heap serves properly aligned memory chunks. Implementation of the heap is (hopefully) platform
-independent, so all ``ARM_COMPLIANT`` checks has been removed. Some details work differently on 32/64-bit
-machines, this distinction seems inevitable. Allocation related code has been moved to ``util/utilmem*.c`` files.
-
-[There are actually 3 different allocators - **heap**, **stock**, and **pool** - each of which has 4 variants
-for 1, 2, 4 and 8 bytes alignment. So far ``pplib`` uses only the **heap**, but I want to have this part
-in a single place for a while. More notes about allocators in ``utilmemallc.h``.]
-
-``pplib`` uses two heaps:
-
-* bytes heap - providing 2-bytes aligned memory chunks for byte data
-* structures heap - providing 8-bytes aligned chunks for all structures
-
-2-bytes alignment of byte data is caused by implementation details / limits, ``pplib`` doesn't make a use of it
-(could be unaligned as well). All the structures are stored in 8-bytes aligned chunks on both 32 and 64-bit machines
-(in some structures we use ``double`` and ``int64_t``, which generally needs 8-bytes).
-
-Strings And Names
------------------
-
-So far, both ``ppname`` and ``ppstring`` were aliases to ``char *`` with an extra structure hidden just below
-the data address. The idea was to make a string or name usable whenever chars array can, at the cost of some
-pointers trickery. Both names and strings keep an information about pdf-encoded data, as well as plain bytes data.
-I implemented this feature once ``pplib 1.0`` was almost done, and to avoid a revolution, I made that with yet
-another trick. This all was dirty and caused lots of alignment issues.
-
-Now ``ppstring`` and ``ppname`` are **structures**, keeping data and size members, pretty much like ``pparray``::
-
- struct ppname {
- ppbyte *data;
- size_t size;
- ppname *alterego;
- int flags;
- };
-
- struct ppstring {
- ppbyte *data;
- size_t size;
- ppstring *alterego;
- int flags;
- };
-
-Data member is a pointer to (2-bytes aligned) bytes array -- ``ppbyte *``. ``ppbyte`` is an alias to ``char``.
-``pplib`` makes no assumptions about ``ppbyte`` signedness. [I'd prefer to have ``uint8_t``, but better
-keep that in sync with ``ppdict_get_*`` suite, which accepts ``char *``. Using ``"string literals"``
-with ``ppdict_get`` function is the most common case, I guess.]
-
-``ppname_size()`` and ``ppstring_size() `` now have
-trivial ``ppname_data()`` and ``ppstring_data()`` counterparts::
-
- #define ppname_size(name) ((name)->size)
- #define ppname_data(name) ((name)->data)
-
- #define ppstring_size(string) ((string)->size)
- #define ppstring_data(string) ((string)->data)
-
-Switching between encoded / decoded variants is made via explicit ``alterego`` member. If encoded and decoded forms
-are identical, then ``self->alfterego == self`` (never NULL). Helper functions for that::
-
- PPAPI ppname * ppname_decoded (ppname *name);
- PPAPI ppname * ppname_encoded (ppname *name);
-
- PPAPI ppbyte * ppname_decoded_data (ppname *name);
- PPAPI ppbyte * ppname_encoded_data (ppname *name);
-
- PPAPI ppstring * ppstring_decoded (ppstring *string);
- PPAPI ppstring * ppstring_encoded (ppstring *string);
-
- PPAPI ppbyte * ppstring_decoded_data (ppstring *string);
- PPAPI ppbyte * ppstring_encoded_data (ppstring *string);
-
-Since ``ppname`` and ``ppstring`` are now structures, all API functions returning name/string or taking name/string
-as an argument, now take **a pointer to name/string**. Watch out for ``ppdict_get_*`` functions suite. They still accept
-``const char *`` key as an argument, but ``ppname`` type can no longer be used there::
-
- ppname key;
- ppdict_get_something(dict, key); // wrong
- ppdict_get_something(dict, key.data); // ok
-
- ppname *pkey;
- ppdict_get_something(dict, (const char *)pkey); // wrong
- ppdict_get_something(dict, pkey->data); // ok
-
-Consequently, functions / macros that used pointer to ``ppname`` (``ppdict_first()`` / ``ppdict_next()``),
-now needs ``ppname **pname``.
-
-Cleanups
---------
-
-Some of unused utils were removed. There is still some code in utils part that is not used by the library,
-but I need this tollbox in many other places and don't want to maintain two versions.
-
-Some unification in integer types; ``size_t`` seems to be the best choice for and integer representing machine
-word (``unsigned long`` is not long enough on windows), less utils dependencies, less compiler warnings.
-
+ +1.x vs 2.x +========== + +Allocation +---------- + +Allocation mechanisms has been revised. All objects are still allocated from a private storage (called heap), +but now the heap serves properly aligned memory chunks. Implementation of the heap is (hopefully) platform +independent, so all ``ARM_COMPLIANT`` checks has been removed. Some details work differently on 32/64-bit +machines, this distinction seems inevitable. Allocation related code has been moved to ``util/utilmem*.c`` files. + +[There are actually 3 different allocators - **heap**, **stock**, and **pool** - each of which has 4 variants +for 1, 2, 4 and 8 bytes alignment. So far ``pplib`` uses only the **heap**, but I want to have this part +in a single place for a while. More notes about allocators in ``utilmemallc.h``.] + +``pplib`` uses two heaps: + +* bytes heap - providing 2-bytes aligned memory chunks for byte data +* structures heap - providing 8-bytes aligned chunks for all structures + +2-bytes alignment of byte data is caused by implementation details / limits, ``pplib`` doesn't make a use of it +(could be unaligned as well). All the structures are stored in 8-bytes aligned chunks on both 32 and 64-bit machines +(in some structures we use ``double`` and ``int64_t``, which generally needs 8-bytes). + +Strings And Names +----------------- + +So far, both ``ppname`` and ``ppstring`` were aliases to ``char *`` with an extra structure hidden just below +the data address. The idea was to make a string or name usable whenever chars array can, at the cost of some +pointers trickery. Both names and strings keep an information about pdf-encoded data, as well as plain bytes data. +I implemented this feature once ``pplib 1.0`` was almost done, and to avoid a revolution, I made that with yet +another trick. This all was dirty and caused lots of alignment issues. + +Now ``ppstring`` and ``ppname`` are **structures**, keeping data and size members, pretty much like ``pparray``:: + + struct ppname { + ppbyte *data; + size_t size; + ppname *alterego; + int flags; + }; + + struct ppstring { + ppbyte *data; + size_t size; + ppstring *alterego; + int flags; + }; + +Data member is a pointer to (2-bytes aligned) bytes array -- ``ppbyte *``. ``ppbyte`` is an alias to ``char``. +``pplib`` makes no assumptions about ``ppbyte`` signedness. [I'd prefer to have ``uint8_t``, but better +keep that in sync with ``ppdict_get_*`` suite, which accepts ``char *``. Using ``"string literals"`` +with ``ppdict_get`` function is the most common case, I guess.] + +``ppname_size()`` and ``ppstring_size() `` now have +trivial ``ppname_data()`` and ``ppstring_data()`` counterparts:: + + #define ppname_size(name) ((name)->size) + #define ppname_data(name) ((name)->data) + + #define ppstring_size(string) ((string)->size) + #define ppstring_data(string) ((string)->data) + +Switching between encoded / decoded variants is made via explicit ``alterego`` member. If encoded and decoded forms +are identical, then ``self->alfterego == self`` (never NULL). Helper functions for that:: + + PPAPI ppname * ppname_decoded (ppname *name); + PPAPI ppname * ppname_encoded (ppname *name); + + PPAPI ppbyte * ppname_decoded_data (ppname *name); + PPAPI ppbyte * ppname_encoded_data (ppname *name); + + PPAPI ppstring * ppstring_decoded (ppstring *string); + PPAPI ppstring * ppstring_encoded (ppstring *string); + + PPAPI ppbyte * ppstring_decoded_data (ppstring *string); + PPAPI ppbyte * ppstring_encoded_data (ppstring *string); + +Since ``ppname`` and ``ppstring`` are now structures, all API functions returning name/string or taking name/string +as an argument, now take **a pointer to name/string**. Watch out for ``ppdict_get_*`` functions suite. They still accept +``const char *`` key as an argument, but ``ppname`` type can no longer be used there:: + + ppname key; + ppdict_get_something(dict, key); // wrong + ppdict_get_something(dict, key.data); // ok + + ppname *pkey; + ppdict_get_something(dict, (const char *)pkey); // wrong + ppdict_get_something(dict, pkey->data); // ok + +Consequently, functions / macros that used pointer to ``ppname`` (``ppdict_first()`` / ``ppdict_next()``), +now needs ``ppname **pname``. + +Cleanups +-------- + +Some of unused utils were removed. There is still some code in utils part that is not used by the library, +but I need this tollbox in many other places and don't want to maintain two versions. + +Some unification in integer types; ``size_t`` seems to be the best choice for and integer representing machine +word (``unsigned long`` is not long enough on windows), less utils dependencies, less compiler warnings. + diff --git a/Build/source/libs/pplib/pplib-src/doc/_build/html/_static/pygments.css b/Build/source/libs/pplib/pplib-src/doc/_build/html/_static/pygments.css index a5e279dcaea..20c4814dcf0 100644 --- a/Build/source/libs/pplib/pplib-src/doc/_build/html/_static/pygments.css +++ b/Build/source/libs/pplib/pplib-src/doc/_build/html/_static/pygments.css @@ -1,69 +1,69 @@ -.highlight .hll { background-color: #ffffcc }
-.highlight { background: #eeffcc; }
-.highlight .c { color: #408090; font-style: italic } /* Comment */
-.highlight .err { border: 1px solid #FF0000 } /* Error */
-.highlight .k { color: #007020; font-weight: bold } /* Keyword */
-.highlight .o { color: #666666 } /* Operator */
-.highlight .ch { color: #408090; font-style: italic } /* Comment.Hashbang */
-.highlight .cm { color: #408090; font-style: italic } /* Comment.Multiline */
-.highlight .cp { color: #007020 } /* Comment.Preproc */
-.highlight .cpf { color: #408090; font-style: italic } /* Comment.PreprocFile */
-.highlight .c1 { color: #408090; font-style: italic } /* Comment.Single */
-.highlight .cs { color: #408090; background-color: #fff0f0 } /* Comment.Special */
-.highlight .gd { color: #A00000 } /* Generic.Deleted */
-.highlight .ge { font-style: italic } /* Generic.Emph */
-.highlight .gr { color: #FF0000 } /* Generic.Error */
-.highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */
-.highlight .gi { color: #00A000 } /* Generic.Inserted */
-.highlight .go { color: #333333 } /* Generic.Output */
-.highlight .gp { color: #c65d09; font-weight: bold } /* Generic.Prompt */
-.highlight .gs { font-weight: bold } /* Generic.Strong */
-.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
-.highlight .gt { color: #0044DD } /* Generic.Traceback */
-.highlight .kc { color: #007020; font-weight: bold } /* Keyword.Constant */
-.highlight .kd { color: #007020; font-weight: bold } /* Keyword.Declaration */
-.highlight .kn { color: #007020; font-weight: bold } /* Keyword.Namespace */
-.highlight .kp { color: #007020 } /* Keyword.Pseudo */
-.highlight .kr { color: #007020; font-weight: bold } /* Keyword.Reserved */
-.highlight .kt { color: #902000 } /* Keyword.Type */
-.highlight .m { color: #208050 } /* Literal.Number */
-.highlight .s { color: #4070a0 } /* Literal.String */
-.highlight .na { color: #4070a0 } /* Name.Attribute */
-.highlight .nb { color: #007020 } /* Name.Builtin */
-.highlight .nc { color: #0e84b5; font-weight: bold } /* Name.Class */
-.highlight .no { color: #60add5 } /* Name.Constant */
-.highlight .nd { color: #555555; font-weight: bold } /* Name.Decorator */
-.highlight .ni { color: #d55537; font-weight: bold } /* Name.Entity */
-.highlight .ne { color: #007020 } /* Name.Exception */
-.highlight .nf { color: #06287e } /* Name.Function */
-.highlight .nl { color: #002070; font-weight: bold } /* Name.Label */
-.highlight .nn { color: #0e84b5; font-weight: bold } /* Name.Namespace */
-.highlight .nt { color: #062873; font-weight: bold } /* Name.Tag */
-.highlight .nv { color: #bb60d5 } /* Name.Variable */
-.highlight .ow { color: #007020; font-weight: bold } /* Operator.Word */
-.highlight .w { color: #bbbbbb } /* Text.Whitespace */
-.highlight .mb { color: #208050 } /* Literal.Number.Bin */
-.highlight .mf { color: #208050 } /* Literal.Number.Float */
-.highlight .mh { color: #208050 } /* Literal.Number.Hex */
-.highlight .mi { color: #208050 } /* Literal.Number.Integer */
-.highlight .mo { color: #208050 } /* Literal.Number.Oct */
-.highlight .sa { color: #4070a0 } /* Literal.String.Affix */
-.highlight .sb { color: #4070a0 } /* Literal.String.Backtick */
-.highlight .sc { color: #4070a0 } /* Literal.String.Char */
-.highlight .dl { color: #4070a0 } /* Literal.String.Delimiter */
-.highlight .sd { color: #4070a0; font-style: italic } /* Literal.String.Doc */
-.highlight .s2 { color: #4070a0 } /* Literal.String.Double */
-.highlight .se { color: #4070a0; font-weight: bold } /* Literal.String.Escape */
-.highlight .sh { color: #4070a0 } /* Literal.String.Heredoc */
-.highlight .si { color: #70a0d0; font-style: italic } /* Literal.String.Interpol */
-.highlight .sx { color: #c65d09 } /* Literal.String.Other */
-.highlight .sr { color: #235388 } /* Literal.String.Regex */
-.highlight .s1 { color: #4070a0 } /* Literal.String.Single */
-.highlight .ss { color: #517918 } /* Literal.String.Symbol */
-.highlight .bp { color: #007020 } /* Name.Builtin.Pseudo */
-.highlight .fm { color: #06287e } /* Name.Function.Magic */
-.highlight .vc { color: #bb60d5 } /* Name.Variable.Class */
-.highlight .vg { color: #bb60d5 } /* Name.Variable.Global */
-.highlight .vi { color: #bb60d5 } /* Name.Variable.Instance */
-.highlight .vm { color: #bb60d5 } /* Name.Variable.Magic */
+.highlight .hll { background-color: #ffffcc } +.highlight { background: #eeffcc; } +.highlight .c { color: #408090; font-style: italic } /* Comment */ +.highlight .err { border: 1px solid #FF0000 } /* Error */ +.highlight .k { color: #007020; font-weight: bold } /* Keyword */ +.highlight .o { color: #666666 } /* Operator */ +.highlight .ch { color: #408090; font-style: italic } /* Comment.Hashbang */ +.highlight .cm { color: #408090; font-style: italic } /* Comment.Multiline */ +.highlight .cp { color: #007020 } /* Comment.Preproc */ +.highlight .cpf { color: #408090; font-style: italic } /* Comment.PreprocFile */ +.highlight .c1 { color: #408090; font-style: italic } /* Comment.Single */ +.highlight .cs { color: #408090; background-color: #fff0f0 } /* Comment.Special */ +.highlight .gd { color: #A00000 } /* Generic.Deleted */ +.highlight .ge { font-style: italic } /* Generic.Emph */ +.highlight .gr { color: #FF0000 } /* Generic.Error */ +.highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */ +.highlight .gi { color: #00A000 } /* Generic.Inserted */ +.highlight .go { color: #333333 } /* Generic.Output */ +.highlight .gp { color: #c65d09; font-weight: bold } /* Generic.Prompt */ +.highlight .gs { font-weight: bold } /* Generic.Strong */ +.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ +.highlight .gt { color: #0044DD } /* Generic.Traceback */ +.highlight .kc { color: #007020; font-weight: bold } /* Keyword.Constant */ +.highlight .kd { color: #007020; font-weight: bold } /* Keyword.Declaration */ +.highlight .kn { color: #007020; font-weight: bold } /* Keyword.Namespace */ +.highlight .kp { color: #007020 } /* Keyword.Pseudo */ +.highlight .kr { color: #007020; font-weight: bold } /* Keyword.Reserved */ +.highlight .kt { color: #902000 } /* Keyword.Type */ +.highlight .m { color: #208050 } /* Literal.Number */ +.highlight .s { color: #4070a0 } /* Literal.String */ +.highlight .na { color: #4070a0 } /* Name.Attribute */ +.highlight .nb { color: #007020 } /* Name.Builtin */ +.highlight .nc { color: #0e84b5; font-weight: bold } /* Name.Class */ +.highlight .no { color: #60add5 } /* Name.Constant */ +.highlight .nd { color: #555555; font-weight: bold } /* Name.Decorator */ +.highlight .ni { color: #d55537; font-weight: bold } /* Name.Entity */ +.highlight .ne { color: #007020 } /* Name.Exception */ +.highlight .nf { color: #06287e } /* Name.Function */ +.highlight .nl { color: #002070; font-weight: bold } /* Name.Label */ +.highlight .nn { color: #0e84b5; font-weight: bold } /* Name.Namespace */ +.highlight .nt { color: #062873; font-weight: bold } /* Name.Tag */ +.highlight .nv { color: #bb60d5 } /* Name.Variable */ +.highlight .ow { color: #007020; font-weight: bold } /* Operator.Word */ +.highlight .w { color: #bbbbbb } /* Text.Whitespace */ +.highlight .mb { color: #208050 } /* Literal.Number.Bin */ +.highlight .mf { color: #208050 } /* Literal.Number.Float */ +.highlight .mh { color: #208050 } /* Literal.Number.Hex */ +.highlight .mi { color: #208050 } /* Literal.Number.Integer */ +.highlight .mo { color: #208050 } /* Literal.Number.Oct */ +.highlight .sa { color: #4070a0 } /* Literal.String.Affix */ +.highlight .sb { color: #4070a0 } /* Literal.String.Backtick */ +.highlight .sc { color: #4070a0 } /* Literal.String.Char */ +.highlight .dl { color: #4070a0 } /* Literal.String.Delimiter */ +.highlight .sd { color: #4070a0; font-style: italic } /* Literal.String.Doc */ +.highlight .s2 { color: #4070a0 } /* Literal.String.Double */ +.highlight .se { color: #4070a0; font-weight: bold } /* Literal.String.Escape */ +.highlight .sh { color: #4070a0 } /* Literal.String.Heredoc */ +.highlight .si { color: #70a0d0; font-style: italic } /* Literal.String.Interpol */ +.highlight .sx { color: #c65d09 } /* Literal.String.Other */ +.highlight .sr { color: #235388 } /* Literal.String.Regex */ +.highlight .s1 { color: #4070a0 } /* Literal.String.Single */ +.highlight .ss { color: #517918 } /* Literal.String.Symbol */ +.highlight .bp { color: #007020 } /* Name.Builtin.Pseudo */ +.highlight .fm { color: #06287e } /* Name.Function.Magic */ +.highlight .vc { color: #bb60d5 } /* Name.Variable.Class */ +.highlight .vg { color: #bb60d5 } /* Name.Variable.Global */ +.highlight .vi { color: #bb60d5 } /* Name.Variable.Instance */ +.highlight .vm { color: #bb60d5 } /* Name.Variable.Magic */ .highlight .il { color: #208050 } /* Literal.Number.Integer.Long */
\ No newline at end of file diff --git a/Build/source/libs/pplib/pplib-src/doc/ppapi-1.x.rst b/Build/source/libs/pplib/pplib-src/doc/ppapi-1.x.rst index df661a7b82d..000681acebe 100644 --- a/Build/source/libs/pplib/pplib-src/doc/ppapi-1.x.rst +++ b/Build/source/libs/pplib/pplib-src/doc/ppapi-1.x.rst @@ -1,937 +1,937 @@ -
-``pplib`` 1.x
-=============
-
-``pplib`` is a library for raw PDF access. It parses PDF documents and provides an interface to access document structures in C.
-
-C-API
-=====
-
-Types
------
-
-``pplib`` defines several C-types to represent PDF types:
-
-- ``ppint`` - signed integer (``int64_t``)
-- ``ppnum`` - real number (double)
-- ``ppname`` - PDF name
-- ``ppstring`` - PDF string
-- ``pparray`` - PDF array
-- ``ppdict`` - PDF dict
-- ``ppstream`` - PDF stream
-- ``ppref`` - PDF indirect reference
-- ``ppobj`` - a container of all above
-
-Among ``ppint`` and ``ppnum``, we also use ``ppuint`` - unsigned integer (machine word, alias to ``size_t``).
-
-Other API types:
-
-- ``ppdoc`` - PDF document
-- ``ppxref`` - cross-references table
-- ``ppcontext`` - ... later
-- ``pprect`` - rectangle
-- ``ppmatrix`` - matrix
-
-Integer, number, name and string are treated as simple types.
-Names and strings are actually C-structures, but exposed to API as typedefs to ``const char *``.
-Other types (array, dict, stream, reference, object container, xref, PDF) are C-structures,
-and you operate it their pointers. So when you declare a simple type variable you say::
-
- ppuint u;
- ppnum n;
- ppname name;
- ppstring string;
- ...
-
-And when you declare a compound type you operate on pointers::
-
- ppobj *obj;
- pparray *array;
- ppdict *dict;
- ppstream *stream;
- ppref *ref;
- ppdoc *pdf;
-
-Some of those C-types are defined in library header ``ppapi.h`` (complete types). Some others are incomplete
-(eg. you can't say ``sizeof(ppdoc)`` or ``sizeof(ppxref)``). This is to avoid unnecesary dependencies in
-the header. [At some points it's not clear to me what to hide and what to expose, will see.] The library itself
-uses ``pplib.h`` but for auxilary applications including a standalone ``ppapi.h`` header should be enough.
-
-``pplib`` was designed having **read-only** PDF access in mind. Even if some structure is completelly exposed,
-so that you can directly access its members, you should treat them as read-only. I don't make them ``const`` because
-then all variable declarations would need to be ``const``, which is annoying, and I'd need some trickery in the library
-internals to unconst. Besides, nothing is really const for C type casts.
-
-Object
-------
-
-A common container for all elementary PDF object types is ``ppobj`` structure. ``ppobj`` has a type identifier
-(integer) and union of values::
-
- struct ppobj {
- ppobjtp type;
- union {
- ppint integer;
- ppnum number;
- ppname name;
- ppstring string;
- pparray *array;
- ppdict *dict;
- ppstream *stream;
- ppref *ref;
- void *any;
- };
- };
-
-Object type is one of constants (enum)::
-
- PPNONE
- PPNULL
- PPBOOL
- PPINT
- PPNUM
- PPNAME
- PPSTRING
- PPARRAY
- PPDICT
- PPSTREAM
- PPREF
-
-The type determines the structure member you're allowed to access::
-
- ppobj *obj;
- ...
- switch (obj->type)
- {
- case PPNONE: // shouldn't actually happen, indicates some failure
- break;
- case PPNULL: // valid PDF null object, no value
- break;
- case PPBOOL: // do something with obj->integer (ppint), value 0 or 1
- break;
- case PPINT: // do something with obj->integer (ppint)
- break;
- case PPNUM: // do something with obj->number (ppnum)
- break;
- case PPNAME: // do something with obj->name (ppname)
- break;
- case PPSTRING: // do something with obj->string (ppstring)
- break;
- case PPARRAY: // do something with obj->array (pparray *)
- break;
- case PPDICT: // do something with obj->dict (ppdict *)
- break;
- case PPSTREAM: // do something with obj->stream (ppstream *)
- break;
- case PPREF: // do something with obj->ref (ppref *)
- break;
- }
-
-More often then not you know exactly what type of object value is expected, in which case
-you may use one of the following macros::
-
- // returns 1 if o->type is PPNULL
- int ppobj_get_null(o) \
-
- // if o->type is PPBOOL, sets int v to 0 or 1 and returns 1, 0 otherwise
- int ppobj_get_bool(o, v)
-
- // if o->type is PPINT, sets ppint v and returns 1, 0 otherwise
- int ppobj_get_int(o, v)
-
- // if o->type is PPINT and >= 0, sets ppuint v and returns 1, 0 otherwise
- int ppobj_get_uint(o, v)
-
- // if o->type is PPNUM or PPINT, sets ppnum v and returns 1, 0 otherwise
- int ppobj_get_num(o, v)
-
- // if o->type is PPNAME returns the name, NULL otherwise
- ppname ppobj_get_name(o)
-
- // if o->type is PPSTRING returns the string, NULL otherwise
- ppstring ppobj_get_string(o)
-
- // if o->type is PPARRAY returns the array, NULL otherwise
- pparray * ppobj_get_array(o)
-
- // if o->type is PPDICT returns the dict, NULL otherwise
- ppdict * ppobj_get_dict(o)
-
- // if o->type is PPSTREAM returns the stream, NULL otherwise
- ppstream * ppobj_get_stream(o)
-
- // if o->type is PPREF returns the reference, NULL otherwise
- ppref * ppobj_get_ref(o)
-
-Note the coercion from integer to real number, but not reverse. In practise, whenever you expect a real number,
-you should also handle integer (eg. '1' used instead of '1.0').
-
-It is a common case that the object is given as an indirect reference, but what you actually
-want is not the reference, but the object referred by it. Here is a helper for it::
-
- // if o->type is PPREF, returns what the reference points, otherwise returns o
- ppobj * ppobj_rget_obj(o)
-
-Also every ``ppobj_get_*`` macro has ``ppobj_rget_*`` counterpart that makes a check
-for the expected type, but if the object is PPREF, it jumps to the target object.
-So for example ``ppobj_rget_dict(obj)`` will return dict if ``obj`` is of type PPDICT
-or if it is of type PPREF and ``obj->ref`` hosts an object of type PPDICT.
-
-Names
------
-
-PDF names are represented as ``ppname``.
-I find it convenient to have ``ppname`` type pretending ``const char *``. This allows to use ``ppname``
-in all C-style string functions like ``printf("%s", name)``.
-
-Be aware, however, that ``ppname`` is actually a C-structure. It is perfectly ok to cast ``ppname`` to ``const char *``::
-
- ppname name;
- ...
- (const char *)name;
-
-But reverse is forbidden::
-
- const char *cstr = "cstring";
- ...
- (ppname)cstr; // expect segmentation fault soon
-
-For convenient use in C, names are ``'\0'`` terminated. But to get the length of name better always use
-``ppname_size()`` macro. ``ppname`` object knows its size, don't use ``strlen()``::
-
- size_t ppname_size(ppname name); // macro, returns length of name in bytes
-
-In current implementation names are not hashed anyhow, so name-to-name comparison is not smarter than ``memcmp()``.
-Use macros::
-
- int ppname_is(ppname name, "literal"); // to compare ppname with C-literal string
- int ppname_eq(ppname name, ppname other); // to compare ppname with a different name
-
-If you'll use ``pplib`` to parse contents streams, you may need to distinguish names from operators
-(more precisely executable names). Names in PDF are preceeded by '/', executable names aren't. In both
-cases PDF parser will produce ``ppname`` but can be distingushed with::
-
- int ppname_exec(ppname name); // returns non-zero if name is executable
-
-Names are kept in their raw form, with possible PDF specific escapes (in text below we call it **encoded** form).
-Leading '/' is omitted, though. One may need a decoded name, with no PDF escapes.
-A pair of functions provides a simple interface to switch between those two forms::
-
- ppname ppname_decoded (ppname name); // returns decoded (unescaped) form of the name
- ppname ppname_encoded (ppname name); // returns encoded (escaped) form of the name
-
-In pretty most cases PDF names contains only letters (no special characters, no escapes), so decoded and encoded forms are identical.
-In that case both functions simply return the argument. It is ok to call ``ppname_decoded()`` on already decoded form
-and ``ppname_encoded()`` on already encoded form. Both forms are produced by PDF objects parser, so accessing ``ppname`` alter ego
-in whatever direction needs no extra decoding or allocation costs.
-
-String
-------
-
-PDF strings have the same internal construction as names, so most of names description above applies to strings as well.
-``ppstring`` is a typedef of ``const char *``, roughly ``'\0'`` terminiated C-string. To get the size of the string::
-
- size_t ppstring_size(ppstring string); // macro, returns the length of the string in bytes
-
-Strings are provided in their raw form, preserving PDF specific escapes, but with no
-``()`` or ``<>`` delims. To distinguish plain strings from hex strings::
-
- int ppstring_hex(ppstring string); // macro, returns non zero if hex string
-
-Or if you prefer::
-
- switch (ppstring_type(string))
- {
- case PPSTRING_PLAIN: // literal string, surrounded by ``(`` and ``)`` in PDF
- break;
- case PPSTRING_BASE16: // hex string, surrounded by ``<`` and ``>`` in PDF
- break;
- case PPSTRING_BASE85: // base85 string surrounded by ``<~`` and ``~>`` in PDF
- break;
- }
-
-The last is actually Postscript specific, not used in PDF, but I think it might appear in contents streams...
-No matter how the string is given in PDF (plain or hex), here are two functions to
-switch between encoded and decoded strings forms::
-
- ppstring ppstring_decoded (ppstring string); // returns decoded string possibly with PDF escapes
- ppstring ppstring_encoded (ppstring string); // returns encoded string with no PDF escapes
-
-For hex strings, encoded form contains hex digits, while decoded form contains arbitrary bytes (the result of hex decoding).
-Plain strings usually contains printable ASCII characters, but they might contain any binary data.
-As with names, objects parser produces both forms. The raw form with PDF escapes (or raw hex form) is considered the main one.
-Eg. when you access ``obj->string`` you always get the encoded form. At any moment you can switch to its alter ego.
-
-No matter if the string is plain or hex, if its first two bytes (decoded) are UTF16 BOM, the string
-is considered unicode. ``ppstring`` object *knows* it is unicode or not::
-
- switch (ppstring_utf(string))
- {
- case PPSTRING_UTF16LE: // unicode string, utf16le
- break;
- case PPSTRING_UTF16BE: // unicode string, utf16be
- break;
- default: // no unicode
- }
-
-Or simply::
-
- if (ppstring_utf(string) != 0) {
- // handle unicode string
- }
-
-If the string is unicode, BOM remains the part of the string -- ``pplib`` parser does not strip it.
-Unicode or not, encoded or decoded, strings are always C-arrays of bytes and ``ppstring_size()``
-always returns the size in bytes.
-
-Array
------
-
-PDF arrays are represented as ``pparray`` type, which is C-array of ``ppobj`` structures.
-To get the size::
-
- size_t pparray_size(pparray *array) // macro, returns the number of array items
-
-To get ``ppobj *`` at a given index::
-
- ppobj * pparray_at(array, index) // macro, returns ppobj * (no index check)
- ppobj * pparray_get(array, index) // macro, returns ppobj * or NULL (with index check)
- ppobj * pparray_get_obj (pparray *array, size_t index); // function equiv to pparray_get()
-
-Iterating over array elements::
-
- pparray *array;
- size_t index, size;
- ppobj *obj;
- for (size = pparray_size(array), pparray_first(array, index, obj); index < size; pparray_next(index, obj))
- {
- // do something with index and obj
- }
-
-There is no magic first/next macros, just iteration over pointers. One could also use something like::
-
- for (index = 0, size = array->size; index < size; ++index)
- {
- obj = pparray_at(array, index);
- // do something with index and obj
- }
-
-When getting values from array and expecting a result of known type, use one of the following::
-
- int pparray_get_bool (pparray *array, size_t index, int *v); // get boolean value
- int pparray_get_int (pparray *array, size_t index, ppint *v); // get ppint value
- int pparray_get_uint (pparray *array, size_t index, ppuint *v); // get ppuint value
- int pparray_get_num (pparray *array, size_t index, ppnum *v); // get ppnum value
- ppname pparray_get_name (pparray *array, size_t index); // get ppname value
- ppstring pparray_get_string (pparray *array, size_t index); // get ppstring value
- pparray * pparray_get_array (pparray *array, size_t index); // get pparray * value
- ppdict * pparray_get_dict (pparray *array, size_t index); // get ppdict * value
- ppref * pparray_get_ref (pparray *array, size_t index); // get ppref * value
-
-As with ``ppobj_get_*`` suite, numeric types getters set the value of a given type and returns 1, if the type matches.
-Otherwise sets nothing and returns 0. Other getters return the value if the type matches, or NULL.
-
-Every function from ``pparray_get_*`` suite have its ``pparray_rget_*`` counterpart that
-that dereferences indirect objects (as explained for ``ppobj_rget_*`` getters). Note that
-there is no ``pparray_get_stream()`` function, as streams in PDF are always indirect.
-To get the stream from array use::
-
- ppstream * pparray_rget_stream (pparray *array, size_t index);
-
-Dict
-----
-
-PDF dicts are represented as ``ppdict`` structure, which is C-array of ``ppobj`` with parallel
-C-array of ``ppname`` pointers. To get the size of a dict::
-
- size_t ppdict_size(ppdict *dict) // macro, returns the number of key-val pairs
-
-To get the value at a given index (integer)::
-
- ppobj * ppdict_at(ppdict *dict, index) // macro, no index check
-
-To get the name (key) at a given index::
-
- ppname ppdict_key(ppdict *dict, index) // macro, no index check
-
-To iterate over dict key-val pairs::
-
- ppdict *dict;
- ppname *pkey;
- ppobj *obj;
-
- for (ppdict_first(dict, pkey, obj); *pkey != NULL; ppdict_next(pkey, obj))
- {
- // do something with *pkey and obj
- }
-
-There is no magic in first/next macros, just iteration through keys and values lists pointers.
-For convenient iteration, a list of keys is terminated with NULL, so in the code above ``*pkey != NULL``
-is used as the loop condition. One may also iterate via indices::
-
- ppdict *dict;
- size_t index, size;
- ppname key;
- ppobj *obj;
- for (index = 0, size = ppdict_size(dict); index < size; ++index)
- {
- key = ppdict_key(dict, index);
- obj = ppdict_at(dict, index);
- // do something with key and obj
- }
-
-To get the object associated with a given name, use one of the following::
-
- ppobj * ppdict_get_obj (ppdict *dict, const char *name);
- int ppdict_get_bool (ppdict *dict, const char *name, int *v);
- int ppdict_get_int (ppdict *dict, const char *name, ppint *v);
- int ppdict_get_uint (ppdict *dict, const char *name, ppuint *v);
- int ppdict_get_num (ppdict *dict, const char *name, ppnum *v);
- ppname ppdict_get_name (ppdict *dict, const char *name);
- ppstring ppdict_get_string (ppdict *dict, const char *name);
- pparray * ppdict_get_array (ppdict *dict, const char *name);
- ppdict * ppdict_get_dict (ppdict *dict, const char *name);
- ppref * ppdict_get_ref (ppdict *dict, const char *name);
-
-Note that all getters accepts ``const char *`` as key, so it is ok to say::
-
- ppdict_rget_dict(dict, "Resources");
-
-as well as::
-
- ppdic_rget_dict(dict, name); // ppname name
-
-Every ``ppdict_get_*`` getter has ``ppdict_rget_*`` counterpart that dereferences
-indirect objects if necessary. Note that there is no ``ppdict_get_stream()`` function,
-but there is::
-
- ppstream * ppdict_rget_stream (ppdict *dict, const char *name);
-
-So far dicts comes with no names mapping, so by-name dict accessors perform a linear search
-through the keys list. PDF dicts are usually small, so it is fast enough.
-Building names lookup for every dict in PDF makes no sense I think, as ``pplib`` applications
-will query just several dicts I guess.. However, some apps may extensively query
-resources, which may refer to hundreds of objects (eg. images). So some mapping for dicts
-is still considered.
-
-Stream
-------
-
-PDF streams are represented as ``ppstream`` objects. To get the stream dict::
-
- ppdict * ppstream_dict(ppstream *stream) // macro
-
-To read the stream data::
-
- uint8_t * ppstream_first (ppstream *stream, size_t *size, int decode);
- uint8_t * ppstream_next (ppstream *stream, size_t *size);
- void ppstream_done (ppstream *stream);
-
-Both ``first` and ``next`` functions return a chunk of stream data and sets the ``size`` of the chunk.
-``decode`` parameter tell the reader to decompress the stream (1) or return raw (0). A call to ``ppstream_next()``
-must be preceeded by ``ppstream_first()``. Once you're done with the stream, you have to call ``ppstream_done()``,
-no matter if the stream has been read to the end or not. The stream data iterator in use::
-
- uint8_t *data;
- size_t size;
- ppstream *stream;
- int decode = 1; // 1 - get decompressed, 0 - get raw
-
- for (data = ppstream_first(stream, &size, decode); data != NULL; data = ppstream_next(stream, &size))
- {
- // do something with data and its size
- }
- ppstream_done(stream);
-
-Every subsequent iterator call invalidates the previous reader output, so you have to utilize the returned chunk
-of data just after you ot that. So the following is wrong::
-
- data1 = ppstream_first(stream, &size, 1);
- data2 = ppstream_next(stream, &size);
- data3 = ppstream_next(stream, &size);
- some_output(data1, size);
- some_output(data2, size);
-
-The reader calls usually return the same pointer to internal buffer, just filled with a different data.
-``pplib`` allocates reasonably large buffer and fills that buffer on subsequent calls to the reader.
-
-If the source stream has no compression, using both ``decode == 1`` and ``decode == 0`` should give the same result.
-You can check if the stream is actually compressed with::
-
- ppstream_compressed(stream) // macro, returns non zero if /Filter is present
-
-It might be necessary to load the entire stream data at once::
-
- uint8_t * ppstream_all (ppstream *stream, size_t *size, int decode);
-
-If the initial buffer size is insufficient, it grows until the entire stream data is loaded. You must call
-``ppstream_done(stream)`` after using returned data.
-
-``ppstream_done()`` doesn't invalidate the stream object, it just closes its internal reader.
-The stream itself remains a valid object (eg. one can read it again if necessary),
-but the reader buffer is released. It is actually not freed but kept for future the reuse with that on some other stream,
-but you still need to mark it ready for reuse to avoid allocating a separate buffer for every stream you're going to read.
-
-Stream data readers will return ``NULL`` if you haven't close the previous reader process with ``ppstream_done()``. All below is wrong::
-
- data1 = ppstream_all(stream, &size, 1);
- data2 = ppstream_all(stream, &size, 1); // data2 == NULL
- // or
- data1 = ppstream_first(stream, &size, 1);
- data2 = ppstream_first(stream, &size, 1); // data2 == NULL
- // or
- data1 = ppstream_first(stream, &size, 1);
- data2 = ppstream_all(stream, &size, 1); // data2 == NULL
-
-To avoid unnecessary dependencies, ``pplib`` does not support image filters (``/DCT``, ``/JPX``, ``/JBIG``, ``/CCITT``).
-But it is ok to read the stream with ``decode`` set to 1 on such streams. ``pplib`` assumes that the image is the
-final/target stream form and just returns it as-is. Eg. in the case of JPEG (``/DCT`` filtered) image both calls should
-give the same results::
-
- ppstream_all(jpegstream, &jpegsize, 0); // don't decode, return what's there
- ppstream_all(jpegstream, &jpegsize, 1); // decode but found image filter, effectively the same
-
-A bit more about streams memory. As mentioned, ``pplib`` allocates buffers for stream readers. After ``ppstream_done()``,
-the stream no longer *owns* the buffer space. But the buffer may remain allocated, to be reused with future readers.
-``pplib`` keeps a pool of several buffers. This means, that when you use stream readers, ``pplib`` eats
-some memory (1MB or so) that is not freed, even if no streams are used. And even if you free all objects.
-If you suffer from this, you can optionally use a pair of functions::
-
- void ppstream_init_buffers (void);
- void ppstream_free_buffers (void);
-
-The first initializes buffers pool, unless done so far. Currently ``pplib`` cares of it before opening every stream reader,
-so it is not obligatory. The second frees a pool of buffers. The intended use is to call ``ppstream_init_buffers()`` once
-as kind of library initializer and to call ``ppstream_free_buffers()`` once, as the library finalizer.
-
-Filters
--------
-
-In version v1.00 (20190916) ``ppstream`` API has been extended with filters information.
-``ppstream`` knows its filter(s) and keps it as ``stream->filter``::
-
- // ppstream *stream;
- ppstream_filter *info = &stream->filter;
-
-``ppstream_filter`` is the following structure::
-
- typedef struct {
- ppstreamtp *filters; // c-array of filter identifiers (enum integers)
- ppdict **params; // c-array of ppdict pointers
- size_t count; // number of filters, length of the arrays (typically 1)
- } ppstream_filter;
-
-If ``count > 0`` then ``filters`` member is not NULL. Filters array keeps integer constants::
-
- PPSTREAM_BASE16 /* /ASCIIHexDecode */
- PPSTREAM_BASE85 /* /ASCII85Decode */
- PPSTREAM_RUNLENGTH /* /RunLengthDecode */
- PPSTREAM_FLATE /* /FlateDecode */
- PPSTREAM_LZW /* /LZWDecode */
- PPSTREAM_CCITT /* /CCITTFaxDecode */
- PPSTREAM_DCT /* /DCTDecode */
- PPSTREAM_JBIG2 /* /JBIG2Decode */
- PPSTREAM_JPX /* /JPXDecode */
- PPSTREAM_CRYPT /* /Crypt */
-
-Params array keeps corresponding filter parameters (``/DecodeParms``) if present. ``params`` member is not NULL
-if ``count > 0`` and the stream dict has ``/DecodeParms`` entry. Even if ``params`` is there,
-for every N-th filter, ``params[N]`` may be NULL (corresponding to PDF ``null``).
-
-``stream->filter`` keeps the source stream filter information, which may not correspond to the result of stream readers
-(``ppstream_first()``, ``ppstream_next()``, ``ppstream_all()``). The get the filters info relevant to the result from readers::
-
- void ppstream_filter_info (ppstream *stream, ppstream_filter *info, int decode);
-
-The function fills ``ppstream_filter`` structure according to the expected result from stream readers (example 3 shows
-how to use it to reconstruct ``/Filter`` and ``/DecodeParms`` when copying the stream to some other PDF).
-
-To convert filter identifier (``ppstreamtp``) to a corresponding PDF filter name::
-
- const char * ppstream_filter_name[];
-
-To covert ``ppname`` to filter identifier::
-
- int ppstream_filter_type (ppname filtername, ppstreamtp *filtertype);
- // returns 1 and sets filtertype if filtername is the proper filter name
-
-Additional information about the stream can be fetched from macros::
-
- ppstream_compressed(stream) /* stream->flags & (PPSTREAM_FILTER|PPSTREAM_IMAGE) */
- ppstream_filtered(stream) /* stream->flags & PPSTREAM_FILTER */
- ppstream_image(stream) /* stream->flags * PPSTREAM_IMAGE */
-
-``stream->flags`` is a binary sum of the following::
-
- PPSTREAM_FILTER /* set iff the stream filters list has one of: BASE16, BASE85, RUNLENGTH, FLATE, LZW */
- PPSTREAM_IMAGE /* set iff the stream filters list has one of: CCITT, DCT, JBIG2, JPX */
- PPSTREAM_ENCRYPTED /* set iff the stream is encrypted */
- PPSTREAM_ENCRYPTED_OWN /* set iff the stream has own CRYPT filter */
-
-Note that ``PPSTREAM_COMPRESSED`` is not there any longer, use ``ppstream_compressed()`` instead.
-And there is some more, see ``ppapi.h``.
-
-Ref
----
-
-Indirect objects are represented as ``ppref`` structure. To get the object that the
-reference refers to::
-
- ppobj * ppref_obj(ppref *ref) // macro
-
-``ppref`` structure also keeps the reference number and version, a pointer to cross reference table it belongs
-to and others, but I guess you won't need anything but the referenced object. ``pplib`` parser resolves references
-on-fly. So if there is a dict with indirect objects::
-
- <<
- /Type /Page
- /Resources 123 0 R
- ...
- >>
-
-the parser will produce ``ppdict`` with ``Resources`` key pointing the proper ``ppref *`` value.
-If you need more, access ``ppref`` members::
-
- struct ppref {
- ppobj object; // target object
- ppuint number, version; // identifiers
- size_t offset; // file offset (useless for you, may be zero for compressed objects)
- ppuint length; // the length of the original object data
- ppxref *xref; // cross reference table it belongs to
- };
-
-
-XRef
-----
-
-Cross reference table is exposed as ``ppxref`` (incomplete type, you can only oprate on its pointer).
-To get top document xref::
-
- ppxref * ppdoc_xref (ppdoc *pdf);
-
-To get previous (older) xref::
-
- ppxref * ppxref_prev (ppxref *xref);
-
-To find an object of a given refnumber::
-
- ppref * ppxref_find (ppxref *xref, ppuint refnumber);
-
-[Note: since pplib v0.98 in case of documents with incremental update, ``ppxref_find()`` returns
-the newest available version of a given object rather than the object in a given body.]
-
-PDF
----
-
-PDF document is represented as ``ppdoc`` structure (incomplete type, you can only operate on its pointer).
-To load a document from file::
-
- ppdoc * ppdoc_load (const char *filename);
-
-To load a document from memory data::
-
- ppdoc * ppdoc_mem (const void *data, size_t size);
-
-The data is assumed to be a buffer allocated with ``malloc`` - it is freed when destroying ``ppdoc``.
-
-Both loaders returns ``NULL`` on failure.
-
-To free ``ppdoc`` and all objects it refers to::
-
- void ppdoc_free (ppdoc *pdf);
-
-So far we haven't mention about any explicit object reclaimers. There are no dedicated ``free`` functions
-for other objects. You don't allocate or free objects yourself. ``ppdoc`` object is an owner of all
-beings it refers to. It also means that every object described so far is alive as long as the containing
-``ppdoc`` is alive.
-
-To access main PDF dicts::
-
- ppdict * ppdoc_trailer(ppdoc *pdf); // returns top xref trailer dict
- ppdict * ppdoc_catalog(ppdoc *pdf); // returns catalog referred from the trailer
- ppdict * ppdoc_info(ppdoc *pdf); // returns info dict referred from the trailer
-
-To get the PDF version::
-
- const char * ppdoc_version_string (ppdoc *pdf); // version string
- int ppdoc_version_number (ppdoc *pdf, int *minor); // minor and major numbers
-
-To get the file size of the source PDF document::
-
- size_t ppdoc_file_size (ppdoc *pdf);
-
-To get the number of objects in all xrefs::
-
- ppuint ppdoc_objects (ppdoc *pdf);
-
-To get the approx usage of memory::
-
- size_t ppdoc_memory (ppdoc *pdf, size_t *waste);
-
-Encryption
-----------
-
-``pplib`` handles encrypted (password protected) documents. If a document is encrypted, most of strings and streams are ciphered.
-In that form they are unreadable and rather useless, you can't even rewrite such strings/streams as-is to a different PDF output.
-It is a common practise to *protect* documents with an empty password. Such documents remain readable in Acrobat (just opens them without prompting
-for a password), but some features (eg. printing) may restricted by the application.
-
-When ``pplib`` detects encryption, it follows Acrobat approach and first tries an empty password. If it succeeds, ``pplib`` proceeeds normally, providing
-an access to decrypted strings and streams, as if they weren't ciphered. If the document is protected with non-empty password, ``pplib`` gives
-a way to provide a password and proceed. Until you provide a password, ``ppdoc`` object returned by ``ppdoc_load()`` function has all object wntries
-set to ``null``.
-
-After loading a document you should check encryption status with::
-
- ppcrypt_status ppdoc_crypt_status (ppdoc *pdf);
-
-``ppcrypt_status`` (integer) may have the following values:
-
- ``PPCRYPT_NONE`` - no encryption, go ahead
- ``PPCRYPT_DONE`` - encryption present but password succeeded, go ahead
- ``PPCRYPT_PASS`` - encryption present, need non-empty password
- ``PPCRYPT_FAIL`` - invalid or unsupported encryption (eg. undocumented in pdf spec)
-
-If a password is needed, you can provide one with::
-
- ppcrypt_status ppdoc_crypt_pass (ppdoc *pdf, const void *userpass, size_t userpasslength,
- const void *ownerpass, size_t ownerpasslength);
-
-Well, yes, there are actually two passwords in encrypted documents. Relation between them is obscure to me, but enough
-to know that having one of them is enough to decrypt the document. If you know the password, you probably mean
-``userpass``, in which case you should put ``NULL`` as ``ownerpass``. The function returns ``PPCRYPT_DONE`` if the password
-succeeds and the previous status otherwise. Your custom loader function may look like that::
-
- ppdoc *pdf;
- pdf = ppdoc_load("file.pdf");
- if (pdf == NULL)
- return NULL;
- switch (ppdoc_crypt_status(pdf))
- {
- case PPCRYPT_NONE:
- case PPCRYPT_DONE:
- return pdf;
- case PPCRYPT_PASS:
- if (ppdoc_crypt_pass(pdf, "dummy", 5, NULL, 0) == PPCRYPT_DONE ||
- ppdoc_crypt_pass(pdf, NULL, 0, "dummy", 5) == PPCRYPT_DONE)
- return pdf;
- printf("sorry, password needed\n");
- ppdoc_free(pdf);
- return NULL;
- case PPCRYPT_FAIL:
- printf("sorry, encryption failed\n");
- ppdoc_free(pdf);
- return NULL;
- }
-
-[If you get ``PPCRYPT_FAIL`` it might mean *I failed*, so treat as a bug.]
-
-If you'd like to know what permissions are given/restricted to encrypted document::
-
- ppint ppdoc_permissions (ppdoc *pdf);
-
-Returned value can be queried with the following binary flags (you can verify with Acrobat *File -> Properties -> Security* tab)::
-
- PPDOC_ALLOW_PRINT // printing
- PPDOC_ALLOW_MODIFY // filling form fields, signing, creating template pages
- PPDOC_ALLOW_COPY // copying, copying for accessibility
- PPDOC_ALLOW_ANNOTS // filling form fields, copying, signing
- PPDOC_ALLOW_EXTRACT // contents copying for accessibility
- PPDOC_ALLOW_ASSEMBLY // (no effect)
- PPDOC_ALLOW_PRINT_HIRES // (no effect)
-
-``pplib`` does absolutelly nothing with permissions, it cares only to decrypt the document. As mentioned, encryption applies to strings
-and streams. ``pplib`` decrypt strings when parsing document objects, so the result you get is *normal* (not ciphered).
-Streams are decrypted whenever you access them. Even if you ask for a raw stream data, you'll get a raw (compressed) stream, but decrypted.
-So except the check to ``ppdoc_crypt_status()``, you shouldn't bother about encryption.
-
-In encrypted documents most of streams are encrypted. To check if a given stream is encrypted::
-
- ppstream_encrypted(stream) // macro, returns non-zero if encrypted
-
-Encryption is independent from compression, don't confuse with ``ppstream_compressed()``
-
-Pages
------
-
-Several helpers to deal with pages. To get the number of pages::
-
- ppuint ppdoc_page_count (ppdoc *pdf);
-
-To access the root pages tree node::
-
- ppref * ppdoc_pages(ppdoc *pdf);
-
-To get the page reference at a given index::
-
- ppref * ppdoc_page (ppdoc *pdf, ppuint index);
-
-``index`` is a page number. First page has number 1. For index out of bounds ``ppdoc_page()`` returns NULL.
-Iterating over pages using index from 1 to ``ppdoc_page_count()`` and calling ``ppdoc_page()`` on each iteration
-would be suboptimal. Here is a dedicted iterator for this::
-
- ppref * ppdoc_first_page (ppdoc *pdf);
- ppref * ppdoc_next_page (ppdoc *pdf);
-
-The iterator in use::
-
- ppdoc *pdf;
- ppref *ref;
- ppdict *dict;
- int pageno;
-
- pdf = ppdoc_load("file.pdf");
- for (ref = ppdoc_first_page(pdf), pageno = 1; ref != NULL; ref = ppdoc_next_page(pdf), ++pageno)
- {
- dict = ppref_obj(obj)->dict; // take for granted it is a dict
- // do something with the page dict
- }
-
-Functions related to pages return ``ppref *`` ensured to contain dict object, so you don't need sanity
-type checks here.
-
-Contents
---------
-
-PDF page contents can be given as a stream or array of streams. Here is a convenience iterator over page
-contents streams::
-
- ppstream * ppcontents_first (ppdict *dict);
- ppstream * ppcontents_next (ppdict *dict, ppstream *stream);
-
-A complete example of contents stream parser use is given below (example 2).
-But before we get there, we need to introduce ``ppcontext`` object. Conceptually,
-``ppcontext`` is an owner (memory handler) of objects created on demand (beyond the ``ppdoc``).
-So far used only with contents stream parser, which might produce quite some data that we want
-to release just after used. To create a new context::
-
- pcontext * ppcontext_new (void);
-
-It initializes a new context and its internal memory heap, taking about 64kB on start. After that,
-the context is ready to produce objects (contents parsing functions below). Once objects produced
-from a given context are no longer needed::
-
- void ppcontext_done (ppcontext *context);
-
-It restores the context to its initial state, as after ``ppcontext_new()``. It means that the context
-is ready to produce another bunch of beings (in the example below, all objects from the next page contents).
-Once the context is not needed anymore::
-
- void ppcontext_free (ppcontext *context);
-
-Now, contents stream parser functions take the context as an argument. Iterator form of contents stream parser
-that allows to process the contents operator by operator::
-
- ppobj * ppcontents_first_op (ppcontext *context, ppstream *stream, size_t *psize, ppname *pname);
- ppobj * ppcontents_next_op (ppcontext *context, ppstream *stream, size_t *psize, ppname *pname);
-
-Returned ``ppobj *`` is a pointer to operands list. ``*psize`` is the number of operands on stack.
-The operator itself is stored as ``*pname``.
-
-To parse the entire contents stream at once with no stop at every operator::
-
- ppobj * ppcontents_parse (ppcontext *context, ppstream *stream, size_t *psize);
-
-Returns probably quite long list of all parsed objects (operands and operatos) in one piece.
-The number of objects is stored to ``*psize``.
-
-[Contents may contain so called inline images, that breaks a simple scheme of operands / operator syntax::
-
- BI <keyval pairs> ID <binary image data> EI
-
-Contents parser treats this genuine triplet as a single piece, producing two operands (dict and string)
-followed by ``EI`` operator name.]
-
-Boxes
------
-
-Boxes (rectangles) in PDF are roughly 4-number arrays, but with a special intent.
-``pplib`` provides a basic interface for these special arrays::
-
- typedef struct {
- ppnum lx, ly, rx, ry;
- } pprect;
-
-This type is used only by helper functions - PDF parser is not aware of the rectangle type.
-To convert ``pparray`` to ``pprect``::
-
- pprect * pparray_to_rect (pparray *array, pprect *rect); // returns rect or NULL
-
-In example::
-
- pprect rect;
- if (pparray_to_rect(array, &rect) != NULL)
- ; // do something with rect
-
-To get some image bounding box::
-
- pprect * ppdict_get_rect (ppdict *dict, const char *name, pprect *rect);
- // eg. ppdict_get_rect(imagedict, "BBox", &rect)
-
-To get some page box::
-
- pprect * ppdict_get_box (ppdict *dict, const char *name, pprect *rect);
- // eg. ppdict_get_box(pagedict, "MediaBox", &rect)
-
-The later not only checks the pagedict, but also goes through parent page nodes.
-
-Transforms
-----------
-
-Transformations are given as 6-number arrays, but with a special intent.
-``pplib`` provides a basic interface for these special arrays::
-
- typedef struct {
- ppnum xx, xy, yx, yy, x, y;
- } ppmatrix;
-
-This type is used only by helper functions - PDF parser is not aware of the matrix type.
-To convert ``pparray`` to ``ppmatrix``::
-
- ppmatrix * pparray_to_matrix (pparray *array, ppmatrix *matrix);
-
-In example::
-
- ppmatrix matrix;
- if (pparray_to_matrix(array, &matrix) != NULL)
- ; // do something with matrix
-
-To get the matrix from dict::
-
- ppmatrix * ppdict_get_matrix (ppdict *dict, const char *name, ppmatrix *matrix);
- // eg. ppdict_get_matrix(imagedict, "Matrix", &matrix)
-
-Errors handling
----------------
-
-``pplib`` is not verbose, but might happen that it needs to log some error message, eg. when parsing
-of some PDF boject fails due to invalid offsets. By default, ``pplib`` prints the message to stdout, eg.::
-
- invalid 123 0 R object at offset 123123
-
-To replace the default logger, you can provide your own::
-
- void pplog_callback (pplogger_callback logger, void *alien);
-
-``pplogger_callback`` is a function::
-
- void your_callback (const char *message, void *alien);
-
-In example, to redirect messages to stderr you may define a function::
-
- void your_callback (const char *message, void *alien)
- {
- fprintf((FILE *)alien, "\nooops: %s\n", message);
- }
-
-Then set the callback somewhere before loading documents::
-
- pplog_callback(your_callback, stderr);
-
-(example 2 uses that).
-
-To set the default log messages prefix, eg. ``pplib:``, use::
-
- int pplog_prefix (const char *prefix)
-
-Default is empty. The function succeeds if provided prefix is reasonably short (less then 32 bytes).
+ +``pplib`` 1.x +============= + +``pplib`` is a library for raw PDF access. It parses PDF documents and provides an interface to access document structures in C. + +C-API +===== + +Types +----- + +``pplib`` defines several C-types to represent PDF types: + +- ``ppint`` - signed integer (``int64_t``) +- ``ppnum`` - real number (double) +- ``ppname`` - PDF name +- ``ppstring`` - PDF string +- ``pparray`` - PDF array +- ``ppdict`` - PDF dict +- ``ppstream`` - PDF stream +- ``ppref`` - PDF indirect reference +- ``ppobj`` - a container of all above + +Among ``ppint`` and ``ppnum``, we also use ``ppuint`` - unsigned integer (machine word, alias to ``size_t``). + +Other API types: + +- ``ppdoc`` - PDF document +- ``ppxref`` - cross-references table +- ``ppcontext`` - ... later +- ``pprect`` - rectangle +- ``ppmatrix`` - matrix + +Integer, number, name and string are treated as simple types. +Names and strings are actually C-structures, but exposed to API as typedefs to ``const char *``. +Other types (array, dict, stream, reference, object container, xref, PDF) are C-structures, +and you operate it their pointers. So when you declare a simple type variable you say:: + + ppuint u; + ppnum n; + ppname name; + ppstring string; + ... + +And when you declare a compound type you operate on pointers:: + + ppobj *obj; + pparray *array; + ppdict *dict; + ppstream *stream; + ppref *ref; + ppdoc *pdf; + +Some of those C-types are defined in library header ``ppapi.h`` (complete types). Some others are incomplete +(eg. you can't say ``sizeof(ppdoc)`` or ``sizeof(ppxref)``). This is to avoid unnecesary dependencies in +the header. [At some points it's not clear to me what to hide and what to expose, will see.] The library itself +uses ``pplib.h`` but for auxilary applications including a standalone ``ppapi.h`` header should be enough. + +``pplib`` was designed having **read-only** PDF access in mind. Even if some structure is completelly exposed, +so that you can directly access its members, you should treat them as read-only. I don't make them ``const`` because +then all variable declarations would need to be ``const``, which is annoying, and I'd need some trickery in the library +internals to unconst. Besides, nothing is really const for C type casts. + +Object +------ + +A common container for all elementary PDF object types is ``ppobj`` structure. ``ppobj`` has a type identifier +(integer) and union of values:: + + struct ppobj { + ppobjtp type; + union { + ppint integer; + ppnum number; + ppname name; + ppstring string; + pparray *array; + ppdict *dict; + ppstream *stream; + ppref *ref; + void *any; + }; + }; + +Object type is one of constants (enum):: + + PPNONE + PPNULL + PPBOOL + PPINT + PPNUM + PPNAME + PPSTRING + PPARRAY + PPDICT + PPSTREAM + PPREF + +The type determines the structure member you're allowed to access:: + + ppobj *obj; + ... + switch (obj->type) + { + case PPNONE: // shouldn't actually happen, indicates some failure + break; + case PPNULL: // valid PDF null object, no value + break; + case PPBOOL: // do something with obj->integer (ppint), value 0 or 1 + break; + case PPINT: // do something with obj->integer (ppint) + break; + case PPNUM: // do something with obj->number (ppnum) + break; + case PPNAME: // do something with obj->name (ppname) + break; + case PPSTRING: // do something with obj->string (ppstring) + break; + case PPARRAY: // do something with obj->array (pparray *) + break; + case PPDICT: // do something with obj->dict (ppdict *) + break; + case PPSTREAM: // do something with obj->stream (ppstream *) + break; + case PPREF: // do something with obj->ref (ppref *) + break; + } + +More often then not you know exactly what type of object value is expected, in which case +you may use one of the following macros:: + + // returns 1 if o->type is PPNULL + int ppobj_get_null(o) \ + + // if o->type is PPBOOL, sets int v to 0 or 1 and returns 1, 0 otherwise + int ppobj_get_bool(o, v) + + // if o->type is PPINT, sets ppint v and returns 1, 0 otherwise + int ppobj_get_int(o, v) + + // if o->type is PPINT and >= 0, sets ppuint v and returns 1, 0 otherwise + int ppobj_get_uint(o, v) + + // if o->type is PPNUM or PPINT, sets ppnum v and returns 1, 0 otherwise + int ppobj_get_num(o, v) + + // if o->type is PPNAME returns the name, NULL otherwise + ppname ppobj_get_name(o) + + // if o->type is PPSTRING returns the string, NULL otherwise + ppstring ppobj_get_string(o) + + // if o->type is PPARRAY returns the array, NULL otherwise + pparray * ppobj_get_array(o) + + // if o->type is PPDICT returns the dict, NULL otherwise + ppdict * ppobj_get_dict(o) + + // if o->type is PPSTREAM returns the stream, NULL otherwise + ppstream * ppobj_get_stream(o) + + // if o->type is PPREF returns the reference, NULL otherwise + ppref * ppobj_get_ref(o) + +Note the coercion from integer to real number, but not reverse. In practise, whenever you expect a real number, +you should also handle integer (eg. '1' used instead of '1.0'). + +It is a common case that the object is given as an indirect reference, but what you actually +want is not the reference, but the object referred by it. Here is a helper for it:: + + // if o->type is PPREF, returns what the reference points, otherwise returns o + ppobj * ppobj_rget_obj(o) + +Also every ``ppobj_get_*`` macro has ``ppobj_rget_*`` counterpart that makes a check +for the expected type, but if the object is PPREF, it jumps to the target object. +So for example ``ppobj_rget_dict(obj)`` will return dict if ``obj`` is of type PPDICT +or if it is of type PPREF and ``obj->ref`` hosts an object of type PPDICT. + +Names +----- + +PDF names are represented as ``ppname``. +I find it convenient to have ``ppname`` type pretending ``const char *``. This allows to use ``ppname`` +in all C-style string functions like ``printf("%s", name)``. + +Be aware, however, that ``ppname`` is actually a C-structure. It is perfectly ok to cast ``ppname`` to ``const char *``:: + + ppname name; + ... + (const char *)name; + +But reverse is forbidden:: + + const char *cstr = "cstring"; + ... + (ppname)cstr; // expect segmentation fault soon + +For convenient use in C, names are ``'\0'`` terminated. But to get the length of name better always use +``ppname_size()`` macro. ``ppname`` object knows its size, don't use ``strlen()``:: + + size_t ppname_size(ppname name); // macro, returns length of name in bytes + +In current implementation names are not hashed anyhow, so name-to-name comparison is not smarter than ``memcmp()``. +Use macros:: + + int ppname_is(ppname name, "literal"); // to compare ppname with C-literal string + int ppname_eq(ppname name, ppname other); // to compare ppname with a different name + +If you'll use ``pplib`` to parse contents streams, you may need to distinguish names from operators +(more precisely executable names). Names in PDF are preceeded by '/', executable names aren't. In both +cases PDF parser will produce ``ppname`` but can be distingushed with:: + + int ppname_exec(ppname name); // returns non-zero if name is executable + +Names are kept in their raw form, with possible PDF specific escapes (in text below we call it **encoded** form). +Leading '/' is omitted, though. One may need a decoded name, with no PDF escapes. +A pair of functions provides a simple interface to switch between those two forms:: + + ppname ppname_decoded (ppname name); // returns decoded (unescaped) form of the name + ppname ppname_encoded (ppname name); // returns encoded (escaped) form of the name + +In pretty most cases PDF names contains only letters (no special characters, no escapes), so decoded and encoded forms are identical. +In that case both functions simply return the argument. It is ok to call ``ppname_decoded()`` on already decoded form +and ``ppname_encoded()`` on already encoded form. Both forms are produced by PDF objects parser, so accessing ``ppname`` alter ego +in whatever direction needs no extra decoding or allocation costs. + +String +------ + +PDF strings have the same internal construction as names, so most of names description above applies to strings as well. +``ppstring`` is a typedef of ``const char *``, roughly ``'\0'`` terminiated C-string. To get the size of the string:: + + size_t ppstring_size(ppstring string); // macro, returns the length of the string in bytes + +Strings are provided in their raw form, preserving PDF specific escapes, but with no +``()`` or ``<>`` delims. To distinguish plain strings from hex strings:: + + int ppstring_hex(ppstring string); // macro, returns non zero if hex string + +Or if you prefer:: + + switch (ppstring_type(string)) + { + case PPSTRING_PLAIN: // literal string, surrounded by ``(`` and ``)`` in PDF + break; + case PPSTRING_BASE16: // hex string, surrounded by ``<`` and ``>`` in PDF + break; + case PPSTRING_BASE85: // base85 string surrounded by ``<~`` and ``~>`` in PDF + break; + } + +The last is actually Postscript specific, not used in PDF, but I think it might appear in contents streams... +No matter how the string is given in PDF (plain or hex), here are two functions to +switch between encoded and decoded strings forms:: + + ppstring ppstring_decoded (ppstring string); // returns decoded string possibly with PDF escapes + ppstring ppstring_encoded (ppstring string); // returns encoded string with no PDF escapes + +For hex strings, encoded form contains hex digits, while decoded form contains arbitrary bytes (the result of hex decoding). +Plain strings usually contains printable ASCII characters, but they might contain any binary data. +As with names, objects parser produces both forms. The raw form with PDF escapes (or raw hex form) is considered the main one. +Eg. when you access ``obj->string`` you always get the encoded form. At any moment you can switch to its alter ego. + +No matter if the string is plain or hex, if its first two bytes (decoded) are UTF16 BOM, the string +is considered unicode. ``ppstring`` object *knows* it is unicode or not:: + + switch (ppstring_utf(string)) + { + case PPSTRING_UTF16LE: // unicode string, utf16le + break; + case PPSTRING_UTF16BE: // unicode string, utf16be + break; + default: // no unicode + } + +Or simply:: + + if (ppstring_utf(string) != 0) { + // handle unicode string + } + +If the string is unicode, BOM remains the part of the string -- ``pplib`` parser does not strip it. +Unicode or not, encoded or decoded, strings are always C-arrays of bytes and ``ppstring_size()`` +always returns the size in bytes. + +Array +----- + +PDF arrays are represented as ``pparray`` type, which is C-array of ``ppobj`` structures. +To get the size:: + + size_t pparray_size(pparray *array) // macro, returns the number of array items + +To get ``ppobj *`` at a given index:: + + ppobj * pparray_at(array, index) // macro, returns ppobj * (no index check) + ppobj * pparray_get(array, index) // macro, returns ppobj * or NULL (with index check) + ppobj * pparray_get_obj (pparray *array, size_t index); // function equiv to pparray_get() + +Iterating over array elements:: + + pparray *array; + size_t index, size; + ppobj *obj; + for (size = pparray_size(array), pparray_first(array, index, obj); index < size; pparray_next(index, obj)) + { + // do something with index and obj + } + +There is no magic first/next macros, just iteration over pointers. One could also use something like:: + + for (index = 0, size = array->size; index < size; ++index) + { + obj = pparray_at(array, index); + // do something with index and obj + } + +When getting values from array and expecting a result of known type, use one of the following:: + + int pparray_get_bool (pparray *array, size_t index, int *v); // get boolean value + int pparray_get_int (pparray *array, size_t index, ppint *v); // get ppint value + int pparray_get_uint (pparray *array, size_t index, ppuint *v); // get ppuint value + int pparray_get_num (pparray *array, size_t index, ppnum *v); // get ppnum value + ppname pparray_get_name (pparray *array, size_t index); // get ppname value + ppstring pparray_get_string (pparray *array, size_t index); // get ppstring value + pparray * pparray_get_array (pparray *array, size_t index); // get pparray * value + ppdict * pparray_get_dict (pparray *array, size_t index); // get ppdict * value + ppref * pparray_get_ref (pparray *array, size_t index); // get ppref * value + +As with ``ppobj_get_*`` suite, numeric types getters set the value of a given type and returns 1, if the type matches. +Otherwise sets nothing and returns 0. Other getters return the value if the type matches, or NULL. + +Every function from ``pparray_get_*`` suite have its ``pparray_rget_*`` counterpart that +that dereferences indirect objects (as explained for ``ppobj_rget_*`` getters). Note that +there is no ``pparray_get_stream()`` function, as streams in PDF are always indirect. +To get the stream from array use:: + + ppstream * pparray_rget_stream (pparray *array, size_t index); + +Dict +---- + +PDF dicts are represented as ``ppdict`` structure, which is C-array of ``ppobj`` with parallel +C-array of ``ppname`` pointers. To get the size of a dict:: + + size_t ppdict_size(ppdict *dict) // macro, returns the number of key-val pairs + +To get the value at a given index (integer):: + + ppobj * ppdict_at(ppdict *dict, index) // macro, no index check + +To get the name (key) at a given index:: + + ppname ppdict_key(ppdict *dict, index) // macro, no index check + +To iterate over dict key-val pairs:: + + ppdict *dict; + ppname *pkey; + ppobj *obj; + + for (ppdict_first(dict, pkey, obj); *pkey != NULL; ppdict_next(pkey, obj)) + { + // do something with *pkey and obj + } + +There is no magic in first/next macros, just iteration through keys and values lists pointers. +For convenient iteration, a list of keys is terminated with NULL, so in the code above ``*pkey != NULL`` +is used as the loop condition. One may also iterate via indices:: + + ppdict *dict; + size_t index, size; + ppname key; + ppobj *obj; + for (index = 0, size = ppdict_size(dict); index < size; ++index) + { + key = ppdict_key(dict, index); + obj = ppdict_at(dict, index); + // do something with key and obj + } + +To get the object associated with a given name, use one of the following:: + + ppobj * ppdict_get_obj (ppdict *dict, const char *name); + int ppdict_get_bool (ppdict *dict, const char *name, int *v); + int ppdict_get_int (ppdict *dict, const char *name, ppint *v); + int ppdict_get_uint (ppdict *dict, const char *name, ppuint *v); + int ppdict_get_num (ppdict *dict, const char *name, ppnum *v); + ppname ppdict_get_name (ppdict *dict, const char *name); + ppstring ppdict_get_string (ppdict *dict, const char *name); + pparray * ppdict_get_array (ppdict *dict, const char *name); + ppdict * ppdict_get_dict (ppdict *dict, const char *name); + ppref * ppdict_get_ref (ppdict *dict, const char *name); + +Note that all getters accepts ``const char *`` as key, so it is ok to say:: + + ppdict_rget_dict(dict, "Resources"); + +as well as:: + + ppdic_rget_dict(dict, name); // ppname name + +Every ``ppdict_get_*`` getter has ``ppdict_rget_*`` counterpart that dereferences +indirect objects if necessary. Note that there is no ``ppdict_get_stream()`` function, +but there is:: + + ppstream * ppdict_rget_stream (ppdict *dict, const char *name); + +So far dicts comes with no names mapping, so by-name dict accessors perform a linear search +through the keys list. PDF dicts are usually small, so it is fast enough. +Building names lookup for every dict in PDF makes no sense I think, as ``pplib`` applications +will query just several dicts I guess.. However, some apps may extensively query +resources, which may refer to hundreds of objects (eg. images). So some mapping for dicts +is still considered. + +Stream +------ + +PDF streams are represented as ``ppstream`` objects. To get the stream dict:: + + ppdict * ppstream_dict(ppstream *stream) // macro + +To read the stream data:: + + uint8_t * ppstream_first (ppstream *stream, size_t *size, int decode); + uint8_t * ppstream_next (ppstream *stream, size_t *size); + void ppstream_done (ppstream *stream); + +Both ``first` and ``next`` functions return a chunk of stream data and sets the ``size`` of the chunk. +``decode`` parameter tell the reader to decompress the stream (1) or return raw (0). A call to ``ppstream_next()`` +must be preceeded by ``ppstream_first()``. Once you're done with the stream, you have to call ``ppstream_done()``, +no matter if the stream has been read to the end or not. The stream data iterator in use:: + + uint8_t *data; + size_t size; + ppstream *stream; + int decode = 1; // 1 - get decompressed, 0 - get raw + + for (data = ppstream_first(stream, &size, decode); data != NULL; data = ppstream_next(stream, &size)) + { + // do something with data and its size + } + ppstream_done(stream); + +Every subsequent iterator call invalidates the previous reader output, so you have to utilize the returned chunk +of data just after you ot that. So the following is wrong:: + + data1 = ppstream_first(stream, &size, 1); + data2 = ppstream_next(stream, &size); + data3 = ppstream_next(stream, &size); + some_output(data1, size); + some_output(data2, size); + +The reader calls usually return the same pointer to internal buffer, just filled with a different data. +``pplib`` allocates reasonably large buffer and fills that buffer on subsequent calls to the reader. + +If the source stream has no compression, using both ``decode == 1`` and ``decode == 0`` should give the same result. +You can check if the stream is actually compressed with:: + + ppstream_compressed(stream) // macro, returns non zero if /Filter is present + +It might be necessary to load the entire stream data at once:: + + uint8_t * ppstream_all (ppstream *stream, size_t *size, int decode); + +If the initial buffer size is insufficient, it grows until the entire stream data is loaded. You must call +``ppstream_done(stream)`` after using returned data. + +``ppstream_done()`` doesn't invalidate the stream object, it just closes its internal reader. +The stream itself remains a valid object (eg. one can read it again if necessary), +but the reader buffer is released. It is actually not freed but kept for future the reuse with that on some other stream, +but you still need to mark it ready for reuse to avoid allocating a separate buffer for every stream you're going to read. + +Stream data readers will return ``NULL`` if you haven't close the previous reader process with ``ppstream_done()``. All below is wrong:: + + data1 = ppstream_all(stream, &size, 1); + data2 = ppstream_all(stream, &size, 1); // data2 == NULL + // or + data1 = ppstream_first(stream, &size, 1); + data2 = ppstream_first(stream, &size, 1); // data2 == NULL + // or + data1 = ppstream_first(stream, &size, 1); + data2 = ppstream_all(stream, &size, 1); // data2 == NULL + +To avoid unnecessary dependencies, ``pplib`` does not support image filters (``/DCT``, ``/JPX``, ``/JBIG``, ``/CCITT``). +But it is ok to read the stream with ``decode`` set to 1 on such streams. ``pplib`` assumes that the image is the +final/target stream form and just returns it as-is. Eg. in the case of JPEG (``/DCT`` filtered) image both calls should +give the same results:: + + ppstream_all(jpegstream, &jpegsize, 0); // don't decode, return what's there + ppstream_all(jpegstream, &jpegsize, 1); // decode but found image filter, effectively the same + +A bit more about streams memory. As mentioned, ``pplib`` allocates buffers for stream readers. After ``ppstream_done()``, +the stream no longer *owns* the buffer space. But the buffer may remain allocated, to be reused with future readers. +``pplib`` keeps a pool of several buffers. This means, that when you use stream readers, ``pplib`` eats +some memory (1MB or so) that is not freed, even if no streams are used. And even if you free all objects. +If you suffer from this, you can optionally use a pair of functions:: + + void ppstream_init_buffers (void); + void ppstream_free_buffers (void); + +The first initializes buffers pool, unless done so far. Currently ``pplib`` cares of it before opening every stream reader, +so it is not obligatory. The second frees a pool of buffers. The intended use is to call ``ppstream_init_buffers()`` once +as kind of library initializer and to call ``ppstream_free_buffers()`` once, as the library finalizer. + +Filters +------- + +In version v1.00 (20190916) ``ppstream`` API has been extended with filters information. +``ppstream`` knows its filter(s) and keps it as ``stream->filter``:: + + // ppstream *stream; + ppstream_filter *info = &stream->filter; + +``ppstream_filter`` is the following structure:: + + typedef struct { + ppstreamtp *filters; // c-array of filter identifiers (enum integers) + ppdict **params; // c-array of ppdict pointers + size_t count; // number of filters, length of the arrays (typically 1) + } ppstream_filter; + +If ``count > 0`` then ``filters`` member is not NULL. Filters array keeps integer constants:: + + PPSTREAM_BASE16 /* /ASCIIHexDecode */ + PPSTREAM_BASE85 /* /ASCII85Decode */ + PPSTREAM_RUNLENGTH /* /RunLengthDecode */ + PPSTREAM_FLATE /* /FlateDecode */ + PPSTREAM_LZW /* /LZWDecode */ + PPSTREAM_CCITT /* /CCITTFaxDecode */ + PPSTREAM_DCT /* /DCTDecode */ + PPSTREAM_JBIG2 /* /JBIG2Decode */ + PPSTREAM_JPX /* /JPXDecode */ + PPSTREAM_CRYPT /* /Crypt */ + +Params array keeps corresponding filter parameters (``/DecodeParms``) if present. ``params`` member is not NULL +if ``count > 0`` and the stream dict has ``/DecodeParms`` entry. Even if ``params`` is there, +for every N-th filter, ``params[N]`` may be NULL (corresponding to PDF ``null``). + +``stream->filter`` keeps the source stream filter information, which may not correspond to the result of stream readers +(``ppstream_first()``, ``ppstream_next()``, ``ppstream_all()``). The get the filters info relevant to the result from readers:: + + void ppstream_filter_info (ppstream *stream, ppstream_filter *info, int decode); + +The function fills ``ppstream_filter`` structure according to the expected result from stream readers (example 3 shows +how to use it to reconstruct ``/Filter`` and ``/DecodeParms`` when copying the stream to some other PDF). + +To convert filter identifier (``ppstreamtp``) to a corresponding PDF filter name:: + + const char * ppstream_filter_name[]; + +To covert ``ppname`` to filter identifier:: + + int ppstream_filter_type (ppname filtername, ppstreamtp *filtertype); + // returns 1 and sets filtertype if filtername is the proper filter name + +Additional information about the stream can be fetched from macros:: + + ppstream_compressed(stream) /* stream->flags & (PPSTREAM_FILTER|PPSTREAM_IMAGE) */ + ppstream_filtered(stream) /* stream->flags & PPSTREAM_FILTER */ + ppstream_image(stream) /* stream->flags * PPSTREAM_IMAGE */ + +``stream->flags`` is a binary sum of the following:: + + PPSTREAM_FILTER /* set iff the stream filters list has one of: BASE16, BASE85, RUNLENGTH, FLATE, LZW */ + PPSTREAM_IMAGE /* set iff the stream filters list has one of: CCITT, DCT, JBIG2, JPX */ + PPSTREAM_ENCRYPTED /* set iff the stream is encrypted */ + PPSTREAM_ENCRYPTED_OWN /* set iff the stream has own CRYPT filter */ + +Note that ``PPSTREAM_COMPRESSED`` is not there any longer, use ``ppstream_compressed()`` instead. +And there is some more, see ``ppapi.h``. + +Ref +--- + +Indirect objects are represented as ``ppref`` structure. To get the object that the +reference refers to:: + + ppobj * ppref_obj(ppref *ref) // macro + +``ppref`` structure also keeps the reference number and version, a pointer to cross reference table it belongs +to and others, but I guess you won't need anything but the referenced object. ``pplib`` parser resolves references +on-fly. So if there is a dict with indirect objects:: + + << + /Type /Page + /Resources 123 0 R + ... + >> + +the parser will produce ``ppdict`` with ``Resources`` key pointing the proper ``ppref *`` value. +If you need more, access ``ppref`` members:: + + struct ppref { + ppobj object; // target object + ppuint number, version; // identifiers + size_t offset; // file offset (useless for you, may be zero for compressed objects) + ppuint length; // the length of the original object data + ppxref *xref; // cross reference table it belongs to + }; + + +XRef +---- + +Cross reference table is exposed as ``ppxref`` (incomplete type, you can only oprate on its pointer). +To get top document xref:: + + ppxref * ppdoc_xref (ppdoc *pdf); + +To get previous (older) xref:: + + ppxref * ppxref_prev (ppxref *xref); + +To find an object of a given refnumber:: + + ppref * ppxref_find (ppxref *xref, ppuint refnumber); + +[Note: since pplib v0.98 in case of documents with incremental update, ``ppxref_find()`` returns +the newest available version of a given object rather than the object in a given body.] + +PDF +--- + +PDF document is represented as ``ppdoc`` structure (incomplete type, you can only operate on its pointer). +To load a document from file:: + + ppdoc * ppdoc_load (const char *filename); + +To load a document from memory data:: + + ppdoc * ppdoc_mem (const void *data, size_t size); + +The data is assumed to be a buffer allocated with ``malloc`` - it is freed when destroying ``ppdoc``. + +Both loaders returns ``NULL`` on failure. + +To free ``ppdoc`` and all objects it refers to:: + + void ppdoc_free (ppdoc *pdf); + +So far we haven't mention about any explicit object reclaimers. There are no dedicated ``free`` functions +for other objects. You don't allocate or free objects yourself. ``ppdoc`` object is an owner of all +beings it refers to. It also means that every object described so far is alive as long as the containing +``ppdoc`` is alive. + +To access main PDF dicts:: + + ppdict * ppdoc_trailer(ppdoc *pdf); // returns top xref trailer dict + ppdict * ppdoc_catalog(ppdoc *pdf); // returns catalog referred from the trailer + ppdict * ppdoc_info(ppdoc *pdf); // returns info dict referred from the trailer + +To get the PDF version:: + + const char * ppdoc_version_string (ppdoc *pdf); // version string + int ppdoc_version_number (ppdoc *pdf, int *minor); // minor and major numbers + +To get the file size of the source PDF document:: + + size_t ppdoc_file_size (ppdoc *pdf); + +To get the number of objects in all xrefs:: + + ppuint ppdoc_objects (ppdoc *pdf); + +To get the approx usage of memory:: + + size_t ppdoc_memory (ppdoc *pdf, size_t *waste); + +Encryption +---------- + +``pplib`` handles encrypted (password protected) documents. If a document is encrypted, most of strings and streams are ciphered. +In that form they are unreadable and rather useless, you can't even rewrite such strings/streams as-is to a different PDF output. +It is a common practise to *protect* documents with an empty password. Such documents remain readable in Acrobat (just opens them without prompting +for a password), but some features (eg. printing) may restricted by the application. + +When ``pplib`` detects encryption, it follows Acrobat approach and first tries an empty password. If it succeeds, ``pplib`` proceeeds normally, providing +an access to decrypted strings and streams, as if they weren't ciphered. If the document is protected with non-empty password, ``pplib`` gives +a way to provide a password and proceed. Until you provide a password, ``ppdoc`` object returned by ``ppdoc_load()`` function has all object wntries +set to ``null``. + +After loading a document you should check encryption status with:: + + ppcrypt_status ppdoc_crypt_status (ppdoc *pdf); + +``ppcrypt_status`` (integer) may have the following values: + + ``PPCRYPT_NONE`` - no encryption, go ahead + ``PPCRYPT_DONE`` - encryption present but password succeeded, go ahead + ``PPCRYPT_PASS`` - encryption present, need non-empty password + ``PPCRYPT_FAIL`` - invalid or unsupported encryption (eg. undocumented in pdf spec) + +If a password is needed, you can provide one with:: + + ppcrypt_status ppdoc_crypt_pass (ppdoc *pdf, const void *userpass, size_t userpasslength, + const void *ownerpass, size_t ownerpasslength); + +Well, yes, there are actually two passwords in encrypted documents. Relation between them is obscure to me, but enough +to know that having one of them is enough to decrypt the document. If you know the password, you probably mean +``userpass``, in which case you should put ``NULL`` as ``ownerpass``. The function returns ``PPCRYPT_DONE`` if the password +succeeds and the previous status otherwise. Your custom loader function may look like that:: + + ppdoc *pdf; + pdf = ppdoc_load("file.pdf"); + if (pdf == NULL) + return NULL; + switch (ppdoc_crypt_status(pdf)) + { + case PPCRYPT_NONE: + case PPCRYPT_DONE: + return pdf; + case PPCRYPT_PASS: + if (ppdoc_crypt_pass(pdf, "dummy", 5, NULL, 0) == PPCRYPT_DONE || + ppdoc_crypt_pass(pdf, NULL, 0, "dummy", 5) == PPCRYPT_DONE) + return pdf; + printf("sorry, password needed\n"); + ppdoc_free(pdf); + return NULL; + case PPCRYPT_FAIL: + printf("sorry, encryption failed\n"); + ppdoc_free(pdf); + return NULL; + } + +[If you get ``PPCRYPT_FAIL`` it might mean *I failed*, so treat as a bug.] + +If you'd like to know what permissions are given/restricted to encrypted document:: + + ppint ppdoc_permissions (ppdoc *pdf); + +Returned value can be queried with the following binary flags (you can verify with Acrobat *File -> Properties -> Security* tab):: + + PPDOC_ALLOW_PRINT // printing + PPDOC_ALLOW_MODIFY // filling form fields, signing, creating template pages + PPDOC_ALLOW_COPY // copying, copying for accessibility + PPDOC_ALLOW_ANNOTS // filling form fields, copying, signing + PPDOC_ALLOW_EXTRACT // contents copying for accessibility + PPDOC_ALLOW_ASSEMBLY // (no effect) + PPDOC_ALLOW_PRINT_HIRES // (no effect) + +``pplib`` does absolutelly nothing with permissions, it cares only to decrypt the document. As mentioned, encryption applies to strings +and streams. ``pplib`` decrypt strings when parsing document objects, so the result you get is *normal* (not ciphered). +Streams are decrypted whenever you access them. Even if you ask for a raw stream data, you'll get a raw (compressed) stream, but decrypted. +So except the check to ``ppdoc_crypt_status()``, you shouldn't bother about encryption. + +In encrypted documents most of streams are encrypted. To check if a given stream is encrypted:: + + ppstream_encrypted(stream) // macro, returns non-zero if encrypted + +Encryption is independent from compression, don't confuse with ``ppstream_compressed()`` + +Pages +----- + +Several helpers to deal with pages. To get the number of pages:: + + ppuint ppdoc_page_count (ppdoc *pdf); + +To access the root pages tree node:: + + ppref * ppdoc_pages(ppdoc *pdf); + +To get the page reference at a given index:: + + ppref * ppdoc_page (ppdoc *pdf, ppuint index); + +``index`` is a page number. First page has number 1. For index out of bounds ``ppdoc_page()`` returns NULL. +Iterating over pages using index from 1 to ``ppdoc_page_count()`` and calling ``ppdoc_page()`` on each iteration +would be suboptimal. Here is a dedicted iterator for this:: + + ppref * ppdoc_first_page (ppdoc *pdf); + ppref * ppdoc_next_page (ppdoc *pdf); + +The iterator in use:: + + ppdoc *pdf; + ppref *ref; + ppdict *dict; + int pageno; + + pdf = ppdoc_load("file.pdf"); + for (ref = ppdoc_first_page(pdf), pageno = 1; ref != NULL; ref = ppdoc_next_page(pdf), ++pageno) + { + dict = ppref_obj(obj)->dict; // take for granted it is a dict + // do something with the page dict + } + +Functions related to pages return ``ppref *`` ensured to contain dict object, so you don't need sanity +type checks here. + +Contents +-------- + +PDF page contents can be given as a stream or array of streams. Here is a convenience iterator over page +contents streams:: + + ppstream * ppcontents_first (ppdict *dict); + ppstream * ppcontents_next (ppdict *dict, ppstream *stream); + +A complete example of contents stream parser use is given below (example 2). +But before we get there, we need to introduce ``ppcontext`` object. Conceptually, +``ppcontext`` is an owner (memory handler) of objects created on demand (beyond the ``ppdoc``). +So far used only with contents stream parser, which might produce quite some data that we want +to release just after used. To create a new context:: + + pcontext * ppcontext_new (void); + +It initializes a new context and its internal memory heap, taking about 64kB on start. After that, +the context is ready to produce objects (contents parsing functions below). Once objects produced +from a given context are no longer needed:: + + void ppcontext_done (ppcontext *context); + +It restores the context to its initial state, as after ``ppcontext_new()``. It means that the context +is ready to produce another bunch of beings (in the example below, all objects from the next page contents). +Once the context is not needed anymore:: + + void ppcontext_free (ppcontext *context); + +Now, contents stream parser functions take the context as an argument. Iterator form of contents stream parser +that allows to process the contents operator by operator:: + + ppobj * ppcontents_first_op (ppcontext *context, ppstream *stream, size_t *psize, ppname *pname); + ppobj * ppcontents_next_op (ppcontext *context, ppstream *stream, size_t *psize, ppname *pname); + +Returned ``ppobj *`` is a pointer to operands list. ``*psize`` is the number of operands on stack. +The operator itself is stored as ``*pname``. + +To parse the entire contents stream at once with no stop at every operator:: + + ppobj * ppcontents_parse (ppcontext *context, ppstream *stream, size_t *psize); + +Returns probably quite long list of all parsed objects (operands and operatos) in one piece. +The number of objects is stored to ``*psize``. + +[Contents may contain so called inline images, that breaks a simple scheme of operands / operator syntax:: + + BI <keyval pairs> ID <binary image data> EI + +Contents parser treats this genuine triplet as a single piece, producing two operands (dict and string) +followed by ``EI`` operator name.] + +Boxes +----- + +Boxes (rectangles) in PDF are roughly 4-number arrays, but with a special intent. +``pplib`` provides a basic interface for these special arrays:: + + typedef struct { + ppnum lx, ly, rx, ry; + } pprect; + +This type is used only by helper functions - PDF parser is not aware of the rectangle type. +To convert ``pparray`` to ``pprect``:: + + pprect * pparray_to_rect (pparray *array, pprect *rect); // returns rect or NULL + +In example:: + + pprect rect; + if (pparray_to_rect(array, &rect) != NULL) + ; // do something with rect + +To get some image bounding box:: + + pprect * ppdict_get_rect (ppdict *dict, const char *name, pprect *rect); + // eg. ppdict_get_rect(imagedict, "BBox", &rect) + +To get some page box:: + + pprect * ppdict_get_box (ppdict *dict, const char *name, pprect *rect); + // eg. ppdict_get_box(pagedict, "MediaBox", &rect) + +The later not only checks the pagedict, but also goes through parent page nodes. + +Transforms +---------- + +Transformations are given as 6-number arrays, but with a special intent. +``pplib`` provides a basic interface for these special arrays:: + + typedef struct { + ppnum xx, xy, yx, yy, x, y; + } ppmatrix; + +This type is used only by helper functions - PDF parser is not aware of the matrix type. +To convert ``pparray`` to ``ppmatrix``:: + + ppmatrix * pparray_to_matrix (pparray *array, ppmatrix *matrix); + +In example:: + + ppmatrix matrix; + if (pparray_to_matrix(array, &matrix) != NULL) + ; // do something with matrix + +To get the matrix from dict:: + + ppmatrix * ppdict_get_matrix (ppdict *dict, const char *name, ppmatrix *matrix); + // eg. ppdict_get_matrix(imagedict, "Matrix", &matrix) + +Errors handling +--------------- + +``pplib`` is not verbose, but might happen that it needs to log some error message, eg. when parsing +of some PDF boject fails due to invalid offsets. By default, ``pplib`` prints the message to stdout, eg.:: + + invalid 123 0 R object at offset 123123 + +To replace the default logger, you can provide your own:: + + void pplog_callback (pplogger_callback logger, void *alien); + +``pplogger_callback`` is a function:: + + void your_callback (const char *message, void *alien); + +In example, to redirect messages to stderr you may define a function:: + + void your_callback (const char *message, void *alien) + { + fprintf((FILE *)alien, "\nooops: %s\n", message); + } + +Then set the callback somewhere before loading documents:: + + pplog_callback(your_callback, stderr); + +(example 2 uses that). + +To set the default log messages prefix, eg. ``pplib:``, use:: + + int pplog_prefix (const char *prefix) + +Default is empty. The function succeeds if provided prefix is reasonably short (less then 32 bytes). diff --git a/Build/source/libs/pplib/pplib-src/doc/ppapi-2.x.rst b/Build/source/libs/pplib/pplib-src/doc/ppapi-2.x.rst index c6779145a56..f04c10b514c 100644 --- a/Build/source/libs/pplib/pplib-src/doc/ppapi-2.x.rst +++ b/Build/source/libs/pplib/pplib-src/doc/ppapi-2.x.rst @@ -1,946 +1,946 @@ -
-``pplib`` 2.x
-=============
-
-``pplib`` is a library for raw PDF access. It parses PDF documents and provides an interface to access document structures in C.
-
-C-API
-=====
-
-Types
------
-
-``pplib`` defines several C-types to represent PDF types:
-
-- ``ppbyte`` - char
-- ``ppint`` - signed integer (``int64_t``)
-- ``ppnum`` - real number (double)
-- ``ppname`` - PDF name
-- ``ppstring`` - PDF string
-- ``pparray`` - PDF array
-- ``ppdict`` - PDF dict
-- ``ppstream`` - PDF stream
-- ``ppref`` - PDF indirect reference
-- ``ppobj`` - a container of all above
-
-Among ``ppint`` and ``ppnum``, we also use ``ppuint`` - unsigned integer (machine word, alias to ``size_t``).
-
-Other API types:
-
-- ``ppdoc`` - PDF document
-- ``ppxref`` - cross-references table
-- ``ppcontext`` - ... later
-- ``pprect`` - rectangle
-- ``ppmatrix`` - matrix
-
-Integer and number are as simple types. Names and strings used to be aliases to ``char *``
-in ``pplib 1.x``, now they are structures; all related API functions operate on pointers.
-Other types (array, dict, stream, reference, object container, xref, doc) are C-structures,
-and you operate it their pointers. So when you declare a simple type variable you say::
-
- ppuint u;
- ppnum n;
- ...
-
-And when you declare a compound type you operate on pointers::
-
- ppobj *obj;
- ppname *name;
- ppstring *string;
- pparray *array;
- ppdict *dict;
- ppstream *stream;
- ppref *ref;
- ppdoc *pdf;
-
-Most of those C-types are defined in library header ``ppapi.h`` (complete types). Some others are incomplete
-(eg. you can't say ``sizeof(ppdoc)`` or ``sizeof(ppxref)``). This is to avoid unnecesary dependencies in
-the header. The library itself uses ``pplib.h`` header but for auxilary applications including a standalone
-``ppapi.h`` header should be enough.
-
-``pplib`` was designed having **read-only** PDF access in mind. Even if some structure is completelly exposed,
-so that you can directly access its members, you should treat them as read-only. I don't make them ``const`` because
-then all variable declarations would need to be ``const``, which is annoying, and I'd need some trickery in the library
-internals to unconst. Besides, nothing is really const for C type casts.
-
-Object
-------
-
-A common container for all elementary PDF object types is ``ppobj`` structure. ``ppobj`` has a type identifier
-(integer) and union of values::
-
- struct ppobj {
- ppobjtp type;
- union {
- ppint integer;
- ppnum number;
- ppname *name;
- ppstring *string;
- pparray *array;
- ppdict *dict;
- ppstream *stream;
- ppref *ref;
- void *any;
- };
- };
-
-Object type is one of constants (enum)::
-
- PPNONE
- PPNULL
- PPBOOL
- PPINT
- PPNUM
- PPNAME
- PPSTRING
- PPARRAY
- PPDICT
- PPSTREAM
- PPREF
-
-The type determines the structure member you're allowed to access::
-
- ppobj *obj;
- ...
- switch (obj->type)
- {
- case PPNONE: // shouldn't actually happen, indicates some failure
- break;
- case PPNULL: // valid PDF null object, no value
- break;
- case PPBOOL: // do something with obj->integer (ppint), value 0 or 1
- break;
- case PPINT: // do something with obj->integer (ppint)
- break;
- case PPNUM: // do something with obj->number (ppnum)
- break;
- case PPNAME: // do something with obj->name (ppname *)
- break;
- case PPSTRING: // do something with obj->string (ppstring *)
- break;
- case PPARRAY: // do something with obj->array (pparray *)
- break;
- case PPDICT: // do something with obj->dict (ppdict *)
- break;
- case PPSTREAM: // do something with obj->stream (ppstream *)
- break;
- case PPREF: // do something with obj->ref (ppref *)
- break;
- }
-
-More often then not you know exactly what type of object value is expected, in which case
-you may use one of the following macros::
-
- // returns 1 if o->type is PPNULL
- int ppobj_get_null(o) \
-
- // if o->type is PPBOOL, sets int v to 0 or 1 and returns 1, 0 otherwise
- int ppobj_get_bool(o, v)
-
- // if o->type is PPINT, sets ppint v and returns 1, 0 otherwise
- int ppobj_get_int(o, v)
-
- // if o->type is PPINT and >= 0, sets ppuint v and returns 1, 0 otherwise
- int ppobj_get_uint(o, v)
-
- // if o->type is PPNUM or PPINT, sets ppnum v and returns 1, 0 otherwise
- int ppobj_get_num(o, v)
-
- // if o->type is PPNAME returns the name, NULL otherwise
- ppname * ppobj_get_name(o)
-
- // if o->type is PPSTRING returns the string, NULL otherwise
- ppstring * ppobj_get_string(o)
-
- // if o->type is PPARRAY returns the array, NULL otherwise
- pparray * ppobj_get_array(o)
-
- // if o->type is PPDICT returns the dict, NULL otherwise
- ppdict * ppobj_get_dict(o)
-
- // if o->type is PPSTREAM returns the stream, NULL otherwise
- ppstream * ppobj_get_stream(o)
-
- // if o->type is PPREF returns the reference, NULL otherwise
- ppref * ppobj_get_ref(o)
-
-Note the coercion from integer to real number, but not reverse. In practise, whenever you expect a real number,
-you should also handle integer (eg. '1' used instead of '1.0' is pretty common in PDF).
-
-It is a common case that the object is given as an indirect reference, but what you actually
-want is not the reference, but the object referred by it. Here is a helper for it::
-
- // if o->type is PPREF, returns what the reference points, otherwise returns o
- ppobj * ppobj_rget_obj(o)
-
-Also every ``ppobj_get_*`` macro has ``ppobj_rget_*`` counterpart that makes a check
-for the expected type, but if the object is PPREF, it jumps to the target object.
-So for example ``ppobj_rget_dict(obj)`` will return dict if ``obj`` is of type PPDICT
-or if it is of type PPREF and ``obj->ref`` hosts an object of type PPDICT.
-
-Names
------
-
-PDF names are represented as ``ppname`` pointer (``ppname`` used to be an alias to ``char *``, now it is a structure).
-To access the name data::
-
- ppbyte * ppname_data(name) // name->data, bytes array
-
-For convenient use in C, names are ``'\0'`` terminated. But to get the length of name better always use
-``ppname_size()`` macro. ``ppname`` object knows its size, don't use ``strlen()``::
-
- size_t ppname_size(ppname name); // name->size, the length of name in bytes
-
-In current implementation names are not hashed anyhow, so name-to-name comparison is not smarter than ``memcmp()``.
-Use macros::
-
- int ppname_is(ppname name, "literal"); // to compare ppname with C-literal string
- int ppname_eq(ppname name, ppname other); // to compare ppname with a different name
-
-If you use ``pplib`` to parse contents streams, you may need to distinguish names from operators
-(more precisely executable names). Names in PDF are preceeded by '/', executable names aren't. In both
-cases PDF parser will produce ``ppname`` but the result can be distingushed with::
-
- int ppname_exec(ppname name); // macro, returns non-zero if the name is executable
-
-Names are kept in their raw form, with possible PDF specific escapes (in text below we call it **encoded** form).
-Leading '/' is omitted. One may need a decoded name, with no PDF escapes.
-A pair of functions provides a simple interface to switch between those two forms::
-
- // these helpers rely on name->alterego member
- ppname * ppname_decoded (ppname *name); // returns decoded (unescaped) form of the name
- ppname * ppname_encoded (ppname *name); // returns encoded (escaped) form of the name
- ppbyte * ppname_decoded_data (ppname *name);
- ppbyte * ppname_encoded_data (ppname *name);
-
-In pretty most cases a PDF name contains only letters (no special characters, no escapes), so decoded and encoded forms are identical.
-In that case both functions simply return the argument. It is ok to call ``ppname_decoded()`` on already decoded form
-and ``ppname_encoded()`` on already encoded form. Both forms are produced by PDF objects parser, so accessing ``ppname`` alter ego
-in whatever direction needs no extra decoding or allocation costs (the cost is paid by parser).
-
-String
-------
-
-PDF strings have the same internal construction as names, so most of names description above applies to strings as well.
-``ppstring`` is a structure (used to be an alias to ``char *``). ``string->data`` is ``\0``-terminated c-array of ``ppbytes``.
-To get the data::
-
- ppbyte * ppstring_data(ppstring *string); // string->data, macro
-
-To get the size of the string::
-
- size_t ppstring_size(ppstring *string); // macro, returns the length of the string in bytes
-
-Strings are provided in their raw form, preserving PDF specific escapes, but with no
-``()`` or ``<>`` delims. To distinguish plain strings from hex strings::
-
- int ppstring_hex(ppstring string); // macro, returns non zero if hex string
-
-Or if you prefer::
-
- switch (ppstring_type(string))
- {
- case PPSTRING_PLAIN: // literal string, surrounded by ``(`` and ``)`` in PDF
- break;
- case PPSTRING_BASE16: // hex string, surrounded by ``<`` and ``>`` in PDF
- break;
- case PPSTRING_BASE85: // base85 string surrounded by ``<~`` and ``~>`` in PDF
- break;
- }
-
-The last is actually Postscript specific, not used in PDF, but I think it might appear in contents streams...
-No matter how the string is given in PDF (plain or hex), here are two functions to
-switch between encoded and decoded strings forms::
-
- ppstring * ppstring_decoded (ppstring *string); // returns decoded string possibly with PDF escapes
- ppstring * ppstring_encoded (ppstring *string); // returns encoded string with no PDF escapes
- ppbyte * ppstring_decoded_data (ppstring *string);
- ppbyte * ppstring_encoded_data (ppstring *string);
-
-For hex strings, encoded form contains hex digits, while decoded form contains arbitrary bytes (the result of hex decoding).
-Plain strings usually contains printable ASCII characters, but they might contain any binary data.
-As with names, objects parser produces both forms. The raw form with PDF escapes (or raw hex form) the main one.
-Eg. when you access ``obj->string`` you always get the encoded form. At any moment you can switch to its alter ego.
-
-No matter if the string is plain or hex, if its first two bytes (decoded) are UTF16 BOM, the string is unicode.
-``ppstring`` object *knows* it is unicode or not::
-
- switch (ppstring_utf(string))
- {
- case PPSTRING_UTF16LE: // unicode string, utf16le
- break;
- case PPSTRING_UTF16BE: // unicode string, utf16be
- break;
- default: // no unicode
- }
-
-Or simply::
-
- if (ppstring_utf(string) != 0) {
- // handle unicode string
- }
-
-If the string is unicode, BOM remains the part of the string -- ``pplib`` parser does not strip it.
-Unicode or not, encoded or decoded, strings are always C-arrays of bytes and ``ppstring_size()``
-always returns the size in bytes.
-
-Array
------
-
-PDF arrays are represented as ``pparray`` type, which is C-array of ``ppobj`` structures.
-To get the size::
-
- size_t pparray_size(pparray *array) // macro, returns the number of array items
-
-To get ``ppobj *`` at a given index::
-
- ppobj * pparray_at(array, index) // macro, returns ppobj * (no index check)
- ppobj * pparray_get(array, index) // macro, returns ppobj * or NULL (with index check)
- ppobj * pparray_get_obj (pparray *array, size_t index); // function equiv to pparray_get()
-
-Iterating over array elements::
-
- pparray *array;
- size_t index, size;
- ppobj *obj;
- for (size = pparray_size(array), pparray_first(array, index, obj); index < size; pparray_next(index, obj))
- {
- // do something with index and obj
- }
-
-There is no magic first/next macros, just iteration over pointers. One could also use something like::
-
- for (index = 0, size = array->size; index < size; ++index)
- {
- obj = pparray_at(array, index);
- // do something with index and obj
- }
-
-When getting values from array and expecting a result of known type, use one of the following::
-
- int pparray_get_bool (pparray *array, size_t index, int *v); // get boolean value
- int pparray_get_int (pparray *array, size_t index, ppint *v); // get ppint value
- int pparray_get_uint (pparray *array, size_t index, ppuint *v); // get ppuint value
- int pparray_get_num (pparray *array, size_t index, ppnum *v); // get ppnum value
- ppname * pparray_get_name (pparray *array, size_t index); // get ppname * value
- ppstring * pparray_get_string (pparray *array, size_t index); // get ppstring * value
- pparray * pparray_get_array (pparray *array, size_t index); // get pparray * value
- ppdict * pparray_get_dict (pparray *array, size_t index); // get ppdict * value
- ppref * pparray_get_ref (pparray *array, size_t index); // get ppref * value
-
-As with ``ppobj_get_*`` suite, numeric types getters set the value of a given type and returns 1, if the type matches.
-Otherwise sets nothing and returns 0. Other getters return the value if the type matches, or NULL.
-
-Every function from ``pparray_get_*`` suite have its ``pparray_rget_*`` counterpart
-that dereferences indirect objects (as explained for ``ppobj_rget_*`` getters). Note that
-there is no ``pparray_get_stream()`` function, as streams in PDF are always indirect
-(may only reside in ``ref->object.stream``). To get the stream from array use::
-
- ppstream * pparray_rget_stream (pparray *array, size_t index);
-
-Dict
-----
-
-PDF dicts are represented as ``ppdict`` structure, which is C-array of ``ppobj`` with parallel
-C-array of ``ppname`` pointers. To get the size of a dict::
-
- size_t ppdict_size(ppdict *dict) // macro, returns the number of key-val pairs
-
-To get the value at a given index (integer)::
-
- ppobj * ppdict_at(ppdict *dict, index) // macro, no index bounds check
-
-To get the name (key) at a given index::
-
- ppname * ppdict_key(ppdict *dict, index) // macro, no index bounds check
-
-To iterate over dict key-val pairs::
-
- ppdict *dict;
- ppname **pkey;
- ppobj *obj;
-
- for (ppdict_first(dict, pkey, obj); *pkey != NULL; ppdict_next(pkey, obj))
- {
- // do something with *pkey and obj
- }
-
-There is no magic in first/next macros, just iteration through keys and values lists pointers.
-For convenient iteration, a list of keys is terminated with NULL, so in the code above ``*pkey != NULL``
-is used as the loop condition. One may also iterate via indices::
-
- ppdict *dict;
- size_t index, size;
- ppname *key;
- ppobj *obj;
- for (index = 0, size = ppdict_size(dict); index < size; ++index)
- {
- key = ppdict_key(dict, index);
- obj = ppdict_at(dict, index);
- // do something with key and obj
- }
-
-To get the object associated with a given name, use one of the following::
-
- ppobj * ppdict_get_obj (ppdict *dict, const char *name);
- int ppdict_get_bool (ppdict *dict, const char *name, int *v);
- int ppdict_get_int (ppdict *dict, const char *name, ppint *v);
- int ppdict_get_uint (ppdict *dict, const char *name, ppuint *v);
- int ppdict_get_num (ppdict *dict, const char *name, ppnum *v);
- ppname ppdict_get_name (ppdict *dict, const char *name);
- ppstring ppdict_get_string (ppdict *dict, const char *name);
- pparray * ppdict_get_array (ppdict *dict, const char *name);
- ppdict * ppdict_get_dict (ppdict *dict, const char *name);
- ppref * ppdict_get_ref (ppdict *dict, const char *name);
-
-Note that all getters accepts ``const char *`` as key, so it is ok to say::
-
- ppdict_rget_dict(dict, "Resources");
-
-(the most common use I guess). But to use ``ppname`` object as a key, one have to
-use data member::
-
- ppdic_rget_dict(dict, name->data); // ppname *name
-
-Every ``ppdict_get_*`` getter has ``ppdict_rget_*`` counterpart that dereferences
-indirect objects if necessary. Note that there is no ``ppdict_get_stream()`` function,
-but there is::
-
- ppstream * ppdict_rget_stream (ppdict *dict, const char *name);
-
-So far dicts comes with no names mapping, so by-name dict accessors perform a linear search
-through the keys list. PDF dicts are usually small.
-
-Stream
-------
-
-PDF streams are represented as ``ppstream`` objects. To get the stream dict::
-
- ppdict * ppstream_dict(ppstream *stream) // macro
-
-To read the stream data::
-
- uint8_t * ppstream_first (ppstream *stream, size_t *size, int decode);
- uint8_t * ppstream_next (ppstream *stream, size_t *size);
- void ppstream_done (ppstream *stream);
-
-Both ``first` and ``next`` functions return a chunk of stream data and sets the ``size`` of the chunk.
-``decode`` parameter tell the reader to decompress the stream (1) or return raw (0). A call to ``ppstream_next()``
-must be preceeded by ``ppstream_first()``. Once you're done with the stream, you have to call ``ppstream_done()``,
-no matter if the stream has been read to the end or not. The stream data iterator in use::
-
- uint8_t *data;
- size_t size;
- ppstream *stream;
- int decode = 1; // 1 - get decompressed, 0 - get raw
-
- for (data = ppstream_first(stream, &size, decode); data != NULL; data = ppstream_next(stream, &size))
- {
- // do something with data and its size
- }
- ppstream_done(stream);
-
-Every subsequent iterator call invalidates the previous reader output, so you have to utilize the returned chunk
-of data just after you ot that. So the following is wrong::
-
- data1 = ppstream_first(stream, &size, 1);
- data2 = ppstream_next(stream, &size);
- data3 = ppstream_next(stream, &size);
- some_output(data1, size);
- some_output(data2, size);
-
-The reader calls usually return the same pointer to internal buffer, just filled with a different data.
-``pplib`` allocates reasonably large buffer and fills that buffer on subsequent calls to the reader.
-
-If the source stream has no compression, using both ``decode == 1`` and ``decode == 0`` should give the same result.
-You can check if the stream is actually compressed with::
-
- ppstream_compressed(stream) // macro, returns non zero if /Filter is present
-
-It might be necessary to load the entire stream data at once::
-
- uint8_t * ppstream_all (ppstream *stream, size_t *size, int decode);
-
-If the initial buffer size is insufficient, it grows until the entire stream data is loaded. You must call
-``ppstream_done(stream)`` after using returned data.
-
-``ppstream_done()`` doesn't invalidate the stream object, it just closes its internal reader.
-The stream itself remains a valid object (eg. one can read it again if necessary),
-but the reader buffer is released. It is actually not freed but kept for future the reuse with that on some other stream,
-but you still need to mark it ready for reuse to avoid allocating a separate buffer for every stream you're going to read.
-
-Stream data readers will return ``NULL`` if you haven't close the previous reader process with ``ppstream_done()``. All below is wrong::
-
- data1 = ppstream_all(stream, &size, 1);
- data2 = ppstream_all(stream, &size, 1); // data2 == NULL
- // or
- data1 = ppstream_first(stream, &size, 1);
- data2 = ppstream_first(stream, &size, 1); // data2 == NULL
- // or
- data1 = ppstream_first(stream, &size, 1);
- data2 = ppstream_all(stream, &size, 1); // data2 == NULL
-
-To avoid unnecessary dependencies, ``pplib`` does not support image filters (``/DCT``, ``/JPX``, ``/JBIG``, ``/CCITT``).
-But it is ok to read the stream with ``decode`` set to 1 on such streams. ``pplib`` assumes that the image is the
-final/target stream form and just returns it as-is. Eg. in the case of JPEG (``/DCT`` filtered) image both calls should
-give the same results::
-
- ppstream_all(jpegstream, &jpegsize, 0); // don't decode, return what's there
- ppstream_all(jpegstream, &jpegsize, 1); // decode but found image filter, effectively the same
-
-A bit more about streams memory. As mentioned, ``pplib`` allocates buffers for stream readers. After ``ppstream_done()``,
-the stream no longer *owns* the buffer space. But the buffer may remain allocated, to be reused with future readers.
-``pplib`` keeps a pool of several buffers. This means, that when you use stream readers, ``pplib`` eats
-some memory (1MB or so) that is not freed, even if no streams are used. And even if you free all objects.
-If you suffer from this, you can optionally use a pair of functions::
-
- void ppstream_init_buffers (void);
- void ppstream_free_buffers (void);
-
-The first initializes buffers pool, unless done so far. Currently ``pplib`` cares of it before opening every stream reader,
-so it is not obligatory. The second frees a pool of buffers. The intended use is to call ``ppstream_init_buffers()`` once
-as kind of library initializer and to call ``ppstream_free_buffers()`` once, as the library finalizer.
-
-Filters
--------
-
-``ppstream`` knows its filter(s) and keps it as ``stream->filter``::
-
- // ppstream *stream;
- ppstream_filter *info = &stream->filter;
-
-``ppstream_filter`` is the following structure::
-
- typedef struct {
- ppstreamtp *filters; // c-array of filter identifiers (enum integers)
- ppdict **params; // c-array of ppdict pointers
- size_t count; // number of filters, length of the arrays (typically 1)
- } ppstream_filter;
-
-If ``count > 0`` then ``filters`` member is not NULL. Filters array keeps integer constants::
-
- PPSTREAM_BASE16 /* /ASCIIHexDecode */
- PPSTREAM_BASE85 /* /ASCII85Decode */
- PPSTREAM_RUNLENGTH /* /RunLengthDecode */
- PPSTREAM_FLATE /* /FlateDecode */
- PPSTREAM_LZW /* /LZWDecode */
- PPSTREAM_CCITT /* /CCITTFaxDecode */
- PPSTREAM_DCT /* /DCTDecode */
- PPSTREAM_JBIG2 /* /JBIG2Decode */
- PPSTREAM_JPX /* /JPXDecode */
- PPSTREAM_CRYPT /* /Crypt */
-
-Params array keeps corresponding filter parameters (``/DecodeParms``) if present. ``params`` member is not NULL
-if ``count > 0`` and the stream dict has ``/DecodeParms`` entry. Even if ``params`` is there,
-for every N-th filter, ``params[N]`` may be NULL (corresponding to PDF ``null``).
-
-``stream->filter`` keeps the source stream filter information, which may not correspond to the result of stream readers
-(``ppstream_first()``, ``ppstream_next()``, ``ppstream_all()``). The get the filters info relevant to the result from readers::
-
- void ppstream_filter_info (ppstream *stream, ppstream_filter *info, int decode);
-
-The function fills ``ppstream_filter`` structure according to the expected result from stream readers (example 3 shows
-how to use it to reconstruct ``/Filter`` and ``/DecodeParms`` when copying the stream to some other PDF).
-
-To convert filter identifier (``ppstreamtp``) to a corresponding PDF filter name::
-
- const char * ppstream_filter_name[];
-
-To covert ``ppname`` to filter identifier::
-
- int ppstream_filter_type (ppname filtername, ppstreamtp *filtertype);
- // returns 1 and sets filtertype if filtername is the proper filter name
-
-Additional information about the stream can be fetched from macros::
-
- ppstream_compressed(stream) /* stream->flags & (PPSTREAM_FILTER|PPSTREAM_IMAGE) */
- ppstream_filtered(stream) /* stream->flags & PPSTREAM_FILTER */
- ppstream_image(stream) /* stream->flags * PPSTREAM_IMAGE */
-
-``stream->flags`` is a binary sum of the following::
-
- PPSTREAM_FILTER /* set iff the stream filters list has one of: BASE16, BASE85, RUNLENGTH, FLATE, LZW */
- PPSTREAM_IMAGE /* set iff the stream filters list has one of: CCITT, DCT, JBIG2, JPX */
- PPSTREAM_ENCRYPTED /* set iff the stream is encrypted */
- PPSTREAM_ENCRYPTED_OWN /* set iff the stream has own CRYPT filter */
-
-Note that ``PPSTREAM_COMPRESSED`` is not there any longer, use ``ppstream_compressed()`` instead.
-And there is some more, see ``ppapi.h``.
-
-Ref
----
-
-Indirect objects are represented as ``ppref`` structure. To get the object that the
-reference refers to::
-
- ppobj * ppref_obj(ppref *ref) // macro
-
-``ppref`` structure also keeps the reference number and version, a pointer to cross reference table it belongs
-to and others, but I guess you won't need anything but the referenced object. ``pplib`` parser resolves references
-on-fly. So if there is a dict with indirect objects::
-
- <<
- /Type /Page
- /Resources 123 0 R
- ...
- >>
-
-the parser will produce ``ppdict`` with ``Resources`` key pointing the proper ``ppref *`` value.
-If you need more, access ``ppref`` members::
-
- struct ppref {
- ppobj object; // target object
- ppuint number, version; // identifiers
- size_t offset; // file offset (useless for you, may be zero for compressed objects)
- ppuint length; // the length of the original object data
- ppxref *xref; // cross reference table it belongs to
- };
-
-
-XRef
-----
-
-Cross reference table is exposed as ``ppxref`` (incomplete type, you can only oprate on its pointer).
-To get top document xref::
-
- ppxref * ppdoc_xref (ppdoc *pdf);
-
-To get previous (older) xref::
-
- ppxref * ppxref_prev (ppxref *xref);
-
-To find an object of a given refnumber::
-
- ppref * ppxref_find (ppxref *xref, ppuint refnumber);
-
-[Note: since pplib v0.98 in case of documents with incremental update, ``ppxref_find()`` returns
-the newest available version of a given object rather than the object in a given body.]
-
-PDF
----
-
-PDF document is represented as ``ppdoc`` structure (incomplete type, you can only operate on its pointer).
-To load a document from file::
-
- ppdoc * ppdoc_load (const char *filename);
-
-To load a document from file handle::
-
- ppdoc * ppdoc_filehandle (FILE *file, int closefile); // closefile 1 to fclose() on end
-
-To load a document from memory data::
-
- ppdoc * ppdoc_mem (const void *data, size_t size);
-
-The data is assumed to be a buffer allocated with ``malloc`` - it is freed when destroying ``ppdoc``.
-
-Both loaders returns ``NULL`` on failure.
-
-To free ``ppdoc`` and all objects it refers to::
-
- void ppdoc_free (ppdoc *pdf);
-
-So far we haven't mention about any explicit object reclaimers. There are no dedicated ``free`` functions
-for other objects. You don't allocate or free objects yourself. ``ppdoc`` object is an owner of all
-beings it refers to. It also means that every object described so far is alive as long as the containing
-``ppdoc`` is alive.
-
-To access main PDF dicts::
-
- ppdict * ppdoc_trailer(ppdoc *pdf); // returns top xref trailer dict
- ppdict * ppdoc_catalog(ppdoc *pdf); // returns catalog referred from the trailer
- ppdict * ppdoc_info(ppdoc *pdf); // returns info dict referred from the trailer
-
-To get the PDF version::
-
- const char * ppdoc_version_string (ppdoc *pdf); // version string
- int ppdoc_version_number (ppdoc *pdf, int *minor); // minor and major numbers
-
-To get the file size of the source PDF document::
-
- size_t ppdoc_file_size (ppdoc *pdf);
-
-To get the number of objects in all xrefs::
-
- ppuint ppdoc_objects (ppdoc *pdf);
-
-To get the approx usage of memory::
-
- size_t ppdoc_memory (ppdoc *pdf, size_t *waste);
-
-Encryption
-----------
-
-``pplib`` handles encrypted (password protected) documents. If a document is encrypted, most of strings and streams are ciphered.
-In that form they are unreadable and rather useless, you can't even rewrite such strings/streams as-is to a different PDF output.
-It is a common practise to *protect* documents with an empty password. Such documents remain readable in Acrobat (just opens them without prompting
-for a password), but some features (eg. printing) may restricted by the application.
-
-When ``pplib`` detects encryption, it follows Acrobat approach and first tries an empty password. If it succeeds, ``pplib`` proceeeds normally, providing
-an access to decrypted strings and streams, as if they weren't ciphered. If the document is protected with non-empty password, you have to call
-``ppdoc_crypt_pass()``. Until you provide a password, ``ppdoc`` object returned by ``ppdoc_load()`` function has all object entries set to ``null``.
-
-Once the document is loaded, encryption status can be checked with::
-
- ppcrypt_status ppdoc_crypt_status (ppdoc *pdf);
-
-``ppcrypt_status`` (enum) may have the following values:
-
- ``PPCRYPT_NONE`` - no encryption, go ahead
- ``PPCRYPT_DONE`` - encryption present but password succeeded, go ahead
- ``PPCRYPT_PASS`` - encryption present, need non-empty password
- ``PPCRYPT_FAIL`` - invalid or unsupported encryption (eg. undocumented in pdf spec)
-
-If a password is needed, you can provide one with::
-
- ppcrypt_status ppdoc_crypt_pass (ppdoc *pdf, const void *userpass, size_t userpasslength,
- const void *ownerpass, size_t ownerpasslength);
-
-Providing one of two is enough to decrypt the document.
-It is ok to use the same password for owner and user -- ``pplib`` will try both.
-
-The function returns ``PPCRYPT_DONE`` if the password succeeds and the previous crypt status otherwise.
-
-Your custom loader function may look like that::
-
- ppdoc *pdf;
- pdf = ppdoc_load("file.pdf");
- if (pdf == NULL)
- return NULL;
- switch (ppdoc_crypt_status(pdf))
- {
- case PPCRYPT_NONE:
- case PPCRYPT_DONE:
- return pdf;
- case PPCRYPT_PASS:
- if (ppdoc_crypt_pass(pdf, "dummy", 5, "dummy", 5) == PPCRYPT_DONE)
- return pdf;
- printf("sorry, password needed\n");
- ppdoc_free(pdf);
- return NULL;
- case PPCRYPT_FAIL:
- printf("sorry, encryption failed\n");
- ppdoc_free(pdf);
- return NULL;
- }
-
-See ``pplib`` tests suite for a complete code.
-
-If you'd like to know what permissions are given/restricted to encrypted document::
-
- ppint ppdoc_permissions (ppdoc *pdf);
-
-Returned value can be queried with the following binary flags (you can verify with Acrobat *File -> Properties -> Security* tab)::
-
- PPDOC_ALLOW_PRINT // printing
- PPDOC_ALLOW_MODIFY // filling form fields, signing, creating template pages
- PPDOC_ALLOW_COPY // copying, copying for accessibility
- PPDOC_ALLOW_ANNOTS // filling form fields, copying, signing
- PPDOC_ALLOW_EXTRACT // contents copying for accessibility
- PPDOC_ALLOW_ASSEMBLY // (no effect)
- PPDOC_ALLOW_PRINT_HIRES // (no effect)
-
-``pplib`` does absolutelly nothing with permissions, it cares only to decrypt the document. As mentioned, encryption applies to strings
-and streams. ``pplib`` decrypt strings when parsing document objects, so the result you get is *normal* (not ciphered).
-Streams are decrypted whenever you access them. Even if you ask for a raw stream data, you'll get a raw (compressed) stream, but decrypted.
-So except the check to ``ppdoc_crypt_status()``, you shouldn't bother about encryption.
-
-In encrypted documents most of streams are encrypted. To check if a given stream is encrypted::
-
- ppstream_encrypted(stream) // macro, returns non-zero if encrypted
-
-Encryption is independent from compression, don't confuse with ``ppstream_compressed()``
-
-.. caution::
- Starting from ``pplib v2.10`` all passwords should be passed as ``UTF-8``.
- Earlier PDF encryption algorithms (/V 1..4, PDF 1.7) were based on ``PdfDocEncoding``.
- Newer algorithms (/V 5, PDF 1.8-2.0) expect Unicode encoded as ``UTF-8``.
- ``pplib`` API now expects ``UTF-8`` and if opening documents with older encryption methods,
- it tries to make a conversion to 8-bit encoding. In earlier versions ``pplib`` didn't
- make any password preprocessing, treating them as raw byte arrays.
- So in case of passwords with fancy characters, it may behave differently.
-
-Pages
------
-
-Several helpers to deal with pages. To get the number of pages::
-
- ppuint ppdoc_page_count (ppdoc *pdf);
-
-To access the root pages tree node::
-
- ppref * ppdoc_pages(ppdoc *pdf);
-
-To get the page reference at a given index::
-
- ppref * ppdoc_page (ppdoc *pdf, ppuint index);
-
-``index`` is a page number. First page has number 1. For index out of bounds ``ppdoc_page()`` returns NULL.
-Iterating over pages using index from 1 to ``ppdoc_page_count()`` and calling ``ppdoc_page()`` on each iteration
-would be suboptimal. Here is a dedicted iterator for this::
-
- ppref * ppdoc_first_page (ppdoc *pdf);
- ppref * ppdoc_next_page (ppdoc *pdf);
-
-The iterator in use::
-
- ppdoc *pdf;
- ppref *ref;
- ppdict *dict;
- int pageno;
-
- pdf = ppdoc_load("file.pdf");
- for (ref = ppdoc_first_page(pdf), pageno = 1; ref != NULL; ref = ppdoc_next_page(pdf), ++pageno)
- {
- dict = ppref_obj(obj)->dict; // take for granted it is a dict
- // do something with the page dict
- }
-
-Functions related to pages return ``ppref *`` ensured to contain dict object, so you don't need sanity
-type checks here.
-
-Contents
---------
-
-PDF page contents can be given as a stream or array of streams. Here is a convenience iterator over page
-contents streams::
-
- ppstream * ppcontents_first (ppdict *dict);
- ppstream * ppcontents_next (ppdict *dict, ppstream *stream);
-
-A complete example of contents stream parser use is given below (example 2).
-But before we get there, we need to introduce ``ppcontext`` object. Conceptually,
-``ppcontext`` is an owner (memory handler) of objects created on demand (beyond the ``ppdoc``).
-So far used only with contents stream parser, which might produce quite some data that we want
-to release just after used. To create a new context::
-
- pcontext * ppcontext_new (void);
-
-It initializes a new context and its internal memory heap, taking about 64kB on start. After that,
-the context is ready to produce objects (contents parsing functions below). Once objects produced
-from a given context are no longer needed::
-
- void ppcontext_done (ppcontext *context);
-
-It restores the context to its initial state, as after ``ppcontext_new()``. It means that the context
-is ready to produce another bunch of beings (in the example below, all objects from the next page contents).
-Once the context is not needed anymore::
-
- void ppcontext_free (ppcontext *context);
-
-Now, contents stream parser functions take the context as an argument. Iterator form of contents stream parser
-that allows to process the contents operator by operator::
-
- ppobj * ppcontents_first_op (ppcontext *context, ppstream *stream, size_t *psize, ppname *pname);
- ppobj * ppcontents_next_op (ppcontext *context, ppstream *stream, size_t *psize, ppname *pname);
-
-Returned ``ppobj *`` is a pointer to operands list. ``*psize`` is the number of operands on stack.
-The operator itself is stored as ``*pname``.
-
-To parse the entire contents stream at once with no stop at every operator::
-
- ppobj * ppcontents_parse (ppcontext *context, ppstream *stream, size_t *psize);
-
-Returns probably quite long list of all parsed objects (operands and operatos) in one piece.
-The number of objects is stored to ``*psize``.
-
-[Contents may contain so called inline images, that breaks a simple scheme of operands / operator syntax::
-
- BI <keyval pairs> ID <binary image data> EI
-
-Contents parser treats this genuine triplet as a single piece, producing two operands (dict and string)
-followed by ``EI`` operator name.]
-
-Boxes
------
-
-Boxes (rectangles) in PDF are roughly 4-number arrays, but with a special intent.
-``pplib`` provides a basic interface for these special arrays::
-
- typedef struct {
- ppnum lx, ly, rx, ry;
- } pprect;
-
-This type is used only by helper functions - PDF parser is not aware of the rectangle type.
-To convert ``pparray`` to ``pprect``::
-
- pprect * pparray_to_rect (pparray *array, pprect *rect); // returns rect or NULL
-
-In example::
-
- pprect rect;
- if (pparray_to_rect(array, &rect) != NULL)
- ; // do something with rect
-
-To get some image bounding box::
-
- pprect * ppdict_get_rect (ppdict *dict, const char *name, pprect *rect);
- // eg. ppdict_get_rect(imagedict, "BBox", &rect)
-
-To get some page box::
-
- pprect * ppdict_get_box (ppdict *dict, const char *name, pprect *rect);
- // eg. ppdict_get_box(pagedict, "MediaBox", &rect)
-
-The later not only checks the pagedict, but also goes through parent page nodes.
-
-Transforms
-----------
-
-Transformations are given as 6-number arrays, but with a special intent.
-``pplib`` provides a basic interface for these special arrays::
-
- typedef struct {
- ppnum xx, xy, yx, yy, x, y;
- } ppmatrix;
-
-This type is used only by helper functions - PDF parser is not aware of the matrix type.
-To convert ``pparray`` to ``ppmatrix``::
-
- ppmatrix * pparray_to_matrix (pparray *array, ppmatrix *matrix);
-
-In example::
-
- ppmatrix matrix;
- if (pparray_to_matrix(array, &matrix) != NULL)
- ; // do something with matrix
-
-To get the matrix from dict::
-
- ppmatrix * ppdict_get_matrix (ppdict *dict, const char *name, ppmatrix *matrix);
- // eg. ppdict_get_matrix(imagedict, "Matrix", &matrix)
-
-Errors handling
----------------
-
-``pplib`` is not verbose, but might happen that it needs to log some error message, eg. when parsing
-of some PDF boject fails due to invalid offsets. By default, ``pplib`` prints the message to stdout, eg.::
-
- invalid 123 0 R object at offset 123123
-
-To replace the default logger, you can provide your own::
-
- void pplog_callback (pplogger_callback logger, void *alien);
-
-``pplogger_callback`` is a function::
-
- void your_callback (const char *message, void *alien);
-
-In example, to redirect messages to stderr you may define a function::
-
- void your_callback (const char *message, void *alien)
- {
- fprintf((FILE *)alien, "\nooops: %s\n", message);
- }
-
-Then set the callback somewhere before loading documents::
-
- pplog_callback(your_callback, stderr);
-
-(example 2 uses that).
-
-To set the default log messages prefix, eg. ``pplib:``, use::
-
- int pplog_prefix (const char *prefix)
-
-Default is empty. The function succeeds if provided prefix is reasonably short (less then 32 bytes).
+ +``pplib`` 2.x +============= + +``pplib`` is a library for raw PDF access. It parses PDF documents and provides an interface to access document structures in C. + +C-API +===== + +Types +----- + +``pplib`` defines several C-types to represent PDF types: + +- ``ppbyte`` - char +- ``ppint`` - signed integer (``int64_t``) +- ``ppnum`` - real number (double) +- ``ppname`` - PDF name +- ``ppstring`` - PDF string +- ``pparray`` - PDF array +- ``ppdict`` - PDF dict +- ``ppstream`` - PDF stream +- ``ppref`` - PDF indirect reference +- ``ppobj`` - a container of all above + +Among ``ppint`` and ``ppnum``, we also use ``ppuint`` - unsigned integer (machine word, alias to ``size_t``). + +Other API types: + +- ``ppdoc`` - PDF document +- ``ppxref`` - cross-references table +- ``ppcontext`` - ... later +- ``pprect`` - rectangle +- ``ppmatrix`` - matrix + +Integer and number are as simple types. Names and strings used to be aliases to ``char *`` +in ``pplib 1.x``, now they are structures; all related API functions operate on pointers. +Other types (array, dict, stream, reference, object container, xref, doc) are C-structures, +and you operate it their pointers. So when you declare a simple type variable you say:: + + ppuint u; + ppnum n; + ... + +And when you declare a compound type you operate on pointers:: + + ppobj *obj; + ppname *name; + ppstring *string; + pparray *array; + ppdict *dict; + ppstream *stream; + ppref *ref; + ppdoc *pdf; + +Most of those C-types are defined in library header ``ppapi.h`` (complete types). Some others are incomplete +(eg. you can't say ``sizeof(ppdoc)`` or ``sizeof(ppxref)``). This is to avoid unnecesary dependencies in +the header. The library itself uses ``pplib.h`` header but for auxilary applications including a standalone +``ppapi.h`` header should be enough. + +``pplib`` was designed having **read-only** PDF access in mind. Even if some structure is completelly exposed, +so that you can directly access its members, you should treat them as read-only. I don't make them ``const`` because +then all variable declarations would need to be ``const``, which is annoying, and I'd need some trickery in the library +internals to unconst. Besides, nothing is really const for C type casts. + +Object +------ + +A common container for all elementary PDF object types is ``ppobj`` structure. ``ppobj`` has a type identifier +(integer) and union of values:: + + struct ppobj { + ppobjtp type; + union { + ppint integer; + ppnum number; + ppname *name; + ppstring *string; + pparray *array; + ppdict *dict; + ppstream *stream; + ppref *ref; + void *any; + }; + }; + +Object type is one of constants (enum):: + + PPNONE + PPNULL + PPBOOL + PPINT + PPNUM + PPNAME + PPSTRING + PPARRAY + PPDICT + PPSTREAM + PPREF + +The type determines the structure member you're allowed to access:: + + ppobj *obj; + ... + switch (obj->type) + { + case PPNONE: // shouldn't actually happen, indicates some failure + break; + case PPNULL: // valid PDF null object, no value + break; + case PPBOOL: // do something with obj->integer (ppint), value 0 or 1 + break; + case PPINT: // do something with obj->integer (ppint) + break; + case PPNUM: // do something with obj->number (ppnum) + break; + case PPNAME: // do something with obj->name (ppname *) + break; + case PPSTRING: // do something with obj->string (ppstring *) + break; + case PPARRAY: // do something with obj->array (pparray *) + break; + case PPDICT: // do something with obj->dict (ppdict *) + break; + case PPSTREAM: // do something with obj->stream (ppstream *) + break; + case PPREF: // do something with obj->ref (ppref *) + break; + } + +More often then not you know exactly what type of object value is expected, in which case +you may use one of the following macros:: + + // returns 1 if o->type is PPNULL + int ppobj_get_null(o) \ + + // if o->type is PPBOOL, sets int v to 0 or 1 and returns 1, 0 otherwise + int ppobj_get_bool(o, v) + + // if o->type is PPINT, sets ppint v and returns 1, 0 otherwise + int ppobj_get_int(o, v) + + // if o->type is PPINT and >= 0, sets ppuint v and returns 1, 0 otherwise + int ppobj_get_uint(o, v) + + // if o->type is PPNUM or PPINT, sets ppnum v and returns 1, 0 otherwise + int ppobj_get_num(o, v) + + // if o->type is PPNAME returns the name, NULL otherwise + ppname * ppobj_get_name(o) + + // if o->type is PPSTRING returns the string, NULL otherwise + ppstring * ppobj_get_string(o) + + // if o->type is PPARRAY returns the array, NULL otherwise + pparray * ppobj_get_array(o) + + // if o->type is PPDICT returns the dict, NULL otherwise + ppdict * ppobj_get_dict(o) + + // if o->type is PPSTREAM returns the stream, NULL otherwise + ppstream * ppobj_get_stream(o) + + // if o->type is PPREF returns the reference, NULL otherwise + ppref * ppobj_get_ref(o) + +Note the coercion from integer to real number, but not reverse. In practise, whenever you expect a real number, +you should also handle integer (eg. '1' used instead of '1.0' is pretty common in PDF). + +It is a common case that the object is given as an indirect reference, but what you actually +want is not the reference, but the object referred by it. Here is a helper for it:: + + // if o->type is PPREF, returns what the reference points, otherwise returns o + ppobj * ppobj_rget_obj(o) + +Also every ``ppobj_get_*`` macro has ``ppobj_rget_*`` counterpart that makes a check +for the expected type, but if the object is PPREF, it jumps to the target object. +So for example ``ppobj_rget_dict(obj)`` will return dict if ``obj`` is of type PPDICT +or if it is of type PPREF and ``obj->ref`` hosts an object of type PPDICT. + +Names +----- + +PDF names are represented as ``ppname`` pointer (``ppname`` used to be an alias to ``char *``, now it is a structure). +To access the name data:: + + ppbyte * ppname_data(name) // name->data, bytes array + +For convenient use in C, names are ``'\0'`` terminated. But to get the length of name better always use +``ppname_size()`` macro. ``ppname`` object knows its size, don't use ``strlen()``:: + + size_t ppname_size(ppname name); // name->size, the length of name in bytes + +In current implementation names are not hashed anyhow, so name-to-name comparison is not smarter than ``memcmp()``. +Use macros:: + + int ppname_is(ppname name, "literal"); // to compare ppname with C-literal string + int ppname_eq(ppname name, ppname other); // to compare ppname with a different name + +If you use ``pplib`` to parse contents streams, you may need to distinguish names from operators +(more precisely executable names). Names in PDF are preceeded by '/', executable names aren't. In both +cases PDF parser will produce ``ppname`` but the result can be distingushed with:: + + int ppname_exec(ppname name); // macro, returns non-zero if the name is executable + +Names are kept in their raw form, with possible PDF specific escapes (in text below we call it **encoded** form). +Leading '/' is omitted. One may need a decoded name, with no PDF escapes. +A pair of functions provides a simple interface to switch between those two forms:: + + // these helpers rely on name->alterego member + ppname * ppname_decoded (ppname *name); // returns decoded (unescaped) form of the name + ppname * ppname_encoded (ppname *name); // returns encoded (escaped) form of the name + ppbyte * ppname_decoded_data (ppname *name); + ppbyte * ppname_encoded_data (ppname *name); + +In pretty most cases a PDF name contains only letters (no special characters, no escapes), so decoded and encoded forms are identical. +In that case both functions simply return the argument. It is ok to call ``ppname_decoded()`` on already decoded form +and ``ppname_encoded()`` on already encoded form. Both forms are produced by PDF objects parser, so accessing ``ppname`` alter ego +in whatever direction needs no extra decoding or allocation costs (the cost is paid by parser). + +String +------ + +PDF strings have the same internal construction as names, so most of names description above applies to strings as well. +``ppstring`` is a structure (used to be an alias to ``char *``). ``string->data`` is ``\0``-terminated c-array of ``ppbytes``. +To get the data:: + + ppbyte * ppstring_data(ppstring *string); // string->data, macro + +To get the size of the string:: + + size_t ppstring_size(ppstring *string); // macro, returns the length of the string in bytes + +Strings are provided in their raw form, preserving PDF specific escapes, but with no +``()`` or ``<>`` delims. To distinguish plain strings from hex strings:: + + int ppstring_hex(ppstring string); // macro, returns non zero if hex string + +Or if you prefer:: + + switch (ppstring_type(string)) + { + case PPSTRING_PLAIN: // literal string, surrounded by ``(`` and ``)`` in PDF + break; + case PPSTRING_BASE16: // hex string, surrounded by ``<`` and ``>`` in PDF + break; + case PPSTRING_BASE85: // base85 string surrounded by ``<~`` and ``~>`` in PDF + break; + } + +The last is actually Postscript specific, not used in PDF, but I think it might appear in contents streams... +No matter how the string is given in PDF (plain or hex), here are two functions to +switch between encoded and decoded strings forms:: + + ppstring * ppstring_decoded (ppstring *string); // returns decoded string possibly with PDF escapes + ppstring * ppstring_encoded (ppstring *string); // returns encoded string with no PDF escapes + ppbyte * ppstring_decoded_data (ppstring *string); + ppbyte * ppstring_encoded_data (ppstring *string); + +For hex strings, encoded form contains hex digits, while decoded form contains arbitrary bytes (the result of hex decoding). +Plain strings usually contains printable ASCII characters, but they might contain any binary data. +As with names, objects parser produces both forms. The raw form with PDF escapes (or raw hex form) the main one. +Eg. when you access ``obj->string`` you always get the encoded form. At any moment you can switch to its alter ego. + +No matter if the string is plain or hex, if its first two bytes (decoded) are UTF16 BOM, the string is unicode. +``ppstring`` object *knows* it is unicode or not:: + + switch (ppstring_utf(string)) + { + case PPSTRING_UTF16LE: // unicode string, utf16le + break; + case PPSTRING_UTF16BE: // unicode string, utf16be + break; + default: // no unicode + } + +Or simply:: + + if (ppstring_utf(string) != 0) { + // handle unicode string + } + +If the string is unicode, BOM remains the part of the string -- ``pplib`` parser does not strip it. +Unicode or not, encoded or decoded, strings are always C-arrays of bytes and ``ppstring_size()`` +always returns the size in bytes. + +Array +----- + +PDF arrays are represented as ``pparray`` type, which is C-array of ``ppobj`` structures. +To get the size:: + + size_t pparray_size(pparray *array) // macro, returns the number of array items + +To get ``ppobj *`` at a given index:: + + ppobj * pparray_at(array, index) // macro, returns ppobj * (no index check) + ppobj * pparray_get(array, index) // macro, returns ppobj * or NULL (with index check) + ppobj * pparray_get_obj (pparray *array, size_t index); // function equiv to pparray_get() + +Iterating over array elements:: + + pparray *array; + size_t index, size; + ppobj *obj; + for (size = pparray_size(array), pparray_first(array, index, obj); index < size; pparray_next(index, obj)) + { + // do something with index and obj + } + +There is no magic first/next macros, just iteration over pointers. One could also use something like:: + + for (index = 0, size = array->size; index < size; ++index) + { + obj = pparray_at(array, index); + // do something with index and obj + } + +When getting values from array and expecting a result of known type, use one of the following:: + + int pparray_get_bool (pparray *array, size_t index, int *v); // get boolean value + int pparray_get_int (pparray *array, size_t index, ppint *v); // get ppint value + int pparray_get_uint (pparray *array, size_t index, ppuint *v); // get ppuint value + int pparray_get_num (pparray *array, size_t index, ppnum *v); // get ppnum value + ppname * pparray_get_name (pparray *array, size_t index); // get ppname * value + ppstring * pparray_get_string (pparray *array, size_t index); // get ppstring * value + pparray * pparray_get_array (pparray *array, size_t index); // get pparray * value + ppdict * pparray_get_dict (pparray *array, size_t index); // get ppdict * value + ppref * pparray_get_ref (pparray *array, size_t index); // get ppref * value + +As with ``ppobj_get_*`` suite, numeric types getters set the value of a given type and returns 1, if the type matches. +Otherwise sets nothing and returns 0. Other getters return the value if the type matches, or NULL. + +Every function from ``pparray_get_*`` suite have its ``pparray_rget_*`` counterpart +that dereferences indirect objects (as explained for ``ppobj_rget_*`` getters). Note that +there is no ``pparray_get_stream()`` function, as streams in PDF are always indirect +(may only reside in ``ref->object.stream``). To get the stream from array use:: + + ppstream * pparray_rget_stream (pparray *array, size_t index); + +Dict +---- + +PDF dicts are represented as ``ppdict`` structure, which is C-array of ``ppobj`` with parallel +C-array of ``ppname`` pointers. To get the size of a dict:: + + size_t ppdict_size(ppdict *dict) // macro, returns the number of key-val pairs + +To get the value at a given index (integer):: + + ppobj * ppdict_at(ppdict *dict, index) // macro, no index bounds check + +To get the name (key) at a given index:: + + ppname * ppdict_key(ppdict *dict, index) // macro, no index bounds check + +To iterate over dict key-val pairs:: + + ppdict *dict; + ppname **pkey; + ppobj *obj; + + for (ppdict_first(dict, pkey, obj); *pkey != NULL; ppdict_next(pkey, obj)) + { + // do something with *pkey and obj + } + +There is no magic in first/next macros, just iteration through keys and values lists pointers. +For convenient iteration, a list of keys is terminated with NULL, so in the code above ``*pkey != NULL`` +is used as the loop condition. One may also iterate via indices:: + + ppdict *dict; + size_t index, size; + ppname *key; + ppobj *obj; + for (index = 0, size = ppdict_size(dict); index < size; ++index) + { + key = ppdict_key(dict, index); + obj = ppdict_at(dict, index); + // do something with key and obj + } + +To get the object associated with a given name, use one of the following:: + + ppobj * ppdict_get_obj (ppdict *dict, const char *name); + int ppdict_get_bool (ppdict *dict, const char *name, int *v); + int ppdict_get_int (ppdict *dict, const char *name, ppint *v); + int ppdict_get_uint (ppdict *dict, const char *name, ppuint *v); + int ppdict_get_num (ppdict *dict, const char *name, ppnum *v); + ppname ppdict_get_name (ppdict *dict, const char *name); + ppstring ppdict_get_string (ppdict *dict, const char *name); + pparray * ppdict_get_array (ppdict *dict, const char *name); + ppdict * ppdict_get_dict (ppdict *dict, const char *name); + ppref * ppdict_get_ref (ppdict *dict, const char *name); + +Note that all getters accepts ``const char *`` as key, so it is ok to say:: + + ppdict_rget_dict(dict, "Resources"); + +(the most common use I guess). But to use ``ppname`` object as a key, one have to +use data member:: + + ppdic_rget_dict(dict, name->data); // ppname *name + +Every ``ppdict_get_*`` getter has ``ppdict_rget_*`` counterpart that dereferences +indirect objects if necessary. Note that there is no ``ppdict_get_stream()`` function, +but there is:: + + ppstream * ppdict_rget_stream (ppdict *dict, const char *name); + +So far dicts comes with no names mapping, so by-name dict accessors perform a linear search +through the keys list. PDF dicts are usually small. + +Stream +------ + +PDF streams are represented as ``ppstream`` objects. To get the stream dict:: + + ppdict * ppstream_dict(ppstream *stream) // macro + +To read the stream data:: + + uint8_t * ppstream_first (ppstream *stream, size_t *size, int decode); + uint8_t * ppstream_next (ppstream *stream, size_t *size); + void ppstream_done (ppstream *stream); + +Both ``first` and ``next`` functions return a chunk of stream data and sets the ``size`` of the chunk. +``decode`` parameter tell the reader to decompress the stream (1) or return raw (0). A call to ``ppstream_next()`` +must be preceeded by ``ppstream_first()``. Once you're done with the stream, you have to call ``ppstream_done()``, +no matter if the stream has been read to the end or not. The stream data iterator in use:: + + uint8_t *data; + size_t size; + ppstream *stream; + int decode = 1; // 1 - get decompressed, 0 - get raw + + for (data = ppstream_first(stream, &size, decode); data != NULL; data = ppstream_next(stream, &size)) + { + // do something with data and its size + } + ppstream_done(stream); + +Every subsequent iterator call invalidates the previous reader output, so you have to utilize the returned chunk +of data just after you ot that. So the following is wrong:: + + data1 = ppstream_first(stream, &size, 1); + data2 = ppstream_next(stream, &size); + data3 = ppstream_next(stream, &size); + some_output(data1, size); + some_output(data2, size); + +The reader calls usually return the same pointer to internal buffer, just filled with a different data. +``pplib`` allocates reasonably large buffer and fills that buffer on subsequent calls to the reader. + +If the source stream has no compression, using both ``decode == 1`` and ``decode == 0`` should give the same result. +You can check if the stream is actually compressed with:: + + ppstream_compressed(stream) // macro, returns non zero if /Filter is present + +It might be necessary to load the entire stream data at once:: + + uint8_t * ppstream_all (ppstream *stream, size_t *size, int decode); + +If the initial buffer size is insufficient, it grows until the entire stream data is loaded. You must call +``ppstream_done(stream)`` after using returned data. + +``ppstream_done()`` doesn't invalidate the stream object, it just closes its internal reader. +The stream itself remains a valid object (eg. one can read it again if necessary), +but the reader buffer is released. It is actually not freed but kept for future the reuse with that on some other stream, +but you still need to mark it ready for reuse to avoid allocating a separate buffer for every stream you're going to read. + +Stream data readers will return ``NULL`` if you haven't close the previous reader process with ``ppstream_done()``. All below is wrong:: + + data1 = ppstream_all(stream, &size, 1); + data2 = ppstream_all(stream, &size, 1); // data2 == NULL + // or + data1 = ppstream_first(stream, &size, 1); + data2 = ppstream_first(stream, &size, 1); // data2 == NULL + // or + data1 = ppstream_first(stream, &size, 1); + data2 = ppstream_all(stream, &size, 1); // data2 == NULL + +To avoid unnecessary dependencies, ``pplib`` does not support image filters (``/DCT``, ``/JPX``, ``/JBIG``, ``/CCITT``). +But it is ok to read the stream with ``decode`` set to 1 on such streams. ``pplib`` assumes that the image is the +final/target stream form and just returns it as-is. Eg. in the case of JPEG (``/DCT`` filtered) image both calls should +give the same results:: + + ppstream_all(jpegstream, &jpegsize, 0); // don't decode, return what's there + ppstream_all(jpegstream, &jpegsize, 1); // decode but found image filter, effectively the same + +A bit more about streams memory. As mentioned, ``pplib`` allocates buffers for stream readers. After ``ppstream_done()``, +the stream no longer *owns* the buffer space. But the buffer may remain allocated, to be reused with future readers. +``pplib`` keeps a pool of several buffers. This means, that when you use stream readers, ``pplib`` eats +some memory (1MB or so) that is not freed, even if no streams are used. And even if you free all objects. +If you suffer from this, you can optionally use a pair of functions:: + + void ppstream_init_buffers (void); + void ppstream_free_buffers (void); + +The first initializes buffers pool, unless done so far. Currently ``pplib`` cares of it before opening every stream reader, +so it is not obligatory. The second frees a pool of buffers. The intended use is to call ``ppstream_init_buffers()`` once +as kind of library initializer and to call ``ppstream_free_buffers()`` once, as the library finalizer. + +Filters +------- + +``ppstream`` knows its filter(s) and keps it as ``stream->filter``:: + + // ppstream *stream; + ppstream_filter *info = &stream->filter; + +``ppstream_filter`` is the following structure:: + + typedef struct { + ppstreamtp *filters; // c-array of filter identifiers (enum integers) + ppdict **params; // c-array of ppdict pointers + size_t count; // number of filters, length of the arrays (typically 1) + } ppstream_filter; + +If ``count > 0`` then ``filters`` member is not NULL. Filters array keeps integer constants:: + + PPSTREAM_BASE16 /* /ASCIIHexDecode */ + PPSTREAM_BASE85 /* /ASCII85Decode */ + PPSTREAM_RUNLENGTH /* /RunLengthDecode */ + PPSTREAM_FLATE /* /FlateDecode */ + PPSTREAM_LZW /* /LZWDecode */ + PPSTREAM_CCITT /* /CCITTFaxDecode */ + PPSTREAM_DCT /* /DCTDecode */ + PPSTREAM_JBIG2 /* /JBIG2Decode */ + PPSTREAM_JPX /* /JPXDecode */ + PPSTREAM_CRYPT /* /Crypt */ + +Params array keeps corresponding filter parameters (``/DecodeParms``) if present. ``params`` member is not NULL +if ``count > 0`` and the stream dict has ``/DecodeParms`` entry. Even if ``params`` is there, +for every N-th filter, ``params[N]`` may be NULL (corresponding to PDF ``null``). + +``stream->filter`` keeps the source stream filter information, which may not correspond to the result of stream readers +(``ppstream_first()``, ``ppstream_next()``, ``ppstream_all()``). The get the filters info relevant to the result from readers:: + + void ppstream_filter_info (ppstream *stream, ppstream_filter *info, int decode); + +The function fills ``ppstream_filter`` structure according to the expected result from stream readers (example 3 shows +how to use it to reconstruct ``/Filter`` and ``/DecodeParms`` when copying the stream to some other PDF). + +To convert filter identifier (``ppstreamtp``) to a corresponding PDF filter name:: + + const char * ppstream_filter_name[]; + +To covert ``ppname`` to filter identifier:: + + int ppstream_filter_type (ppname filtername, ppstreamtp *filtertype); + // returns 1 and sets filtertype if filtername is the proper filter name + +Additional information about the stream can be fetched from macros:: + + ppstream_compressed(stream) /* stream->flags & (PPSTREAM_FILTER|PPSTREAM_IMAGE) */ + ppstream_filtered(stream) /* stream->flags & PPSTREAM_FILTER */ + ppstream_image(stream) /* stream->flags * PPSTREAM_IMAGE */ + +``stream->flags`` is a binary sum of the following:: + + PPSTREAM_FILTER /* set iff the stream filters list has one of: BASE16, BASE85, RUNLENGTH, FLATE, LZW */ + PPSTREAM_IMAGE /* set iff the stream filters list has one of: CCITT, DCT, JBIG2, JPX */ + PPSTREAM_ENCRYPTED /* set iff the stream is encrypted */ + PPSTREAM_ENCRYPTED_OWN /* set iff the stream has own CRYPT filter */ + +Note that ``PPSTREAM_COMPRESSED`` is not there any longer, use ``ppstream_compressed()`` instead. +And there is some more, see ``ppapi.h``. + +Ref +--- + +Indirect objects are represented as ``ppref`` structure. To get the object that the +reference refers to:: + + ppobj * ppref_obj(ppref *ref) // macro + +``ppref`` structure also keeps the reference number and version, a pointer to cross reference table it belongs +to and others, but I guess you won't need anything but the referenced object. ``pplib`` parser resolves references +on-fly. So if there is a dict with indirect objects:: + + << + /Type /Page + /Resources 123 0 R + ... + >> + +the parser will produce ``ppdict`` with ``Resources`` key pointing the proper ``ppref *`` value. +If you need more, access ``ppref`` members:: + + struct ppref { + ppobj object; // target object + ppuint number, version; // identifiers + size_t offset; // file offset (useless for you, may be zero for compressed objects) + ppuint length; // the length of the original object data + ppxref *xref; // cross reference table it belongs to + }; + + +XRef +---- + +Cross reference table is exposed as ``ppxref`` (incomplete type, you can only oprate on its pointer). +To get top document xref:: + + ppxref * ppdoc_xref (ppdoc *pdf); + +To get previous (older) xref:: + + ppxref * ppxref_prev (ppxref *xref); + +To find an object of a given refnumber:: + + ppref * ppxref_find (ppxref *xref, ppuint refnumber); + +[Note: since pplib v0.98 in case of documents with incremental update, ``ppxref_find()`` returns +the newest available version of a given object rather than the object in a given body.] + +PDF +--- + +PDF document is represented as ``ppdoc`` structure (incomplete type, you can only operate on its pointer). +To load a document from file:: + + ppdoc * ppdoc_load (const char *filename); + +To load a document from file handle:: + + ppdoc * ppdoc_filehandle (FILE *file, int closefile); // closefile 1 to fclose() on end + +To load a document from memory data:: + + ppdoc * ppdoc_mem (const void *data, size_t size); + +The data is assumed to be a buffer allocated with ``malloc`` - it is freed when destroying ``ppdoc``. + +Both loaders returns ``NULL`` on failure. + +To free ``ppdoc`` and all objects it refers to:: + + void ppdoc_free (ppdoc *pdf); + +So far we haven't mention about any explicit object reclaimers. There are no dedicated ``free`` functions +for other objects. You don't allocate or free objects yourself. ``ppdoc`` object is an owner of all +beings it refers to. It also means that every object described so far is alive as long as the containing +``ppdoc`` is alive. + +To access main PDF dicts:: + + ppdict * ppdoc_trailer(ppdoc *pdf); // returns top xref trailer dict + ppdict * ppdoc_catalog(ppdoc *pdf); // returns catalog referred from the trailer + ppdict * ppdoc_info(ppdoc *pdf); // returns info dict referred from the trailer + +To get the PDF version:: + + const char * ppdoc_version_string (ppdoc *pdf); // version string + int ppdoc_version_number (ppdoc *pdf, int *minor); // minor and major numbers + +To get the file size of the source PDF document:: + + size_t ppdoc_file_size (ppdoc *pdf); + +To get the number of objects in all xrefs:: + + ppuint ppdoc_objects (ppdoc *pdf); + +To get the approx usage of memory:: + + size_t ppdoc_memory (ppdoc *pdf, size_t *waste); + +Encryption +---------- + +``pplib`` handles encrypted (password protected) documents. If a document is encrypted, most of strings and streams are ciphered. +In that form they are unreadable and rather useless, you can't even rewrite such strings/streams as-is to a different PDF output. +It is a common practise to *protect* documents with an empty password. Such documents remain readable in Acrobat (just opens them without prompting +for a password), but some features (eg. printing) may restricted by the application. + +When ``pplib`` detects encryption, it follows Acrobat approach and first tries an empty password. If it succeeds, ``pplib`` proceeeds normally, providing +an access to decrypted strings and streams, as if they weren't ciphered. If the document is protected with non-empty password, you have to call +``ppdoc_crypt_pass()``. Until you provide a password, ``ppdoc`` object returned by ``ppdoc_load()`` function has all object entries set to ``null``. + +Once the document is loaded, encryption status can be checked with:: + + ppcrypt_status ppdoc_crypt_status (ppdoc *pdf); + +``ppcrypt_status`` (enum) may have the following values: + + ``PPCRYPT_NONE`` - no encryption, go ahead + ``PPCRYPT_DONE`` - encryption present but password succeeded, go ahead + ``PPCRYPT_PASS`` - encryption present, need non-empty password + ``PPCRYPT_FAIL`` - invalid or unsupported encryption (eg. undocumented in pdf spec) + +If a password is needed, you can provide one with:: + + ppcrypt_status ppdoc_crypt_pass (ppdoc *pdf, const void *userpass, size_t userpasslength, + const void *ownerpass, size_t ownerpasslength); + +Providing one of two is enough to decrypt the document. +It is ok to use the same password for owner and user -- ``pplib`` will try both. + +The function returns ``PPCRYPT_DONE`` if the password succeeds and the previous crypt status otherwise. + +Your custom loader function may look like that:: + + ppdoc *pdf; + pdf = ppdoc_load("file.pdf"); + if (pdf == NULL) + return NULL; + switch (ppdoc_crypt_status(pdf)) + { + case PPCRYPT_NONE: + case PPCRYPT_DONE: + return pdf; + case PPCRYPT_PASS: + if (ppdoc_crypt_pass(pdf, "dummy", 5, "dummy", 5) == PPCRYPT_DONE) + return pdf; + printf("sorry, password needed\n"); + ppdoc_free(pdf); + return NULL; + case PPCRYPT_FAIL: + printf("sorry, encryption failed\n"); + ppdoc_free(pdf); + return NULL; + } + +See ``pplib`` tests suite for a complete code. + +If you'd like to know what permissions are given/restricted to encrypted document:: + + ppint ppdoc_permissions (ppdoc *pdf); + +Returned value can be queried with the following binary flags (you can verify with Acrobat *File -> Properties -> Security* tab):: + + PPDOC_ALLOW_PRINT // printing + PPDOC_ALLOW_MODIFY // filling form fields, signing, creating template pages + PPDOC_ALLOW_COPY // copying, copying for accessibility + PPDOC_ALLOW_ANNOTS // filling form fields, copying, signing + PPDOC_ALLOW_EXTRACT // contents copying for accessibility + PPDOC_ALLOW_ASSEMBLY // (no effect) + PPDOC_ALLOW_PRINT_HIRES // (no effect) + +``pplib`` does absolutelly nothing with permissions, it cares only to decrypt the document. As mentioned, encryption applies to strings +and streams. ``pplib`` decrypt strings when parsing document objects, so the result you get is *normal* (not ciphered). +Streams are decrypted whenever you access them. Even if you ask for a raw stream data, you'll get a raw (compressed) stream, but decrypted. +So except the check to ``ppdoc_crypt_status()``, you shouldn't bother about encryption. + +In encrypted documents most of streams are encrypted. To check if a given stream is encrypted:: + + ppstream_encrypted(stream) // macro, returns non-zero if encrypted + +Encryption is independent from compression, don't confuse with ``ppstream_compressed()`` + +.. caution:: + Starting from ``pplib v2.10`` all passwords should be passed as ``UTF-8``. + Earlier PDF encryption algorithms (/V 1..4, PDF 1.7) were based on ``PdfDocEncoding``. + Newer algorithms (/V 5, PDF 1.8-2.0) expect Unicode encoded as ``UTF-8``. + ``pplib`` API now expects ``UTF-8`` and if opening documents with older encryption methods, + it tries to make a conversion to 8-bit encoding. In earlier versions ``pplib`` didn't + make any password preprocessing, treating them as raw byte arrays. + So in case of passwords with fancy characters, it may behave differently. + +Pages +----- + +Several helpers to deal with pages. To get the number of pages:: + + ppuint ppdoc_page_count (ppdoc *pdf); + +To access the root pages tree node:: + + ppref * ppdoc_pages(ppdoc *pdf); + +To get the page reference at a given index:: + + ppref * ppdoc_page (ppdoc *pdf, ppuint index); + +``index`` is a page number. First page has number 1. For index out of bounds ``ppdoc_page()`` returns NULL. +Iterating over pages using index from 1 to ``ppdoc_page_count()`` and calling ``ppdoc_page()`` on each iteration +would be suboptimal. Here is a dedicted iterator for this:: + + ppref * ppdoc_first_page (ppdoc *pdf); + ppref * ppdoc_next_page (ppdoc *pdf); + +The iterator in use:: + + ppdoc *pdf; + ppref *ref; + ppdict *dict; + int pageno; + + pdf = ppdoc_load("file.pdf"); + for (ref = ppdoc_first_page(pdf), pageno = 1; ref != NULL; ref = ppdoc_next_page(pdf), ++pageno) + { + dict = ppref_obj(obj)->dict; // take for granted it is a dict + // do something with the page dict + } + +Functions related to pages return ``ppref *`` ensured to contain dict object, so you don't need sanity +type checks here. + +Contents +-------- + +PDF page contents can be given as a stream or array of streams. Here is a convenience iterator over page +contents streams:: + + ppstream * ppcontents_first (ppdict *dict); + ppstream * ppcontents_next (ppdict *dict, ppstream *stream); + +A complete example of contents stream parser use is given below (example 2). +But before we get there, we need to introduce ``ppcontext`` object. Conceptually, +``ppcontext`` is an owner (memory handler) of objects created on demand (beyond the ``ppdoc``). +So far used only with contents stream parser, which might produce quite some data that we want +to release just after used. To create a new context:: + + pcontext * ppcontext_new (void); + +It initializes a new context and its internal memory heap, taking about 64kB on start. After that, +the context is ready to produce objects (contents parsing functions below). Once objects produced +from a given context are no longer needed:: + + void ppcontext_done (ppcontext *context); + +It restores the context to its initial state, as after ``ppcontext_new()``. It means that the context +is ready to produce another bunch of beings (in the example below, all objects from the next page contents). +Once the context is not needed anymore:: + + void ppcontext_free (ppcontext *context); + +Now, contents stream parser functions take the context as an argument. Iterator form of contents stream parser +that allows to process the contents operator by operator:: + + ppobj * ppcontents_first_op (ppcontext *context, ppstream *stream, size_t *psize, ppname *pname); + ppobj * ppcontents_next_op (ppcontext *context, ppstream *stream, size_t *psize, ppname *pname); + +Returned ``ppobj *`` is a pointer to operands list. ``*psize`` is the number of operands on stack. +The operator itself is stored as ``*pname``. + +To parse the entire contents stream at once with no stop at every operator:: + + ppobj * ppcontents_parse (ppcontext *context, ppstream *stream, size_t *psize); + +Returns probably quite long list of all parsed objects (operands and operatos) in one piece. +The number of objects is stored to ``*psize``. + +[Contents may contain so called inline images, that breaks a simple scheme of operands / operator syntax:: + + BI <keyval pairs> ID <binary image data> EI + +Contents parser treats this genuine triplet as a single piece, producing two operands (dict and string) +followed by ``EI`` operator name.] + +Boxes +----- + +Boxes (rectangles) in PDF are roughly 4-number arrays, but with a special intent. +``pplib`` provides a basic interface for these special arrays:: + + typedef struct { + ppnum lx, ly, rx, ry; + } pprect; + +This type is used only by helper functions - PDF parser is not aware of the rectangle type. +To convert ``pparray`` to ``pprect``:: + + pprect * pparray_to_rect (pparray *array, pprect *rect); // returns rect or NULL + +In example:: + + pprect rect; + if (pparray_to_rect(array, &rect) != NULL) + ; // do something with rect + +To get some image bounding box:: + + pprect * ppdict_get_rect (ppdict *dict, const char *name, pprect *rect); + // eg. ppdict_get_rect(imagedict, "BBox", &rect) + +To get some page box:: + + pprect * ppdict_get_box (ppdict *dict, const char *name, pprect *rect); + // eg. ppdict_get_box(pagedict, "MediaBox", &rect) + +The later not only checks the pagedict, but also goes through parent page nodes. + +Transforms +---------- + +Transformations are given as 6-number arrays, but with a special intent. +``pplib`` provides a basic interface for these special arrays:: + + typedef struct { + ppnum xx, xy, yx, yy, x, y; + } ppmatrix; + +This type is used only by helper functions - PDF parser is not aware of the matrix type. +To convert ``pparray`` to ``ppmatrix``:: + + ppmatrix * pparray_to_matrix (pparray *array, ppmatrix *matrix); + +In example:: + + ppmatrix matrix; + if (pparray_to_matrix(array, &matrix) != NULL) + ; // do something with matrix + +To get the matrix from dict:: + + ppmatrix * ppdict_get_matrix (ppdict *dict, const char *name, ppmatrix *matrix); + // eg. ppdict_get_matrix(imagedict, "Matrix", &matrix) + +Errors handling +--------------- + +``pplib`` is not verbose, but might happen that it needs to log some error message, eg. when parsing +of some PDF boject fails due to invalid offsets. By default, ``pplib`` prints the message to stdout, eg.:: + + invalid 123 0 R object at offset 123123 + +To replace the default logger, you can provide your own:: + + void pplog_callback (pplogger_callback logger, void *alien); + +``pplogger_callback`` is a function:: + + void your_callback (const char *message, void *alien); + +In example, to redirect messages to stderr you may define a function:: + + void your_callback (const char *message, void *alien) + { + fprintf((FILE *)alien, "\nooops: %s\n", message); + } + +Then set the callback somewhere before loading documents:: + + pplog_callback(your_callback, stderr); + +(example 2 uses that). + +To set the default log messages prefix, eg. ``pplib:``, use:: + + int pplog_prefix (const char *prefix) + +Default is empty. The function succeeds if provided prefix is reasonably short (less then 32 bytes). diff --git a/Build/source/libs/pplib/pplib-src/doc/ppcode.rst b/Build/source/libs/pplib/pplib-src/doc/ppcode.rst index e9f6dc7adbd..37a062e94be 100644 --- a/Build/source/libs/pplib/pplib-src/doc/ppcode.rst +++ b/Build/source/libs/pplib/pplib-src/doc/ppcode.rst @@ -1,101 +1,101 @@ -Examples
-========
-
-Example 1
----------
-
-.. literalinclude:: ../src/pptest1.c
-
-Example 2
----------
-
-.. literalinclude:: ../src/pptest2.c
-
-Example 3
----------
-
-.. literalinclude:: ../src/pptest3.c
-
-ppapi.h
--------
-
-.. literalinclude:: ../src/ppapi.h
-
-
-Changes
-=======
-
-v0.97
------
-First release integrated with luatex sources, plus portability changes from Luigi.
-
-v0.98
------
-Changed references resolving in case of incremental updates; tech notes ppxref_find() in ppxref.c.
-
-v0.99
------
-Fixed streams handling; null characters should NOT be gobbled after "stream" keyword
-
-v1.00
------
-Fixed streams handling (Luigi); object streams updated before other streams
-Revised streams handling, ppstream API extended
-
-v1.01
------
-Fixed names handling (thanks Hans); digits after '#' weren't skipped
-
-v1.02
------
-Fixed page finder (thanks Luigi)
-
-v1.03
------
-Fixed TIFF predictor (thanks folks)
-
-v1.04
------
-Fixed TIFF predictor for ARM
-
-v1.05
------
-Attempt to fix parsing inline images crap
-
-v2.00
------
-Deep rework on allocators.
-Deep rework on strings and names.
-
-v2.01
------
-Fixed invalid stream buffer handling; ``iof_discard()`` no longer reclaims the source (``filter->next``) filter.
-Sanity alignment adjustments in ``iof_heap``.
-
-v2.02
------
-Fixed incorrect encoding of strings alterego with octal escaping, thanks Luigi.
-On Hans request added ``ppdoc_filehandle()`` function and ``ppdoc_file()`` macro for loading ppdoc from ``FILE *``.
-
-v2.03
------
-Fixed alloc/free of ``ppdoc`` heap; ``ppdoc`` is now mallocated, no longer taken from its own heap. Again, thanks Luigi.
-Fixed warnings about dereferencing type-puned pointers, and some others.
-
-v2.04
------
-Byte lookups for names/strings loaders are now int8_t, as char might be signed.
-ppdoc_first_page() / ppdoc_next_page() iterator now handles a case when /Kids array is empty.
-Fixed generating keys for encrypted streams; ppstring_internal() returns the string of the proper size.
-More stream tests in pptest3.c.
-Some rework on md5 and sha2.
-
-v2.05
------
-uint8_t instead of ppbyte in internals; ppbyte intent is "the most natural 8-bit integer", so it is 'char',
-but internally we almost always need uint8_t (char may be signed or not..)
-
-v2.10
------
-Rework on encryption; algorithms /V5 /R6.
-Passwords passed to ppdoc_crypt_pass() should be UTF-8 (backward incompatible).
+Examples +======== + +Example 1 +--------- + +.. literalinclude:: ../src/pptest1.c + +Example 2 +--------- + +.. literalinclude:: ../src/pptest2.c + +Example 3 +--------- + +.. literalinclude:: ../src/pptest3.c + +ppapi.h +------- + +.. literalinclude:: ../src/ppapi.h + + +Changes +======= + +v0.97 +----- +First release integrated with luatex sources, plus portability changes from Luigi. + +v0.98 +----- +Changed references resolving in case of incremental updates; tech notes ppxref_find() in ppxref.c. + +v0.99 +----- +Fixed streams handling; null characters should NOT be gobbled after "stream" keyword + +v1.00 +----- +Fixed streams handling (Luigi); object streams updated before other streams +Revised streams handling, ppstream API extended + +v1.01 +----- +Fixed names handling (thanks Hans); digits after '#' weren't skipped + +v1.02 +----- +Fixed page finder (thanks Luigi) + +v1.03 +----- +Fixed TIFF predictor (thanks folks) + +v1.04 +----- +Fixed TIFF predictor for ARM + +v1.05 +----- +Attempt to fix parsing inline images crap + +v2.00 +----- +Deep rework on allocators. +Deep rework on strings and names. + +v2.01 +----- +Fixed invalid stream buffer handling; ``iof_discard()`` no longer reclaims the source (``filter->next``) filter. +Sanity alignment adjustments in ``iof_heap``. + +v2.02 +----- +Fixed incorrect encoding of strings alterego with octal escaping, thanks Luigi. +On Hans request added ``ppdoc_filehandle()`` function and ``ppdoc_file()`` macro for loading ppdoc from ``FILE *``. + +v2.03 +----- +Fixed alloc/free of ``ppdoc`` heap; ``ppdoc`` is now mallocated, no longer taken from its own heap. Again, thanks Luigi. +Fixed warnings about dereferencing type-puned pointers, and some others. + +v2.04 +----- +Byte lookups for names/strings loaders are now int8_t, as char might be signed. +ppdoc_first_page() / ppdoc_next_page() iterator now handles a case when /Kids array is empty. +Fixed generating keys for encrypted streams; ppstring_internal() returns the string of the proper size. +More stream tests in pptest3.c. +Some rework on md5 and sha2. + +v2.05 +----- +uint8_t instead of ppbyte in internals; ppbyte intent is "the most natural 8-bit integer", so it is 'char', +but internally we almost always need uint8_t (char may be signed or not..) + +v2.10 +----- +Rework on encryption; algorithms /V5 /R6. +Passwords passed to ppdoc_crypt_pass() should be UTF-8 (backward incompatible). diff --git a/Build/source/libs/pplib/pplib-src/doc/pplib.rst b/Build/source/libs/pplib/pplib-src/doc/pplib.rst index 763dc79cf62..b1eb82a1ebd 100644 --- a/Build/source/libs/pplib/pplib-src/doc/pplib.rst +++ b/Build/source/libs/pplib/pplib-src/doc/pplib.rst @@ -1,15 +1,15 @@ -.. pplib documentation master file, created by
- sphinx-quickstart on Thu Jun 07 14:23:51 2018.
- You can adapt this file completely to your liking, but it should at least
- contain the root `toctree` directive.
-
-pplib
-=====
-
-.. toctree::
- :maxdepth: 2
-
- ppnew
- ppapi-2.x
- ppapi-1.x
- ppcode
+.. pplib documentation master file, created by + sphinx-quickstart on Thu Jun 07 14:23:51 2018. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +pplib +===== + +.. toctree:: + :maxdepth: 2 + + ppnew + ppapi-2.x + ppapi-1.x + ppcode diff --git a/Build/source/libs/pplib/pplib-src/doc/ppnew.rst b/Build/source/libs/pplib/pplib-src/doc/ppnew.rst index 4a0a3b42887..b72d46bdac5 100644 --- a/Build/source/libs/pplib/pplib-src/doc/ppnew.rst +++ b/Build/source/libs/pplib/pplib-src/doc/ppnew.rst @@ -1,103 +1,103 @@ -
-1.x vs 2.x
-==========
-
-Allocation
-----------
-
-Allocation mechanisms has been revised. All objects are still allocated from a private storage (called heap),
-but now the heap serves properly aligned memory chunks. Implementation of the heap is (hopefully) platform
-independent, so all ``ARM_COMPLIANT`` checks has been removed. Some details work differently on 32/64-bit
-machines, this distinction seems inevitable. Allocation related code has been moved to ``util/utilmem*.c`` files.
-
-[There are actually 3 different allocators - **heap**, **stock**, and **pool** - each of which has 4 variants
-for 1, 2, 4 and 8 bytes alignment. So far ``pplib`` uses only the **heap**, but I want to have this part
-in a single place for a while. More notes about allocators in ``utilmemallc.h``.]
-
-``pplib`` uses two heaps:
-
-* bytes heap - providing 2-bytes aligned memory chunks for byte data
-* structures heap - providing 8-bytes aligned chunks for all structures
-
-2-bytes alignment of byte data is caused by implementation details / limits, ``pplib`` doesn't make a use of it
-(could be unaligned as well). All the structures are stored in 8-bytes aligned chunks on both 32 and 64-bit machines
-(in some structures we use ``double`` and ``int64_t``, which generally needs 8-bytes).
-
-Strings And Names
------------------
-
-So far, both ``ppname`` and ``ppstring`` were aliases to ``char *`` with an extra structure hidden just below
-the data address. The idea was to make a string or name usable whenever chars array can, at the cost of some
-pointers trickery. Both names and strings keep an information about pdf-encoded data, as well as plain bytes data.
-I implemented this feature once ``pplib 1.0`` was almost done, and to avoid a revolution, I made that with yet
-another trick. This all was dirty and caused lots of alignment issues.
-
-Now ``ppstring`` and ``ppname`` are **structures**, keeping data and size members, pretty much like ``pparray``::
-
- struct ppname {
- ppbyte *data;
- size_t size;
- ppname *alterego;
- int flags;
- };
-
- struct ppstring {
- ppbyte *data;
- size_t size;
- ppstring *alterego;
- int flags;
- };
-
-Data member is a pointer to (2-bytes aligned) bytes array -- ``ppbyte *``. ``ppbyte`` is an alias to ``char``.
-``pplib`` makes no assumptions about ``ppbyte`` signedness. [I'd prefer to have ``uint8_t``, but better
-keep that in sync with ``ppdict_get_*`` suite, which accepts ``char *``. Using ``"string literals"``
-with ``ppdict_get`` function is the most common case, I guess.]
-
-``ppname_size()`` and ``ppstring_size() `` now have
-trivial ``ppname_data()`` and ``ppstring_data()`` counterparts::
-
- #define ppname_size(name) ((name)->size)
- #define ppname_data(name) ((name)->data)
-
- #define ppstring_size(string) ((string)->size)
- #define ppstring_data(string) ((string)->data)
-
-Switching between encoded / decoded variants is made via explicit ``alterego`` member. If encoded and decoded forms
-are identical, then ``self->alfterego == self`` (never NULL). Helper functions for that::
-
- PPAPI ppname * ppname_decoded (ppname *name);
- PPAPI ppname * ppname_encoded (ppname *name);
-
- PPAPI ppbyte * ppname_decoded_data (ppname *name);
- PPAPI ppbyte * ppname_encoded_data (ppname *name);
-
- PPAPI ppstring * ppstring_decoded (ppstring *string);
- PPAPI ppstring * ppstring_encoded (ppstring *string);
-
- PPAPI ppbyte * ppstring_decoded_data (ppstring *string);
- PPAPI ppbyte * ppstring_encoded_data (ppstring *string);
-
-Since ``ppname`` and ``ppstring`` are now structures, all API functions returning name/string or taking name/string
-as an argument, now take **a pointer to name/string**. Watch out for ``ppdict_get_*`` functions suite. They still accept
-``const char *`` key as an argument, but ``ppname`` type can no longer be used there::
-
- ppname key;
- ppdict_get_something(dict, key); // wrong
- ppdict_get_something(dict, key.data); // ok
-
- ppname *pkey;
- ppdict_get_something(dict, (const char *)pkey); // wrong
- ppdict_get_something(dict, pkey->data); // ok
-
-Consequently, functions / macros that used pointer to ``ppname`` (``ppdict_first()`` / ``ppdict_next()``),
-now needs ``ppname **pname``.
-
-Cleanups
---------
-
-Some of unused utils were removed. There is still some code in utils part that is not used by the library,
-but I need this tollbox in many other places and don't want to maintain two versions.
-
-Some unification in integer types; ``size_t`` seems to be the best choice for and integer representing machine
-word (``unsigned long`` is not long enough on windows), less utils dependencies, less compiler warnings.
-
+ +1.x vs 2.x +========== + +Allocation +---------- + +Allocation mechanisms has been revised. All objects are still allocated from a private storage (called heap), +but now the heap serves properly aligned memory chunks. Implementation of the heap is (hopefully) platform +independent, so all ``ARM_COMPLIANT`` checks has been removed. Some details work differently on 32/64-bit +machines, this distinction seems inevitable. Allocation related code has been moved to ``util/utilmem*.c`` files. + +[There are actually 3 different allocators - **heap**, **stock**, and **pool** - each of which has 4 variants +for 1, 2, 4 and 8 bytes alignment. So far ``pplib`` uses only the **heap**, but I want to have this part +in a single place for a while. More notes about allocators in ``utilmemallc.h``.] + +``pplib`` uses two heaps: + +* bytes heap - providing 2-bytes aligned memory chunks for byte data +* structures heap - providing 8-bytes aligned chunks for all structures + +2-bytes alignment of byte data is caused by implementation details / limits, ``pplib`` doesn't make a use of it +(could be unaligned as well). All the structures are stored in 8-bytes aligned chunks on both 32 and 64-bit machines +(in some structures we use ``double`` and ``int64_t``, which generally needs 8-bytes). + +Strings And Names +----------------- + +So far, both ``ppname`` and ``ppstring`` were aliases to ``char *`` with an extra structure hidden just below +the data address. The idea was to make a string or name usable whenever chars array can, at the cost of some +pointers trickery. Both names and strings keep an information about pdf-encoded data, as well as plain bytes data. +I implemented this feature once ``pplib 1.0`` was almost done, and to avoid a revolution, I made that with yet +another trick. This all was dirty and caused lots of alignment issues. + +Now ``ppstring`` and ``ppname`` are **structures**, keeping data and size members, pretty much like ``pparray``:: + + struct ppname { + ppbyte *data; + size_t size; + ppname *alterego; + int flags; + }; + + struct ppstring { + ppbyte *data; + size_t size; + ppstring *alterego; + int flags; + }; + +Data member is a pointer to (2-bytes aligned) bytes array -- ``ppbyte *``. ``ppbyte`` is an alias to ``char``. +``pplib`` makes no assumptions about ``ppbyte`` signedness. [I'd prefer to have ``uint8_t``, but better +keep that in sync with ``ppdict_get_*`` suite, which accepts ``char *``. Using ``"string literals"`` +with ``ppdict_get`` function is the most common case, I guess.] + +``ppname_size()`` and ``ppstring_size() `` now have +trivial ``ppname_data()`` and ``ppstring_data()`` counterparts:: + + #define ppname_size(name) ((name)->size) + #define ppname_data(name) ((name)->data) + + #define ppstring_size(string) ((string)->size) + #define ppstring_data(string) ((string)->data) + +Switching between encoded / decoded variants is made via explicit ``alterego`` member. If encoded and decoded forms +are identical, then ``self->alfterego == self`` (never NULL). Helper functions for that:: + + PPAPI ppname * ppname_decoded (ppname *name); + PPAPI ppname * ppname_encoded (ppname *name); + + PPAPI ppbyte * ppname_decoded_data (ppname *name); + PPAPI ppbyte * ppname_encoded_data (ppname *name); + + PPAPI ppstring * ppstring_decoded (ppstring *string); + PPAPI ppstring * ppstring_encoded (ppstring *string); + + PPAPI ppbyte * ppstring_decoded_data (ppstring *string); + PPAPI ppbyte * ppstring_encoded_data (ppstring *string); + +Since ``ppname`` and ``ppstring`` are now structures, all API functions returning name/string or taking name/string +as an argument, now take **a pointer to name/string**. Watch out for ``ppdict_get_*`` functions suite. They still accept +``const char *`` key as an argument, but ``ppname`` type can no longer be used there:: + + ppname key; + ppdict_get_something(dict, key); // wrong + ppdict_get_something(dict, key.data); // ok + + ppname *pkey; + ppdict_get_something(dict, (const char *)pkey); // wrong + ppdict_get_something(dict, pkey->data); // ok + +Consequently, functions / macros that used pointer to ``ppname`` (``ppdict_first()`` / ``ppdict_next()``), +now needs ``ppname **pname``. + +Cleanups +-------- + +Some of unused utils were removed. There is still some code in utils part that is not used by the library, +but I need this tollbox in many other places and don't want to maintain two versions. + +Some unification in integer types; ``size_t`` seems to be the best choice for and integer representing machine +word (``unsigned long`` is not long enough on windows), less utils dependencies, less compiler warnings. + diff --git a/Build/source/libs/pplib/pplib-src/src/util/README.md b/Build/source/libs/pplib/pplib-src/src/util/README.md index 209bced0082..28f18ca6540 100644 --- a/Build/source/libs/pplib/pplib-src/src/util/README.md +++ b/Build/source/libs/pplib/pplib-src/src/util/README.md @@ -1,8 +1,8 @@ -# pplib util
-
-This part is a toolbox. Contains utilities that are used by `pplib`
-but aren't tightly related to `PDF`. I use the toolbox in different
-projects and repos. It is important to me to keep this part in a perfect
-sync, at the cost of some redundant code (not used in `pplib`).
-`pplib` is hopefully not a subject for eternal development, so once
-it become final, we will make some cleanups here.
+# pplib util + +This part is a toolbox. Contains utilities that are used by `pplib` +but aren't tightly related to `PDF`. I use the toolbox in different +projects and repos. It is important to me to keep this part in a perfect +sync, at the cost of some redundant code (not used in `pplib`). +`pplib` is hopefully not a subject for eternal development, so once +it become final, we will make some cleanups here. |