pplib — pplib 0.1 documentation

# `pplib`

`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).