pack: Binary encoding and decoding
This module provides low-level facilities for converting Alore objects to and from packed binary representations (this is called packing and unpacking, respectively). The packed representations are narrow strings that can written to files, sockets and other narrow streams. Strings containing character codes larger than 255 (wide strings) must be encoded before passing them to the packing methods (using the encodings module, for example).
This module is typically used for accessing and generating binary data using standard binary formats, for implementing binary network protocols and interoperating with lower-level languages such as C.
Pack formats
Binary data can be packed in several different formats. Some formats can only pack integer data, others floating point numbers, and finally there is a format for string data. There are no separate formats for different endiannesses — instead there are separate classes for packing and unpacking big endian and little endian data.
The table below contains descriptions of the supported formats, including sizes of the packed representations and the corresponding Alore types that can be packed into and unpacked from using each format (note that N in a format name must be replaced by a valid integer):
Format | Description | Packed bits | Packed bytes | Alore type |
---|---|---|---|---|
Byte | unsigned byte1 | 8 | 1 | Int |
WordN | unsigned integer | N (16, 32 or 64) | 2, 4, or 8 | Int |
IntN | signed integer2 | N (8, 16, 32 or 64) | 1, 2, 4 or 8 | Int |
FloatN | floating point number3 | N (32 or 64) | 4 or 8 | Float |
Str | narrow string | variable4 | variable4 | Str |
Notes:
1 | The Byte format is thus named for convenience; for consistency's sake it could equivalently have been named Word8. |
2 | Signed integer formats (Int8 to Int64) are encoded using the standard 2's complement encoding. |
3 | The Float32 and Float64 formats correspond to single and double precision IEEE floating point numbers, respectively. |
4 | The width of a Str format is always specified with an additional integer argument specifying the length of the packed string in bytes. When packing, input strings may be smaller than the length; they will be padded with spaces so that the desired length is reached. |
Packer classes
There are two concrete packer classes, one for the big-endian (network) byte order and other for the little-endian byte order. They both support the same methods; the common abstract superclass PackerBase defines these.
Class Packer
Inherits PackerBase
- class Packer()
- Construct a packer that packs and unpacks data in the big-endian (network) byte order.
Class LittleEndianPacker
Inherits PackerBase
- class LittleEndianPacker()
- Construct a packer that packs and unpacks data in the little-endian byte order.
Class PackerBase
This is an abstract base class of the packer classes.
Methods
Note: Instances of N in method names below must be replaced with an integer valid for the format. See the above table for details. For example, the actual methods for packing words are packWord16, packWord32 and packWord64.
- packByte(int as Int) as Str
- packWordN(int as Int) as Str
- packIntN(int as Int) as Str
- packFloatN(float as Float) as Str
- packStr(str as Str, len as Int) as Str
- packWordN(int as Int) as Str
- Pack a value in a specific format. The argument must have a compatible Alore type for the format (integers are also valid when floats are expected). The result is a narrow string.
- packBytes(array as Array<Int>) as Str
- packWordsN(array as Array<Int>) as Str
- packIntsN(array as Array<Int>) as Str
- packFloatsN(array as Array<Float>) as Str
- packStrs(array as Array<Str>, len as Int) as Str
- packWordsN(array as Array<Int>) as Str
- Pack an array of values in a specific format. The argument must be an array, and each array item must have a compatible Alore type for the format. The result is a narrow string that is the concatenation of the packed items.
- unpackByte(str as Str) as Int
- unpackWordN(str as Str) as Int
- unpackIntN(str as Str) as Int
- unpackFloatN(str as Str) as Float
- unpackStr(str as Str) as Str
- unpackWordN(str as Str) as Int
- Unpack a narrow string encoded in the format specified by the method name. The argument must have the correct length for the format. The Alore type of the result value is specified by the format.
- unpackBytes(str as Str) as Array<Int>
- unpackWordsN(str as Str) as Array<Int>
- unpackIntsN(str as Str) as Array<Int>
- unpackFloatsN(str as Str) as Array<Float>
- unpackStrs(str as Str, len as Int) as Array<Str>
- unpackWordsN(str as Str) as Array<Int>
- Unpack a narrow string that contains any number of values encoded in the format specified by the method name. The argument must have a valid length for the format (any multiple of the single item length). The result is an array of values whose type is specified by the format.
Examples
var p = Packer() p.packWord16(7) -- Result: "\u0000\u0007" p.packBytes([16, 128]) -- Result: "\u0010\u0080" p.unpackBytes("\u0010\u0080") -- Result: [16, 128] var pl = LittleEndianPacker() pl.packWord16(7) -- Result: "\u0007\u0000"
Class PackStream
Inherits Stream
- class PackStream(stream as Stream[, packer as PackerBase][, bufMode as Constant])
- Construct a PackStream instance that uses another stream for input/output. The packer argument, if present, must be a packer object. If omitted, the big endian packer will be used. The bufMode argument may be Buffered, LineBuffered or Unbuffered. If omitted, full buffering will be used.
PackStream methods
Note: Instances of N in method names below must be replaced with an integer valid for the format. See the above table for details. For example, the actual methods for writing words are writeWord16, writeWord32 and writeWord64.
- writeByte(int as Int)
- writeWordN(int as Int)
- writeIntN(int as Int)
- writeFloatN(float as Float)
- writeStr(str as Str, int as Int)
- writeWordN(int as Int)
- Pack data and write to the stream. The arguments are similar to the corresponding pack* methods (see above).
- writeBytes(array as Array<Int>)
- writeWordsN(array as Array<Int>)
- writeIntsN(array as Array<Int>)
- writeFloatsN(array as Array<Float>)
- writeStrs(array as Array<Str>, int as Str)
- writeWordsN(array as Array<Int>)
- Pack an array and write to the stream. The arguments are similar to the corresponding pack* methods (see above).
- readByte() as Int
- readWordN() as Int
- readIntN() as Int
- readFloatN() as Int
- readWordN() as Int
- Read and unpack data from the stream. The format specifies the number of characters (bytes) to read and the type of the return value.
- readBytes(n as Int) as Array<Int>
- readWordsN(n as Int) as Array<Int>
- readIntsN(n as Int) as Array<Int>
- readFloatsN(n as Int) as Array<Float>
- readStrs(n as Int, len as Int) as Array<Str>
- readWordsN(n as Int) as Array<Int>
- Read and unpack multiple data items from the stream. The format and the length argument specify the number of characters (bytes) to read and the length of the Array return value and the type of its items.
- eof() as Boolean
- seek(n as Int)
- close()
- seek(n as Int)
- Call the corresponding method of the underlying stream (if it is supported).
The inherited writing and reading methods (write, readLn, etc.) behave normally and can be used in addition to the PackStream specific input/output methods.
Class PackFile
Inherits PackStream
- class PackFile(path as Str[, packer as PackerBase], ... as Constant)
-
Open a binary file for reading and/or writing. The supported additional
arguments are the same as for io::File. The packer
argument, if present, must be a packer object (see above). If omitted,
the big endian packer will be used.
Example:
var f = PackFile("file.bin", Output) f.writeWord32(1234) f.writeBytes([1, 2, 3, 4]) f.close()
Constants
- HostByteOrderPacker as def () as PackerBase
- This constant refers to either Packer or LittleEndianPacker depending on the native byte order of the host system.
Exceptions
- class PackError
- Raised when a packer class gets invalid input and cannot perform packing or unpacking. Inherits from std::ValueError.