|
LAR Library
1.14
|
Modules | |
| Field Formatting Functions | |
| Set of pre-defined formatting functions. | |
Data Structures | |
| struct | format_t |
| Overall parameters of a format session. More... | |
| struct | formatField_t |
| Information about each field to be read or written. More... | |
Enumerations | |
| enum | formatDirection_t { FORMAT_PACK, FORMAT_UNPACK } |
| Used as parameter to the formatting functions to inform if they should handle packing or unpacking. More... | |
Functions | |
| int | formatPack (format_t *fmt, uint8_t *output, int maxOutput) |
Write to output the packed values as described in fmt. More... | |
| int | formatUnpack (format_t *fmt, uint8_t *input, int inputSize) |
Read from input and unpack the fields to fmt. More... | |
Detailed Description
Rationale
One of the basic operations necessary to perform during communication and storage is generating a formatted buffer coalesced from many data items, perhaps with necessary conversions, for example ISO8583 message packing. This module is an extension of existing ISO8583 message-packing libraries, with additions so it can be used for other packing formats, and can be highly customized by the user.
Introduction
Formatting (or packing) a buffer is the generation of a buffer from a collection of (many) data elements possibly spread in many data structures, with added conversion and formatting. The inverse process is called unpacking.
The design of this module is such that the user needs to create and maintain a single table with the list of fields, and how to format each, and this same structure can be used both for packing and unpacking. Some pre-defined functions for this are included with the library (see Field Formatting Functions), but the user is free to create new ones.
See the documentation of formatField_t and format_t for information on how to fill those structures. See below for more information about how each field is used during packing and unpacking.
Packing
On a call to formatPack() the following algorithm is followed for each field:
- If
filter!=NULLandfilter(fmt, field)== 0, ignore this field - Set
bodySize=0; - If
body!=NULL, call it to write the field data;- Set
bodySizeto the return value ofbody;
- Set
- If
prefix!=NULL, call it;- Note that
prefixcan accessbodySizeto know the number of bytes actually written bybody, andsizefor the user-provided size information;
- Note that
- If
suffix!=NULL, call it;- Note that
suffixcan accessbodySizeto know the number of bytes actually written bybody, andsizefor the user-provided size information;
- Note that
- Swap
bodyandprefixsoprefixis beforebodyon the output buffer.
- The formatting of the size and padding is independent of the formatting of the actual field data;
bodySizerarely needs to be filled by the user, it is filled on runtime with the value returned bybody;- Fields that require padding to specific sizes can break this into a
bodythat write the actual data and aprefixand/orsuffixthat deals with the padding; - On the call to
prefixorsuffixthesizefield indicates the number given by the caller when filling the formatField_t structure, whilebodySizeis the actual number of bytes written bybody; - Padding is usually done by a
suffixthat writessize - bodySizebytes; prefixcan be used to write a size field with the actual number of bytes written, as stored inbodySize;- A separator can be generated using the
suffixfunction.
Unpacking
On a call to formatUnpack() the following algorithm is followed for each field:
- If
filter!=NULLandfilter(fmt, field)== 0, ignore this field - Set
bodySize=size; - If
prefix!=NULL, call it;- If
prefixdeals with the actual field length, it must fillbodySizewith the number of bytes that need to be read!
- If
- If
body!=NULL, call it to read the field data;bodyshould always readbodySizebytes, notsizebytes;
- If
suffix!=NULL, call it;- Note that
suffixcan accessbodySizeto know the actual size ofbodyin bytes;
- Note that
- Remember that
prefixshould set thebodySizefield, and thatbodymust usebodySizeinstead ofsizeto know how many bytes to read (ifprefixisNULLthenbodySize=size); - If
suffixis used for padding or separator, then it may only skip the necessary number of bytes;
Examples
Here we list a sample of common field types and a simple ISO8583-like field list with a few bits.
Fixed-size Fields
Fixed-size fields are fields where the number of bytes written by body is always equal to size as given by the user on the field table. This usually means that those fields include no prefix or suffix, but they may require a sufix function to write a fixed separator.
Example: a fixed-size field with 16 bytes.
Variable-size Fields
Variable-size fields require a size prefix to indicate the actual size of the body. Usually they are string data (as card-holder name) or numerical data without padding.
Example: a variable-size field of a string.
Padded Fields
Padded fields are a combination of fixed and variable-sized fields. They have a size prefix but are padded to fit exactly size bytes.
Example: a string field padded with spaces to 20 bytes.
Filtering
By filling the filter field of the format_t structure, the caller may allow conditional processing of fields. The most common use is during ISO8583 processing, but the system is flexible enough for other uses. During execution the filter function is called for each field, passing a pointer to both the format_t and the specific formatField_t.
A filter implementation may use the fieldMap pointer to store the set of allowed fields. For example, for ISO8583, the fieldMap could be a pointer to the actual ISO8583 bitmap as in the packed buffer.
A common framework is to use a body writer function that both pack/ unpack the bitmap and set the fieldMap field, for example:
Is a function that checks the bit field->index of fmt->fieldMap to choose if a field should or not be part of the packing/unpacking process.
In order for this to work, the user must also define, inside the field list, where the bitmap is stored, and properly associate the value of the fieldMap field. The following function does both:
And can be used as:
A simple body function
This is a simple function that could be used as the body of a field. It copies variable-sized zero-terminated strings:
Note how it return strlen() on packing, and both uses and return bodySize on unpack.
A simple prefix function
Following the example above, this is a prefix function that write the value of bodySize as a two-digit decimal number:
Note how it return the number of bytes read or written on both pack and unpack, and how it uses bodySize on packing and stores to it on unpacking. (This version uses the functions from Conversion routines).
A simple suffix function
Now a function that does padding with spaces: it writes enough spaces to compensate by the different between size and bodySize, if any.
Note how, on unpacking, the function ignores the actual buffer contents and just return how many bytes need to be skipped over.
A (small) complete example
Putting together the pieces above we can create a simple formatter table for a buffer with only variable-sized string fields.
First, define the list of fields and their format:
Create the format_t instance with the fields defined above:
Set the bits on iso_bitmap to identify which fields are part of the buffer. (When unpacking, the buffer is read from the input buffer).
Enumeration Type Documentation
| enum formatDirection_t |
Function Documentation
Write to output the packed values as described in fmt.
- Parameters
-
fmt format_t with packing parameters. output Where to store the packed message. maxOutput Size of output, in bytes.
- Returns
- Number of bytes writen on success.
- Negative on error.
Read from input and unpack the fields to fmt.
- Parameters
-
fmt format_t with packing parameters. input Where to read the packed message. inputSize Size of input, in bytes.
- Returns
- Number of bytes actually read from
input, on success. - Negative on error.
Generated on Mon Mar 27 2017 15:42:52 for LAR Library by
1.8.9.1