Dunstblick Data Types
This document contains descriptions of all data types used in the dunstblick project. It explains the encoding and data structures in network streams or on disk.
The document uses a C/C++ like syntax to document compound types with struct
definitions. Each struct is considered tightly packed with no padding between
each members, the members are stored in the order of declaration.
Code examples are also in a C/C++ like language using the C type names and operators.
Primitive Types
byte
A byte is the most basic unit and is an 8 bit unsigned integer ranging from 0 to 255.
uint
An up-to 32 bit unsigned integer encoded in 1 to 5 bytes. The encoding stores 7 bit per byte of use data, the most significant bit marks that more bytes are to follow. For each byte read this way, shift the currently decoded value 7 bits to the left and insert the read bits at the least significant position.
The encoding allows arbitrary bit widths for integers, but dunstblick restricts the numer of encoded bits to 32.
This encoding allows to store smaller numbers in a smaller amount of bytes than large numbers. As numbers larger than 5000 aren't common in user interfaces, most numbers can be encoded in one or two bytes.
Range | Number of bytes |
---|---|
0 … 127 | 1 |
128 … 16383 | 2 |
16384 … 2097151 | 3 |
2097152 … 268435455 | 4 |
268435456 … 4294967295 | 5 |
Reference implementation:
uint32_t decode_uint()
{
uint32_t number = 0;
uint8_t value;
do {
value = read_byte();
number <<= 7;
number |= value & 0x7F;
} while ((value & 0x80) != 0);
return number;
}
void encode_uint(uint32_t value)
{
uint8_t buf[5];
size_t maxidx = 4;
for (size_t n = 0; n < 5; n++) {
uint8_t c = (value >> (7 * n)) & 0x7F;
if (c != 0)
maxidx = 4 - n;
if (n > 0)
c |= 0x80;
buf[4 - n] = c;
}
assert(maxidx < 5);
write(buf + maxidx, 5 - maxidx);
}
int
A signed 32 bit integer encoded in a ZigZag pattern similar to the ProtoBuf signed integers:
Signed Original | Encoded As |
---|---|
0 | 0 |
-1 | 1 |
1 | 2 |
-2 | 3 |
2147483647 | 4294967294 |
-2147483648 | 4294967295 |
This is achieved by the following conversion:
uint32_t encode(int32_t n) {
int32_t encoded = (n << 1) ^ (n >> 31); // uses arithmetic shift/sign extend
return bitcast<uint32_t>(input);
}
This encoding allows storing numbers with a small absolute value in a smaller number of bytes than values with a high absolute value.
Two's complement is not a good encoding here as -1
would encode to 5 bytes
whereas 1
would encode to a single byte.
number
A floating point number encoded in little-endian IEEE 754 binary32.
chunk
A chunk is a sequence of bytes of unspecified length. The length is not encoded in the chunk itself and must be either well-known or stored in a previously encoded field.
Compound Types
string
A string is a sequence of bytes with a known length. The string is encoded as
the length encoded as an uint
followed by a chunk
of length bytes:
struct {
uint length;
byte data[length];
}
boolean
A boolean is encoded as a single byte where 0 is the false
value and
any other value encodes true
.
color
An sRGB color value with linear alpha.
struct {
byte r;
byte g;
byte b;
byte a;
}
size
The vertical and horizontal extends of a rectangle.
struct {
uint width;
uint height;
}
point
A coordinate on the 2D euclidean plane.
struct {
int x;
int y;
}
margins
Stores the margins of each rectangle edge. Each field stores the distance to the given edge of a rectangle.
struct {
int left;
int top;
int right;
int bottom;
}
sizelist
Used in the grid widget to configure the rows/columns of the grid and their respective sizes.
Sizelists store the number of rows/columns, the type for each element (auto
, expand
, size in pixels or size in percent) and the size for sized columns.
First, the number of elements is encoded as a uint
, followed by ceil(number/4)
bytes containing the size specification for each element:
The elements are encoded by two bits each, starting with the least significant bits and going up. If the number of elements is not divisible by 4, the rest of the bits is padded with zero.
After that, for each element which encodes a size in pixels, a uint
follows.
For each element in percent, a single byte follows, encoding the percentage
in the value range `0 … 100. The most significant bit is reserved for future use
and must be 0.
Element Type Encoding
Element Type | Bits |
---|---|
auto |
0b00 |
expand |
0b01 |
pixels |
0b10 |
percentage |
0b11 |
Example
The encoding of the list expand, auto, auto, 374px, 10%, 15%
is the following
byte sequence:
06 # length
81 0F # element encoding
82 76 # 374 pixels
10 # 10%
15 # 15%