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.