Files

286 lines
8.2 KiB
Plaintext

import string
import stdlib
import memhub
# ============================================================
# DEFLATE / zlib constants
# ============================================================
define ZDEFLATE_WINDOW_BITS = 15
define ZDEFLATE_WINDOW_SIZE = (1 << ZDEFLATE_WINDOW_BITS)
define ZDEFLATE_WINDOW_MASK = (ZDEFLATE_WINDOW_SIZE - 1)
define ZDEFLATE_MIN_MATCH = 3
define ZDEFLATE_MAX_MATCH = 258
define ZDEFLATE_HASH_BITS = 15
define ZDEFLATE_HASH_SIZE = (1 << ZDEFLATE_HASH_BITS)
define ZDEFLATE_HASH_MASK = (ZDEFLATE_HASH_SIZE - 1)
define ZDEFLATE_MAX_CODES = 288
define ZDEFLATE_MAX_DIST_CODES = 32
define ZDEFLATE_MAX_BITS = 15
define ZDEFLATE_MAX_CODELEN_CODES = 19
define ZDEFLATE_LIT_COUNT = 286
define ZDEFLATE_DIST_COUNT = 30
define ZDEFLATE_LEN_SYMBOLS_BASE = 257
define ZDEFLATE_END_OF_BLOCK = 256
# ============================================================
# Length / Distance extra bits tables (RFC 1951)
# ============================================================
zdeflate_len_extra_bits: [29]int = [
0, 0, 0, 0, 0, 0, 0, 0,
1, 1, 1, 1,
2, 2, 2, 2,
3, 3, 3, 3,
4, 4, 4, 4,
5, 5, 5, 5,
0
]
zdeflate_len_base: [29]int = [
3, 4, 5, 6, 7, 8, 9, 10,
11, 13, 15, 17,
19, 23, 27, 31,
35, 43, 51, 59,
67, 83, 99, 115,
131, 163, 195, 227,
258
]
zdeflate_dist_extra_bits: [30]int = [
0, 0, 0, 0,
1, 1,
2, 2,
3, 3,
4, 4,
5, 5,
6, 6,
7, 7,
8, 8,
9, 9,
10, 10,
11, 11,
12, 12,
13, 13
]
zdeflate_dist_base: [30]int = [
1, 2, 3, 4,
5, 7,
9, 13,
17, 25,
33, 49,
65, 97,
129, 193,
257, 385,
513, 769,
1025, 1537,
2049, 3073,
4097, 6145,
8193, 12289,
16385, 24577
]
zdeflate_codelen_order: [19]int = [
16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15
]
# ============================================================
# Bit writer - writes bits LSB first into a byte buffer
# ============================================================
class zbit_writer:
pool: memhub.MemManager*
buf: bytes
cap: sizet
byte_pos: sizet
bit_pos: int
def __init__(self, pool: memhub.MemManager*):
self.pool = pool
self.cap = 4096
if pool == None:
self.buf = bytes(stdlib.malloc(self.cap))
else:
self.buf = bytes(pool.alloc(self.cap))
string.memset(self.buf, 0, self.cap)
self.byte_pos = 0
self.bit_pos = 0
def ensure(self, need: sizet):
while self.byte_pos + need + 4 >= self.cap:
new_cap: sizet = self.cap * 2
if self.pool == None:
new_buf: bytes = bytes(stdlib.realloc(self.buf, new_cap))
else:
new_buf: bytes = bytes(self.pool.alloc(new_cap))
if new_buf:
string.memcpy(new_buf, self.buf, self.byte_pos + (self.bit_pos + 7) / 8)
self.pool.free(self.buf)
if not new_buf: return
string.memset(new_buf + self.cap, 0, new_cap - self.cap)
self.buf = new_buf
self.cap = new_cap
def write_bits(self, value: uint, nbits: int):
self.ensure((nbits + 7) / 8 + 1)
for i in range(int(nbits)):
if value & (uint(1) << i):
# BYTE(...) 显式窄化:|= 的目标 buf 元素是 8 位(BYTE/uchar),右值是 i32 位图掩码
self.buf[self.byte_pos] |= char(uint(1) << self.bit_pos)
self.bit_pos += 1
if self.bit_pos == 8:
self.bit_pos = 0
self.byte_pos += 1
def write_bits_rev(self, code: uint, nbits: int):
self.ensure((nbits + 7) / 8 + 1)
for i in range(int(nbits - 1), -1, -1):
if code & (uint(1) << i):
# BYTE(...) 显式窄化:|= 的目标 buf 元素是 8 位(BYTE/uchar),右值是 i32 位图掩码
self.buf[self.byte_pos] |= char(uint(1) << self.bit_pos)
self.bit_pos += 1
if self.bit_pos == 8:
self.bit_pos = 0
self.byte_pos += 1
def stored_block(self, data: uint8*, length: sizet, final: int):
self.write_bits(1 if final else 0, 1)
self.write_bits(0, 2)
self.align()
pos: sizet = 0
while pos < length:
block_length: sizet = length - pos
if block_length > 65535:
block_length = 65535
n: uint16 = uint16(block_length)
ncomp: uint16 = ~n
self.write_bits(n, 16)
self.write_bits(ncomp, 16)
self.ensure(block_length)
i: sizet = 0
for i in range(int(block_length)):
self.buf[self.byte_pos] = data[pos + i]
self.byte_pos += 1
pos += block_length
if pos < length:
self.write_bits(0, 1)
self.write_bits(0, 2)
self.align()
def write_zlib_header(self, wbits: int, level: int):
cinfo: int = wbits - 8
if cinfo < 1: cinfo = 1
if cinfo > 7: cinfo = 7
cmf: uchar = uchar((cinfo << 4) | 8)
flevel: int = 0
if level >= 5: flevel = 3
elif level >= 3: flevel = 1
flg: uchar = uchar(flevel << 6)
flg |= uchar(31 - (cmf * 256 + flg) % 31)
self.buf[self.byte_pos + 0] = cmf
self.buf[self.byte_pos + 1] = flg
self.byte_pos += 2
def write_gzip_header(self):
self.buf[self.byte_pos + 0] = 0x1F
self.buf[self.byte_pos + 1] = 0x8B
self.buf[self.byte_pos + 2] = 0x08
self.buf[self.byte_pos + 3] = 0x00
self.buf[self.byte_pos + 4] = 0x00
self.buf[self.byte_pos + 5] = 0x00
self.buf[self.byte_pos + 6] = 0x00
self.buf[self.byte_pos + 7] = 0x00
self.buf[self.byte_pos + 8] = 0x00
self.buf[self.byte_pos + 9] = 0xFF
self.byte_pos += 10
def align(self):
if self.bit_pos > 0:
self.bit_pos = 0
self.byte_pos += 1
def total(self) -> sizet:
return self.byte_pos + (1 if (self.bit_pos > 0) else 0)
def free(self):
if self.pool == None:
stdlib.free(self.buf)
else:
self.pool.free(self.buf)
self.buf = None
self.cap = 0
self.byte_pos = 0
self.bit_pos = 0
def __del__(self):
self.free()
# ============================================================
# Bit reader - reads bits LSB first from a byte buffer
# ============================================================
class zbit_reader:
buf: bytes
length: sizet
byte_pos: sizet
bit_pos: int
def init(self, buf: bytes, length: sizet):
self.buf = buf
self.length = length
self.byte_pos = 0
self.bit_pos = 0
def read_bits(self, nbits: int, out: uint*) -> int:
val: uint = 0
for i in range(int(nbits)):
if self.byte_pos >= self.length: return -1
if self.buf[self.byte_pos] & (uint(1) << self.bit_pos):
val |= (uint(1) << i)
self.bit_pos += 1
if self.bit_pos == 8:
self.bit_pos = 0
self.byte_pos += 1
*out = val
return 0
def read_bits_rev(self, nbits: int, out: uint*) -> int:
val: uint = 0
for i in range(int(nbits - 1), 0, -1):
if self.byte_pos >= self.length: return -1
if self.buf[self.byte_pos] & (uint(1) << self.bit_pos):
val |= (uint(1) << i)
self.bit_pos += 1
if self.bit_pos == 8:
self.bit_pos = 0
self.byte_pos += 1
*out = val
return 0
def align(self):
if self.bit_pos > 0:
self.bit_pos = 0
self.byte_pos += 1
# ============================================================
# Memory allocation helper for bare metal
# Can be replaced with custom allocator
# ============================================================
def zdef_alloc(pool: memhub.MemManager*, n: sizet) -> rawptr:
if pool == None: return stdlib.malloc(n)
return pool.alloc(n)
def zdef_free(pool: memhub.MemManager*, p: rawptr):
if pool == None:
stdlib.free(p)
return
pool.free(p)