247 lines
6.4 KiB
Python
247 lines
6.4 KiB
Python
import math
|
|
|
|
|
|
class FlexBuffer():
|
|
|
|
def __init__(self):
|
|
|
|
self.blockSize = None
|
|
self.c = None
|
|
self.l = None
|
|
self.buf = None
|
|
|
|
def require(self, n):
|
|
|
|
r = self.c - self.l + n
|
|
if r > 0:
|
|
self.l = self.l + self.blockSize * math.ceil(r / self.blockSize)
|
|
#tmp = bytearray(self.l)
|
|
#for i in len(self.buf):
|
|
# tmp[i] = self.buf[i]
|
|
#self.buf = tmp
|
|
self.buf = self.buf + bytearray(self.l - len(self.buf))
|
|
self.c = self.c + n
|
|
return self.buf
|
|
|
|
def alloc(self, initSize, blockSize):
|
|
|
|
if blockSize:
|
|
sz = blockSize
|
|
else:
|
|
sz = 4096
|
|
self.blockSize = self.roundUp(sz)
|
|
self.c = 0
|
|
self.l = self.roundUp(initSize) | 0
|
|
self.l += self.blockSize - (self.l % self.blockSize)
|
|
self.buf = bytearray(self.l)
|
|
return self.buf
|
|
|
|
def roundUp(self, n):
|
|
|
|
r = n % 4
|
|
if r == 0:
|
|
return n
|
|
else:
|
|
return n + 4 - r
|
|
|
|
def reset(self):
|
|
|
|
self.c = 0
|
|
self.l = len(self.buf)
|
|
|
|
def pack(self, size):
|
|
|
|
return self.buf[0:size]
|
|
|
|
def _decompress(inBuf, outBuf):
|
|
|
|
c_top_loop = 1
|
|
c_first_literal_run = 2
|
|
c_match = 3
|
|
c_copy_match = 4
|
|
c_match_done = 5
|
|
c_match_next = 6
|
|
|
|
out = outBuf.buf
|
|
op = 0
|
|
ip = 0
|
|
t = inBuf[ip]
|
|
state = c_top_loop
|
|
m_pos = 0
|
|
ip_end = len(inBuf)
|
|
|
|
if t > 17:
|
|
ip = ip + 1
|
|
t = t - 17
|
|
if t < 4:
|
|
state = c_match_next
|
|
else:
|
|
out = outBuf.require(t)
|
|
while True:
|
|
out[op] = inBuf[ip]
|
|
op = op + 1
|
|
ip = ip + 1
|
|
t = t - 1
|
|
if not t > 0: break
|
|
state = c_first_literal_run
|
|
|
|
while True:
|
|
if_block = False
|
|
|
|
##
|
|
if state == c_top_loop:
|
|
t = inBuf[ip]
|
|
ip = ip + 1
|
|
if t >= 16:
|
|
state = c_match
|
|
continue
|
|
if t == 0:
|
|
while inBuf[ip] == 0:
|
|
t = t + 255
|
|
ip = ip + 1
|
|
t = t + 15 + inBuf[ip]
|
|
ip = ip + 1
|
|
|
|
t = t + 3
|
|
out = outBuf.require(t)
|
|
while True:
|
|
out[op] = inBuf[ip]
|
|
op = op + 1
|
|
ip = ip + 1
|
|
t = t - 1
|
|
if not t > 0: break
|
|
# emulate c switch
|
|
state = c_first_literal_run
|
|
|
|
##
|
|
if state == c_first_literal_run:
|
|
t = inBuf[ip]
|
|
ip = ip + 1
|
|
if t >= 16:
|
|
state = c_match
|
|
continue
|
|
m_pos = op - 0x801 - (t >> 2) - (inBuf[ip] << 2)
|
|
ip = ip + 1
|
|
out = outBuf.require(3)
|
|
out[op] = out[m_pos]
|
|
op = op + 1
|
|
m_pos = m_pos + 1
|
|
out[op] = out[m_pos]
|
|
op = op + 1
|
|
m_pos = m_pos + 1
|
|
out[op] = out[m_pos]
|
|
op = op + 1
|
|
|
|
state = c_match_done
|
|
continue
|
|
|
|
##
|
|
if state == c_match:
|
|
if t >= 64:
|
|
m_pos = op - 1 - ((t >> 2) & 7) - (inBuf[ip] << 3)
|
|
ip = ip + 1
|
|
t = (t >> 5) - 1
|
|
state = c_copy_match
|
|
continue
|
|
elif t >= 32:
|
|
t = t & 31
|
|
if t == 0:
|
|
while inBuf[ip] == 0:
|
|
t = t + 255
|
|
ip = ip + 1
|
|
t = t + 31 + inBuf[ip]
|
|
ip = ip + 1
|
|
m_pos = op - 1 - ((inBuf[ip] + (inBuf[ip + 1] << 8)) >> 2)
|
|
ip = ip + 2
|
|
elif t >= 16:
|
|
m_pos = op - ((t & 8) << 11)
|
|
t = t & 7
|
|
if t == 0:
|
|
while inBuf[ip] == 0:
|
|
t = t + 255
|
|
ip = ip + 1
|
|
t = t + 7 + inBuf[ip]
|
|
ip = ip + 1
|
|
m_pos = m_pos - ((inBuf[ip] + (inBuf[ip + 1] << 8)) >> 2)
|
|
ip = ip + 2
|
|
if m_pos == op:
|
|
break
|
|
m_pos = m_pos - 0x4000
|
|
else:
|
|
m_pos = op - 1 - (t >> 2) - (inBuf[ip] << 2);
|
|
ip = ip + 1
|
|
out = outBuf.require(2)
|
|
out[op] = out[m_pos]
|
|
op = op + 1
|
|
m_pos = m_pos + 1
|
|
out[op] = out[m_pos]
|
|
op = op + 1
|
|
state = c_match_done
|
|
continue
|
|
|
|
if t >= 6 and (op - m_pos) >= 4:
|
|
if_block = True
|
|
t += 2
|
|
out = outBuf.require(t)
|
|
while True:
|
|
out[op] = out[m_pos]
|
|
op += 1
|
|
m_pos += 1
|
|
t -= 1
|
|
if not t > 0: break
|
|
#emulate c switch
|
|
state = c_copy_match
|
|
|
|
##
|
|
if state == c_copy_match:
|
|
if not if_block:
|
|
t += 2
|
|
out = outBuf.require(t)
|
|
while True:
|
|
out[op] = out[m_pos]
|
|
op += 1
|
|
m_pos += 1
|
|
t -= 1
|
|
if not t > 0: break
|
|
#emulating c switch
|
|
state = c_match_done
|
|
|
|
##
|
|
if state == c_match_done:
|
|
t = inBuf[ip - 2] & 3
|
|
if t == 0:
|
|
state = c_top_loop
|
|
continue
|
|
#emulate c switch
|
|
state = c_match_next
|
|
|
|
##
|
|
if state == c_match_next:
|
|
out = outBuf.require(1)
|
|
out[op] = inBuf[ip]
|
|
op += 1
|
|
ip += 1
|
|
if t > 1:
|
|
out = outBuf.require(1)
|
|
out[op] = inBuf[ip]
|
|
op += 1
|
|
ip += 1
|
|
if t > 2:
|
|
out = outBuf.require(1)
|
|
out[op] = inBuf[ip]
|
|
op += 1
|
|
ip += 1
|
|
t = inBuf[ip]
|
|
ip += 1
|
|
state = c_match
|
|
continue
|
|
|
|
return bytes(outBuf.pack(op))
|
|
|
|
def decompress(input, initSize = 16000, blockSize = 8192):
|
|
output = FlexBuffer()
|
|
output.alloc(initSize, blockSize)
|
|
return _decompress(bytearray(input), output)
|
|
|
|
|