bitgtkmm has been split from bit and can be found here.
The bit library now has official Fedora Extras RPMS for i386, x86_64 (amd64) and PPC platforms along with SRPMS for the rest.
Therefore, the bit Fedora RPMS at http://miskatonic.cs.nmsu.edu/pub/fedora will no longer be updated. The miskatonic repository isn't going away though. It will continue to host packages that aren't in Fedora Extras yet, such as bitgtkmm.
bit is a C++ library for manipulating buffers containing data fields that are not octet (byte) aligned.
Binary data formats containing fields that are not octet aligned are still common. One need look no further than the IP header that is present in every packet of data transmitted on the Internet. Additionally many embedded devices and sensors still communicate via binary formats, and it was for the latter (robotic sensors) that this library was initially developed.
The following example uses the IP packet header. This format contains four fields (version, header length, flags and fragment offset) that are not octet aligned.
| 0 | 4 | 8 | 16 | 19 | 31 | ||||||||||||||||||||||||||
| Version | IHL | Type of Service | Total Length | ||||||||||||||||||||||||||||
| Identification | Flags | Fragment Offset | |||||||||||||||||||||||||||||
| Time To Live | Protocol | Header Checksum | |||||||||||||||||||||||||||||
| Source IP Address | |||||||||||||||||||||||||||||||
| Destination IP Address | |||||||||||||||||||||||||||||||
| Options | Padding | ||||||||||||||||||||||||||||||
The traditional approach to unaligned bit fields is to use C's bit field syntax. The following C structure demonstrates this approach.
struct iphdr
{
unsigned int version:4;
unsigned int ihl:4;
u_int8_t tos;
u_int16_t tot_len;
u_int16_t id;
u_int8_t flags:3;
u_int16_t frag_off:13;
u_int8_t ttl;
u_int8_t protocol;
u_int16_t check;
u_int32_t saddr;
u_int32_t daddr;
/*The options start here. */
};
This is only slightly changed from what you will find in /usr/include/netinet/ip.h on a typical Linux system.
The only significant modification has been the addition of the flags field and the limitation of the frag_off field to thirteen bits. With this modification notice that a total of four fields are not octet aligned; version, ihl, flags and frag_off.
(For simplification I removed a few preprocessor directives that took into account big-endian vs. little-endian issues)
Discounting endian issues, assignment to/from unaligned (and aligned) fields is as simple as:
unsigned int header_length=12, fragment_offset; struct iphdr header; header.ihl = header_length; fragment_offset = header.frag_off;
This is a clean and efficient approach when the data format is known at compile time, but data format changes imply recompilation. Thus, the code is tied to the data format.
There are many reasons to separate data formats from code. These can include support for user specified data formats, or elimination of the need to recompile an application when data formats change. In my case, my dissertation area is rule-based visual languages and I needed something that could adapt at run-time when the programmer modified the visual environment.
The bit library provides several C++ classes that provide support for manipulating unaligned (and aligned) fields and the bit library allows data formats to be modified at run-time.
The bit library allows data formats to be specified at run-time through class methods or loaded from XML files at run-time (including any combinations thereof). Returning to the IP header example, the following XML chunk specifies the IP header format (the bit library's record format DTD has been left off):
<record name="IP">
<field name="Version" bits="4" />
<field name="IHL" bits="4" />
<field name="TOS" bits="8" />
<field name="TL" bits="16" />
<field name="Identification" bits="16" />
<field name="Flags" bits="3" />
<field name="FragOff" bits="13" />
<field name="TTL" bits="8" />
<field name="Protocol" bits="8" />
<field name="Checksum" bits="16" />
<field name="Source" bits="32" />
<field name="Destination" bits="32" />
</record>
The following illustrates the use of the bit library to perform the same assignments as the previous example based on C's bit fields:
unsigned int header_length=12, fragment_offset;
bit::RecordBuffer header; // the actual data 'chunk'
bit::Record fields; // contains a specific data format
format.load_xml("ip.xml"); // load the IP data format
header.set_fields(fields); // tell buffer to parse according to IP format
header["IHL"] = header_length;
fragment_offset = header["FragOff"];
speed_test ( found in examples/record ). This example will load the udp.xml specification file and parse an IP/UDP header 100,000 times. To run the test on your own, just run time ./speed_test and divide the running time by 100k to get an approximate value for the parse time.
An Athlon 64 3200+ was able to fully parse the entire IP/UDP header stack into component fields at the rate of ~140us per header (including byte-swapping and field clearing), or about 7142 headers per second.