Documentation to libpack

Template Format

The basic integer type codes and their corresponding C data types are:

Name Code Data type Size
Portable-sized types
Byte b uint8_t 8 bits
Word w uint16_t 16 bits
Double-word d uint32_t 32 bits
Quad-word q uint64_t 64 bits
Generic word u<n> as appropriate n bits
Platform-sized types
Char c char -
Short s short -
Integer i int -
Long l long -

The size of the portable types is fixed in bits, the size of the platform types depends on the platform. Currently, while libpack only supports platforms where CHAR_BITS is 8, the c and b types are identical. This may change in future as other architectures are supported, so be careful to use the correct one.

The generic unsigned word type u is followed by a number giving the size in bits. Currently restricted to the following equivalences:

Format Shortcut Bits
u8 b 8
u16 w 16
u32 d 32
u64 q 64

When packing, the value itself is passed to the *pack() function. When unpacking, a pointer to a variable of the appropriate type is passed to the *unpack() function.

To declare the endian direction of any of the portable types, the following characters can be specified:

Code Meaning
nothing Host endian
< Little endian
> Big endian

If host endian is used, no endian swapping will be performed. This option should be used with care - there are platforms that are neither little nor big endian, and in this case, the data written/read will be in a non-portable order. This might be useful though to transport data within one system but of a fixed bit size.

To specify array of one of the above integer types, the following formats can be used. In each case, t stands for any of the above letters which stand for integer types, and T stands for the associated C data type. 't stands for another, possibly different, integer type letter, and T' stands for its associated C data type. n stands for a decimal integer embedded directly in the template.

Name Template pack() arguments unpack() arguments
Fixed size t[n] T* T*
Variable size in argument t[] T*, int T*, int
Variable size in stream t[t'] T*, T' T*, T'*

During unpacking, the array must be big enough to store the number of elements written into it. In the case of t[t'], the size variable should be initialised with the maximum number of elements the array is able to hold. If the value read from the stream indicates that more elements are to be found, then extra elements that will not fit into the array are not stored there. In either case, the value of the size variable will contain the number that the stream indicated.

Finally, any template item can be followed by a decimal integer indicating a repeat count. The behaviour shall be identical to the behaviour for a template in which this item appears that number of times. Specifically, the absense of a number is equivalent to specifying 1, and specifying zero means that item is ignored.

Any amount of spaces, tabs and linefeeds may be present in the template. These are not considered significant and will be ignored.


size_t  snpack(char *buffer, size_t buflen, const char *tmpl, ...);
size_t vsnpack(char *buffer, size_t buflen, const char *tmpl, va_list args);

size_t  snunpack(const char *buffer, size_t buflen, const char *tmpl, ...);
size_t vsnunpack(const char *buffer, size_t buflen, const char *tmpl, va_list args);

size_t  fpack(FILE *file, const char *tmpl, ...);
size_t vfpack(FILE *file, const char *tmpl, va_list args);

size_t  funpack(FILE *file, const char *tmpl, ...);
size_t vfunpack(FILE *file, const char *tmpl, va_list args);

These functions form an orthogonal set similar to the printf()/scanf() set in standard libc. There does not exist a spack or sunpack function - the size of the string buffer must be explicitly declared in all cases.

The FILE* that is passed to the file versions does not need to seek()able. The only functions that will be called on them are fread() and fwrite().

The string versions of the pack functions will not NUL-terminate the buffer, nor will the unpack versions expect it.

Version 0.2 adds the concept of an abstract PackStream type, of which two implementations, one backed by a FILE*, and one backed by a string buffer, are created. These allow multiple pack/unpack operations to be done on a single stream at once.

PackStream *packstream_string_new(char *buffer, size_t buflen);
PackStream *packstream_conststring_new(const char *buffer, size_t buflen);
void        packstream_string_free(PackStream *stream);

PackStream *packstream_file_new(FILE *file);
void        packstream_file_free(PackStream *stream);

size_t  pack(PackStream *stream, const char *tmpl, ...);
size_t vpack(PackStream *stream, const char *tmpl, va_list args);

size_t  unpack(PackStream *stream, const char *tmpl, ...);
size_t vunpack(PackStream *stream, const char *tmpl, va_list args);

size_t packstream_remaining(PackStream *stream);

Version 0.3 adds a buffer-allocating version of snpack, which malloc()s a new buffer into a variable whose address is passed into it, which is big enough to store the stream. It also adds the ability for snpack()/vsnpack() to return the size of buffer which would be required, without actually filling one, by passing NULL as the buffer address.

size_t  aspack(char **bufferp, size_t maxlen, const char *tmpl, ...);
size_t vaspack(char **bufferp, size_t maxlen, const char *tmpl, va_list args);

Pass the value 0 as maxlen to allow any size of buffer, or limit it by passing a greater value.

TODOs and Future Directions

This area is a rough pad of notes largely to myself, of features still missing in this library, or things I will consider for addition at some point in the future.


Possible Future