A variable-length integer,
in the format used by the 0xfe chunks in the 'dcmp' (0)
and 'dcmp' (1)
resource compression formats.
See the dcmp_0 and dcmp_1 specs for more information about these compression formats.
This variable-length integer format can store an integer x
in any of the following ways:
0 <= x <= 0x7f
(7-bit unsigned integer)-0x4000 <= x <= 0x3eff
(15-bit signed integer with the highest 0x100
values unavailable)-0x80000000 <= x <= 0x7fffffff
(32-bit signed integer)In practice, values are always stored in the smallest possible format, but technically any of the larger formats could be used as well.
This page hosts a formal specification of Variable-length integer used in Apple `'dcmp' (0)` and `'dcmp' (1)` compressed resource formats using Kaitai Struct. This specification can be automatically translated into a variety of programming languages to get a parsing library.
import kaitai_struct_nim_runtime
import options
type
DcmpVariableLengthInteger* = ref object of KaitaiStruct
`first`*: uint8
`more`*: int32
`parent`*: KaitaiStruct
`valueInst`: int
`valueInstFlag`: bool
proc read*(_: typedesc[DcmpVariableLengthInteger], io: KaitaiStream, root: KaitaiStruct, parent: KaitaiStruct): DcmpVariableLengthInteger
proc value*(this: DcmpVariableLengthInteger): int
##[
A variable-length integer,
in the format used by the 0xfe chunks in the `'dcmp' (0)` and `'dcmp' (1)` resource compression formats.
See the dcmp_0 and dcmp_1 specs for more information about these compression formats.
This variable-length integer format can store an integer `x` in any of the following ways:
* In a single byte,
if `0 <= x <= 0x7f`
(7-bit unsigned integer)
* In 2 bytes,
if `-0x4000 <= x <= 0x3eff`
(15-bit signed integer with the highest `0x100` values unavailable)
* In 5 bytes, if `-0x80000000 <= x <= 0x7fffffff`
(32-bit signed integer)
In practice,
values are always stored in the smallest possible format,
but technically any of the larger formats could be used as well.
@see <a href="https://github.com/dgelessus/python-rsrcfork/blob/f891a6e/src/rsrcfork/compress/common.py">Source</a>
]##
proc read*(_: typedesc[DcmpVariableLengthInteger], io: KaitaiStream, root: KaitaiStruct, parent: KaitaiStruct): DcmpVariableLengthInteger =
template this: untyped = result
this = new(DcmpVariableLengthInteger)
let root = if root == nil: cast[DcmpVariableLengthInteger](this) else: cast[DcmpVariableLengthInteger](root)
this.io = io
this.root = root
this.parent = parent
##[
The first byte of the variable-length integer.
This determines which storage format is used.
* For the 1-byte format,
this encodes the entire value of the value.
* For the 2-byte format,
this encodes the high 7 bits of the value,
minus `0xc0`.
The highest bit of the value,
i. e. the second-highest bit of this field,
is the sign bit.
* For the 5-byte format,
this is always `0xff`.
]##
let firstExpr = this.io.readU1()
this.first = firstExpr
##[
The remaining bytes of the variable-length integer.
* For the 1-byte format,
this is not present.
* For the 2-byte format,
this encodes the low 8 bits of the value.
* For the 5-byte format,
this encodes the entire value.
]##
if this.first >= 128:
block:
let on = this.first
if on == 255:
let moreExpr = this.io.readS4be()
this.more = moreExpr
else:
let moreExpr = int32(this.io.readU1())
this.more = moreExpr
proc value(this: DcmpVariableLengthInteger): int =
##[
The decoded value of the variable-length integer.
]##
if this.valueInstFlag:
return this.valueInst
let valueInstExpr = int((if this.first == 255: this.more else: (if this.first >= 128: (((this.first shl 8) or this.more) - 49152) else: this.first)))
this.valueInst = valueInstExpr
this.valueInstFlag = true
return this.valueInst
proc fromFile*(_: typedesc[DcmpVariableLengthInteger], filename: string): DcmpVariableLengthInteger =
DcmpVariableLengthInteger.read(newKaitaiFileStream(filename), nil, nil)