Module refinery.lib.unrar.reader
Bit-level I/O for RAR decompression.
Expand source code Browse git
"""
Bit-level I/O for RAR decompression.
"""
from __future__ import annotations
class BitInput:
"""
Bit-level reader matching unrar's BitInput class.
MSB-first bit ordering. Maintains InAddr (byte) and InBit (bit) positions.
"""
__slots__ = ('buf', 'in_addr', 'in_bit')
OVERREAD_SLACK = 4
def __init__(self, data: bytes | bytearray | memoryview):
self.buf = data
self.in_addr = 0
self.in_bit = 0
def init(self):
self.in_addr = 0
self.in_bit = 0
def load(self, data: bytes | bytearray | memoryview):
"""
Continue with the given data from its start. A solid archive decodes each file with the
same reader, so that whatever reads through it, like the PPM model, reads the new data.
"""
self.buf = data
self.init()
def get_char(self) -> int:
"""
Return the byte at the current byte position and advance past it, or zero at the end.
"""
addr = self.in_addr
if addr >= len(self.buf):
return 0
self.in_addr = addr + 1
return self.buf[addr]
def getbits(self) -> int:
"""
Return 16 bits starting from current position (MSB-first, left-aligned).
Does NOT advance the position.
"""
addr = self.in_addr
bit = self.in_bit
buf = self.buf
blen = len(buf)
b0 = buf[addr] if addr < blen else 0
b1 = buf[addr + 1] if addr + 1 < blen else 0
b2 = buf[addr + 2] if addr + 2 < blen else 0
val = (b0 << 16) | (b1 << 8) | b2
return (val >> (8 - bit)) & 0xFFFF
def getbits32(self) -> int:
"""
Return 32 bits starting from current position (MSB-first).
"""
addr = self.in_addr
bit = self.in_bit
buf = self.buf
blen = len(buf)
b0 = buf[addr] if addr < blen else 0
b1 = buf[addr + 1] if addr + 1 < blen else 0
b2 = buf[addr + 2] if addr + 2 < blen else 0
b3 = buf[addr + 3] if addr + 3 < blen else 0
b4 = buf[addr + 4] if addr + 4 < blen else 0
val = (b0 << 32) | (b1 << 24) | (b2 << 16) | (b3 << 8) | b4
return (val >> (8 - bit)) & 0xFFFFFFFF
def getbits64(self) -> int:
"""
Return 64 bits starting from current position (MSB-first).
"""
addr = self.in_addr
buf = self.buf
blen = len(buf)
val = 0
for k in range(addr, addr + 9):
val = (val << 8) | (buf[k] if k < blen else 0)
return (val >> (8 - self.in_bit)) & 0xFFFFFFFFFFFFFFFF
def addbits(self, bits: int):
"""
Advance the position by the given number of bits.
"""
total = (self.in_addr << 3) + self.in_bit + bits
self.in_addr = total >> 3
self.in_bit = total & 7
@property
def remaining(self) -> int:
"""
Return approximate number of bytes remaining.
"""
return max(0, len(self.buf) - self.in_addr)
@property
def overread(self) -> bool:
"""
Whether the reader has advanced more than a small slack of bytes past the end of the
input. Valid streams routinely read a few bytes past the end because getbits reads
ahead; only advancing beyond the slack indicates a malformed or truncated stream.
"""
return self.in_addr > len(self.buf) + self.OVERREAD_SLACK
Classes
class BitInput (data)-
Bit-level reader matching unrar's BitInput class. MSB-first bit ordering. Maintains InAddr (byte) and InBit (bit) positions.
Expand source code Browse git
class BitInput: """ Bit-level reader matching unrar's BitInput class. MSB-first bit ordering. Maintains InAddr (byte) and InBit (bit) positions. """ __slots__ = ('buf', 'in_addr', 'in_bit') OVERREAD_SLACK = 4 def __init__(self, data: bytes | bytearray | memoryview): self.buf = data self.in_addr = 0 self.in_bit = 0 def init(self): self.in_addr = 0 self.in_bit = 0 def load(self, data: bytes | bytearray | memoryview): """ Continue with the given data from its start. A solid archive decodes each file with the same reader, so that whatever reads through it, like the PPM model, reads the new data. """ self.buf = data self.init() def get_char(self) -> int: """ Return the byte at the current byte position and advance past it, or zero at the end. """ addr = self.in_addr if addr >= len(self.buf): return 0 self.in_addr = addr + 1 return self.buf[addr] def getbits(self) -> int: """ Return 16 bits starting from current position (MSB-first, left-aligned). Does NOT advance the position. """ addr = self.in_addr bit = self.in_bit buf = self.buf blen = len(buf) b0 = buf[addr] if addr < blen else 0 b1 = buf[addr + 1] if addr + 1 < blen else 0 b2 = buf[addr + 2] if addr + 2 < blen else 0 val = (b0 << 16) | (b1 << 8) | b2 return (val >> (8 - bit)) & 0xFFFF def getbits32(self) -> int: """ Return 32 bits starting from current position (MSB-first). """ addr = self.in_addr bit = self.in_bit buf = self.buf blen = len(buf) b0 = buf[addr] if addr < blen else 0 b1 = buf[addr + 1] if addr + 1 < blen else 0 b2 = buf[addr + 2] if addr + 2 < blen else 0 b3 = buf[addr + 3] if addr + 3 < blen else 0 b4 = buf[addr + 4] if addr + 4 < blen else 0 val = (b0 << 32) | (b1 << 24) | (b2 << 16) | (b3 << 8) | b4 return (val >> (8 - bit)) & 0xFFFFFFFF def getbits64(self) -> int: """ Return 64 bits starting from current position (MSB-first). """ addr = self.in_addr buf = self.buf blen = len(buf) val = 0 for k in range(addr, addr + 9): val = (val << 8) | (buf[k] if k < blen else 0) return (val >> (8 - self.in_bit)) & 0xFFFFFFFFFFFFFFFF def addbits(self, bits: int): """ Advance the position by the given number of bits. """ total = (self.in_addr << 3) + self.in_bit + bits self.in_addr = total >> 3 self.in_bit = total & 7 @property def remaining(self) -> int: """ Return approximate number of bytes remaining. """ return max(0, len(self.buf) - self.in_addr) @property def overread(self) -> bool: """ Whether the reader has advanced more than a small slack of bytes past the end of the input. Valid streams routinely read a few bytes past the end because getbits reads ahead; only advancing beyond the slack indicates a malformed or truncated stream. """ return self.in_addr > len(self.buf) + self.OVERREAD_SLACKClass variables
var OVERREAD_SLACK-
The type of the None singleton.
Instance variables
var remaining-
Return approximate number of bytes remaining.
Expand source code Browse git
@property def remaining(self) -> int: """ Return approximate number of bytes remaining. """ return max(0, len(self.buf) - self.in_addr) var overread-
Whether the reader has advanced more than a small slack of bytes past the end of the input. Valid streams routinely read a few bytes past the end because getbits reads ahead; only advancing beyond the slack indicates a malformed or truncated stream.
Expand source code Browse git
@property def overread(self) -> bool: """ Whether the reader has advanced more than a small slack of bytes past the end of the input. Valid streams routinely read a few bytes past the end because getbits reads ahead; only advancing beyond the slack indicates a malformed or truncated stream. """ return self.in_addr > len(self.buf) + self.OVERREAD_SLACK var buf-
Expand source code Browse git
class BitInput: """ Bit-level reader matching unrar's BitInput class. MSB-first bit ordering. Maintains InAddr (byte) and InBit (bit) positions. """ __slots__ = ('buf', 'in_addr', 'in_bit') OVERREAD_SLACK = 4 def __init__(self, data: bytes | bytearray | memoryview): self.buf = data self.in_addr = 0 self.in_bit = 0 def init(self): self.in_addr = 0 self.in_bit = 0 def load(self, data: bytes | bytearray | memoryview): """ Continue with the given data from its start. A solid archive decodes each file with the same reader, so that whatever reads through it, like the PPM model, reads the new data. """ self.buf = data self.init() def get_char(self) -> int: """ Return the byte at the current byte position and advance past it, or zero at the end. """ addr = self.in_addr if addr >= len(self.buf): return 0 self.in_addr = addr + 1 return self.buf[addr] def getbits(self) -> int: """ Return 16 bits starting from current position (MSB-first, left-aligned). Does NOT advance the position. """ addr = self.in_addr bit = self.in_bit buf = self.buf blen = len(buf) b0 = buf[addr] if addr < blen else 0 b1 = buf[addr + 1] if addr + 1 < blen else 0 b2 = buf[addr + 2] if addr + 2 < blen else 0 val = (b0 << 16) | (b1 << 8) | b2 return (val >> (8 - bit)) & 0xFFFF def getbits32(self) -> int: """ Return 32 bits starting from current position (MSB-first). """ addr = self.in_addr bit = self.in_bit buf = self.buf blen = len(buf) b0 = buf[addr] if addr < blen else 0 b1 = buf[addr + 1] if addr + 1 < blen else 0 b2 = buf[addr + 2] if addr + 2 < blen else 0 b3 = buf[addr + 3] if addr + 3 < blen else 0 b4 = buf[addr + 4] if addr + 4 < blen else 0 val = (b0 << 32) | (b1 << 24) | (b2 << 16) | (b3 << 8) | b4 return (val >> (8 - bit)) & 0xFFFFFFFF def getbits64(self) -> int: """ Return 64 bits starting from current position (MSB-first). """ addr = self.in_addr buf = self.buf blen = len(buf) val = 0 for k in range(addr, addr + 9): val = (val << 8) | (buf[k] if k < blen else 0) return (val >> (8 - self.in_bit)) & 0xFFFFFFFFFFFFFFFF def addbits(self, bits: int): """ Advance the position by the given number of bits. """ total = (self.in_addr << 3) + self.in_bit + bits self.in_addr = total >> 3 self.in_bit = total & 7 @property def remaining(self) -> int: """ Return approximate number of bytes remaining. """ return max(0, len(self.buf) - self.in_addr) @property def overread(self) -> bool: """ Whether the reader has advanced more than a small slack of bytes past the end of the input. Valid streams routinely read a few bytes past the end because getbits reads ahead; only advancing beyond the slack indicates a malformed or truncated stream. """ return self.in_addr > len(self.buf) + self.OVERREAD_SLACK var in_addr-
Expand source code Browse git
class BitInput: """ Bit-level reader matching unrar's BitInput class. MSB-first bit ordering. Maintains InAddr (byte) and InBit (bit) positions. """ __slots__ = ('buf', 'in_addr', 'in_bit') OVERREAD_SLACK = 4 def __init__(self, data: bytes | bytearray | memoryview): self.buf = data self.in_addr = 0 self.in_bit = 0 def init(self): self.in_addr = 0 self.in_bit = 0 def load(self, data: bytes | bytearray | memoryview): """ Continue with the given data from its start. A solid archive decodes each file with the same reader, so that whatever reads through it, like the PPM model, reads the new data. """ self.buf = data self.init() def get_char(self) -> int: """ Return the byte at the current byte position and advance past it, or zero at the end. """ addr = self.in_addr if addr >= len(self.buf): return 0 self.in_addr = addr + 1 return self.buf[addr] def getbits(self) -> int: """ Return 16 bits starting from current position (MSB-first, left-aligned). Does NOT advance the position. """ addr = self.in_addr bit = self.in_bit buf = self.buf blen = len(buf) b0 = buf[addr] if addr < blen else 0 b1 = buf[addr + 1] if addr + 1 < blen else 0 b2 = buf[addr + 2] if addr + 2 < blen else 0 val = (b0 << 16) | (b1 << 8) | b2 return (val >> (8 - bit)) & 0xFFFF def getbits32(self) -> int: """ Return 32 bits starting from current position (MSB-first). """ addr = self.in_addr bit = self.in_bit buf = self.buf blen = len(buf) b0 = buf[addr] if addr < blen else 0 b1 = buf[addr + 1] if addr + 1 < blen else 0 b2 = buf[addr + 2] if addr + 2 < blen else 0 b3 = buf[addr + 3] if addr + 3 < blen else 0 b4 = buf[addr + 4] if addr + 4 < blen else 0 val = (b0 << 32) | (b1 << 24) | (b2 << 16) | (b3 << 8) | b4 return (val >> (8 - bit)) & 0xFFFFFFFF def getbits64(self) -> int: """ Return 64 bits starting from current position (MSB-first). """ addr = self.in_addr buf = self.buf blen = len(buf) val = 0 for k in range(addr, addr + 9): val = (val << 8) | (buf[k] if k < blen else 0) return (val >> (8 - self.in_bit)) & 0xFFFFFFFFFFFFFFFF def addbits(self, bits: int): """ Advance the position by the given number of bits. """ total = (self.in_addr << 3) + self.in_bit + bits self.in_addr = total >> 3 self.in_bit = total & 7 @property def remaining(self) -> int: """ Return approximate number of bytes remaining. """ return max(0, len(self.buf) - self.in_addr) @property def overread(self) -> bool: """ Whether the reader has advanced more than a small slack of bytes past the end of the input. Valid streams routinely read a few bytes past the end because getbits reads ahead; only advancing beyond the slack indicates a malformed or truncated stream. """ return self.in_addr > len(self.buf) + self.OVERREAD_SLACK var in_bit-
Expand source code Browse git
class BitInput: """ Bit-level reader matching unrar's BitInput class. MSB-first bit ordering. Maintains InAddr (byte) and InBit (bit) positions. """ __slots__ = ('buf', 'in_addr', 'in_bit') OVERREAD_SLACK = 4 def __init__(self, data: bytes | bytearray | memoryview): self.buf = data self.in_addr = 0 self.in_bit = 0 def init(self): self.in_addr = 0 self.in_bit = 0 def load(self, data: bytes | bytearray | memoryview): """ Continue with the given data from its start. A solid archive decodes each file with the same reader, so that whatever reads through it, like the PPM model, reads the new data. """ self.buf = data self.init() def get_char(self) -> int: """ Return the byte at the current byte position and advance past it, or zero at the end. """ addr = self.in_addr if addr >= len(self.buf): return 0 self.in_addr = addr + 1 return self.buf[addr] def getbits(self) -> int: """ Return 16 bits starting from current position (MSB-first, left-aligned). Does NOT advance the position. """ addr = self.in_addr bit = self.in_bit buf = self.buf blen = len(buf) b0 = buf[addr] if addr < blen else 0 b1 = buf[addr + 1] if addr + 1 < blen else 0 b2 = buf[addr + 2] if addr + 2 < blen else 0 val = (b0 << 16) | (b1 << 8) | b2 return (val >> (8 - bit)) & 0xFFFF def getbits32(self) -> int: """ Return 32 bits starting from current position (MSB-first). """ addr = self.in_addr bit = self.in_bit buf = self.buf blen = len(buf) b0 = buf[addr] if addr < blen else 0 b1 = buf[addr + 1] if addr + 1 < blen else 0 b2 = buf[addr + 2] if addr + 2 < blen else 0 b3 = buf[addr + 3] if addr + 3 < blen else 0 b4 = buf[addr + 4] if addr + 4 < blen else 0 val = (b0 << 32) | (b1 << 24) | (b2 << 16) | (b3 << 8) | b4 return (val >> (8 - bit)) & 0xFFFFFFFF def getbits64(self) -> int: """ Return 64 bits starting from current position (MSB-first). """ addr = self.in_addr buf = self.buf blen = len(buf) val = 0 for k in range(addr, addr + 9): val = (val << 8) | (buf[k] if k < blen else 0) return (val >> (8 - self.in_bit)) & 0xFFFFFFFFFFFFFFFF def addbits(self, bits: int): """ Advance the position by the given number of bits. """ total = (self.in_addr << 3) + self.in_bit + bits self.in_addr = total >> 3 self.in_bit = total & 7 @property def remaining(self) -> int: """ Return approximate number of bytes remaining. """ return max(0, len(self.buf) - self.in_addr) @property def overread(self) -> bool: """ Whether the reader has advanced more than a small slack of bytes past the end of the input. Valid streams routinely read a few bytes past the end because getbits reads ahead; only advancing beyond the slack indicates a malformed or truncated stream. """ return self.in_addr > len(self.buf) + self.OVERREAD_SLACK
Methods
def init(self)-
Expand source code Browse git
def init(self): self.in_addr = 0 self.in_bit = 0 def load(self, data)-
Continue with the given data from its start. A solid archive decodes each file with the same reader, so that whatever reads through it, like the PPM model, reads the new data.
Expand source code Browse git
def load(self, data: bytes | bytearray | memoryview): """ Continue with the given data from its start. A solid archive decodes each file with the same reader, so that whatever reads through it, like the PPM model, reads the new data. """ self.buf = data self.init() def get_char(self)-
Return the byte at the current byte position and advance past it, or zero at the end.
Expand source code Browse git
def get_char(self) -> int: """ Return the byte at the current byte position and advance past it, or zero at the end. """ addr = self.in_addr if addr >= len(self.buf): return 0 self.in_addr = addr + 1 return self.buf[addr] def getbits(self)-
Return 16 bits starting from current position (MSB-first, left-aligned). Does NOT advance the position.
Expand source code Browse git
def getbits(self) -> int: """ Return 16 bits starting from current position (MSB-first, left-aligned). Does NOT advance the position. """ addr = self.in_addr bit = self.in_bit buf = self.buf blen = len(buf) b0 = buf[addr] if addr < blen else 0 b1 = buf[addr + 1] if addr + 1 < blen else 0 b2 = buf[addr + 2] if addr + 2 < blen else 0 val = (b0 << 16) | (b1 << 8) | b2 return (val >> (8 - bit)) & 0xFFFF def getbits32(self)-
Return 32 bits starting from current position (MSB-first).
Expand source code Browse git
def getbits32(self) -> int: """ Return 32 bits starting from current position (MSB-first). """ addr = self.in_addr bit = self.in_bit buf = self.buf blen = len(buf) b0 = buf[addr] if addr < blen else 0 b1 = buf[addr + 1] if addr + 1 < blen else 0 b2 = buf[addr + 2] if addr + 2 < blen else 0 b3 = buf[addr + 3] if addr + 3 < blen else 0 b4 = buf[addr + 4] if addr + 4 < blen else 0 val = (b0 << 32) | (b1 << 24) | (b2 << 16) | (b3 << 8) | b4 return (val >> (8 - bit)) & 0xFFFFFFFF def getbits64(self)-
Return 64 bits starting from current position (MSB-first).
Expand source code Browse git
def getbits64(self) -> int: """ Return 64 bits starting from current position (MSB-first). """ addr = self.in_addr buf = self.buf blen = len(buf) val = 0 for k in range(addr, addr + 9): val = (val << 8) | (buf[k] if k < blen else 0) return (val >> (8 - self.in_bit)) & 0xFFFFFFFFFFFFFFFF def addbits(self, bits)-
Advance the position by the given number of bits.
Expand source code Browse git
def addbits(self, bits: int): """ Advance the position by the given number of bits. """ total = (self.in_addr << 3) + self.in_bit + bits self.in_addr = total >> 3 self.in_bit = total & 7