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
!=NULL
andfilter(fmt, field)
== 0, ignore this field - Set
bodySize
=0
; - If
body
!=NULL
, call it to write the field data;- Set
bodySize
to the return value ofbody
;
- Set
- If
prefix
!=NULL
, call it;- Note that
prefix
can accessbodySize
to know the number of bytes actually written bybody
, andsize
for the user-provided size information;
- Note that
- If
suffix
!=NULL
, call it;- Note that
suffix
can accessbodySize
to know the number of bytes actually written bybody
, andsize
for the user-provided size information;
- Note that
- Swap
body
andprefix
soprefix
is beforebody
on the output buffer.
- The formatting of the size and padding is independent of the formatting of the actual field data;
bodySize
rarely 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
body
that write the actual data and aprefix
and/orsuffix
that deals with the padding; - On the call to
prefix
orsuffix
thesize
field indicates the number given by the caller when filling the formatField_t structure, whilebodySize
is the actual number of bytes written bybody
; - Padding is usually done by a
suffix
that writessize - bodySize
bytes; prefix
can be used to write a size field with the actual number of bytes written, as stored inbodySize
;- A separator can be generated using the
suffix
function.
Unpacking
On a call to formatUnpack() the following algorithm is followed for each field:
- If
filter
!=NULL
andfilter(fmt, field)
== 0, ignore this field - Set
bodySize
=size
; - If
prefix
!=NULL
, call it;- If
prefix
deals with the actual field length, it must fillbodySize
with the number of bytes that need to be read!
- If
- If
body
!=NULL
, call it to read the field data;body
should always readbodySize
bytes, notsize
bytes;
- If
suffix
!=NULL
, call it;- Note that
suffix
can accessbodySize
to know the actual size ofbody
in bytes;
- Note that
- Remember that
prefix
should set thebodySize
field, and thatbody
must usebodySize
instead ofsize
to know how many bytes to read (ifprefix
isNULL
thenbodySize
=size
); - If
suffix
is 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
