fstdtools 0.0.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- fstdtools/__init__.py +0 -0
- fstdtools/__main__.py +2 -0
- fstdtools/cli.py +130 -0
- fstdtools/convert.py +77 -0
- fstdtools/mdict/__init__.py +0 -0
- fstdtools/mdict/lzo.py +246 -0
- fstdtools/mdict/pureSalsa20.py +365 -0
- fstdtools/mdict/readmdict.py +802 -0
- fstdtools/mdict/ripemd128.py +130 -0
- fstdtools/mdict/writemdict.py +673 -0
- fstdtools-0.0.1.dist-info/METADATA +15 -0
- fstdtools-0.0.1.dist-info/RECORD +16 -0
- fstdtools-0.0.1.dist-info/WHEEL +5 -0
- fstdtools-0.0.1.dist-info/entry_points.txt +2 -0
- fstdtools-0.0.1.dist-info/licenses/LICENSE +21 -0
- fstdtools-0.0.1.dist-info/top_level.txt +1 -0
fstdtools/__init__.py
ADDED
|
File without changes
|
fstdtools/__main__.py
ADDED
fstdtools/cli.py
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import click
|
|
2
|
+
import fstd
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from .convert import convert as converter
|
|
5
|
+
from importlib.metadata import version, PackageNotFoundError
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def get_version():
|
|
9
|
+
try:
|
|
10
|
+
return version("fstdtools")
|
|
11
|
+
except PackageNotFoundError:
|
|
12
|
+
return "0.0.0-unknown"
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def print_version(ctx, param, value):
|
|
16
|
+
if not value or ctx.resilient_parsing:
|
|
17
|
+
return
|
|
18
|
+
ver = fstd.get_version()
|
|
19
|
+
click.echo(click.style(f"fstdtools v{get_version()} | fstd core v{ver}", fg="green"))
|
|
20
|
+
ctx.exit()
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def overwrite_confirm(ctx, file_path):
|
|
24
|
+
if Path(file_path).exists():
|
|
25
|
+
if not click.confirm(click.style(f"File {file_path} already exists. Overwrite?", fg="yellow"), default=False):
|
|
26
|
+
click.echo("Operation cancelled", err=True)
|
|
27
|
+
ctx.exit(code=1)
|
|
28
|
+
return False
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
# ===================== Global options =====================
|
|
32
|
+
|
|
33
|
+
@click.group(name="fstdtools", help="CLI tools for fstd dictionary to pack/unpack/list/info/convert.", context_settings={"help_option_names": ["-h", "--help"]})
|
|
34
|
+
@click.option("-V", "--version", is_flag=True, callback=print_version, expose_value=False, is_eager=True, help="print version info and exit")
|
|
35
|
+
@click.option("--verbose", "-v", count=True, help="log level, -v simple log, -vv debug log")
|
|
36
|
+
@click.option("--log-level", "-l", type=click.IntRange(min=0, max=6), default=4, show_default=True, envvar="FSTDTOOLS_LOG_LEVEL", help=" log_level: 0-6, 0 is trace, 1 is debug, 2 is info, 3 is warn, 4 is error, 5 is critical, 6 is off")
|
|
37
|
+
@click.pass_context
|
|
38
|
+
def cli(ctx, verbose, log_level):
|
|
39
|
+
"""global init, all subcommands share this context"""
|
|
40
|
+
ctx.ensure_object(dict)
|
|
41
|
+
ctx.obj["verbose"] = verbose
|
|
42
|
+
ctx.obj["log_level"] = log_level
|
|
43
|
+
fstd.set_log_level(log_level)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
# ===================== Subcommands write =====================
|
|
47
|
+
|
|
48
|
+
@cli.command(name="write", help="from txt/fstdx/mdx to fstdx, from directory/mdd to fstdd")
|
|
49
|
+
@click.argument("source_file", type=click.Path(exists=True, file_okay=True, dir_okay=True, readable=True))
|
|
50
|
+
@click.argument("output_file", type=click.Path(file_okay=True, dir_okay=False, writable=True), required=False)
|
|
51
|
+
@click.option("-c", "--compress-level", type=click.IntRange(min=0, max=22), default=5, help="compression level 0(fast) ~ 22(max compress)")
|
|
52
|
+
@click.option("--compress-dict-size", type=click.IntRange(min=1, max=130), default=100, help="compression dict size, only for fstdx, 1~130, default 100")
|
|
53
|
+
@click.option("-b", "--block-size", type=click.IntRange(min=4, max=512), default=4, help="block size, default 4, unit KB")
|
|
54
|
+
@click.option("-t", "--thread", type=int, default=0, help="concurrency thread count, default 0, auto detect cpu count")
|
|
55
|
+
@click.option("--substyle/--no-substyle", default=False, help="enable substyle, only for mdx/mdd to fstdx/fstdd, default False")
|
|
56
|
+
@click.option("-y", "--yes", is_flag=True, help="overwrite output file, no confirm")
|
|
57
|
+
@click.pass_context
|
|
58
|
+
def convert_(
|
|
59
|
+
ctx, source_file, output_file, compress_level, compress_dict_size, block_size, thread, substyle, yes
|
|
60
|
+
):
|
|
61
|
+
verbose = ctx.obj["verbose"]
|
|
62
|
+
src = Path(source_file)
|
|
63
|
+
out = Path(output_file) if output_file else None
|
|
64
|
+
|
|
65
|
+
if not src.exists():
|
|
66
|
+
click.echo(click.style(f"Source file {src} does not exist", fg="red"), err=True)
|
|
67
|
+
ctx.exit(code=1)
|
|
68
|
+
|
|
69
|
+
if out and out.exists() and not yes:
|
|
70
|
+
if not click.confirm(click.style(f"File {out} already exists, overwrite?", fg="yellow")):
|
|
71
|
+
click.echo("Operation cancelled", err=True)
|
|
72
|
+
ctx.exit(code=1)
|
|
73
|
+
|
|
74
|
+
def show_verbose():
|
|
75
|
+
if verbose >= 1:
|
|
76
|
+
click.echo(click.style(f"Source file: {src}", fg="cyan"))
|
|
77
|
+
click.echo(click.style(f"Output file: {output_file if output_file else 'default'}", fg="cyan"))
|
|
78
|
+
click.echo(click.style(f"Compression level: {compress_level}", fg="cyan"))
|
|
79
|
+
click.echo(click.style(f"Compression dict size: {compress_dict_size}", fg="cyan"))
|
|
80
|
+
click.echo(click.style(f"Block size: {block_size}", fg="cyan"))
|
|
81
|
+
click.echo(click.style(f"Concurrency threads: {thread if thread > 0 else 'auto detect cpu count'}", fg="cyan"))
|
|
82
|
+
|
|
83
|
+
if src.is_dir():
|
|
84
|
+
if out and not out.suffix == ".fstdd":
|
|
85
|
+
click.echo(click.style("For mdd source, output file must have .fstdd extension", fg="red"), err=True)
|
|
86
|
+
ctx.exit(code=1)
|
|
87
|
+
if not output_file:
|
|
88
|
+
output_file = str(src.with_suffix(".fstdd"))
|
|
89
|
+
overwrite_confirm(ctx, output_file)
|
|
90
|
+
writer = fstd.FstddWriter()
|
|
91
|
+
show_verbose()
|
|
92
|
+
writer.compile_fstdd(source_file, output_file, "{}", block_size, compress_level, thread, verbose >= 1)
|
|
93
|
+
|
|
94
|
+
elif src.suffix == ".mdx":
|
|
95
|
+
if out and not out.suffix == ".fstdx":
|
|
96
|
+
click.echo(click.style("For mdx source, output file must have .fstdx extension", fg="red"), err=True)
|
|
97
|
+
ctx.exit(code=1)
|
|
98
|
+
if not output_file:
|
|
99
|
+
output_file = src.with_suffix(".fstdx")
|
|
100
|
+
overwrite_confirm(ctx, output_file)
|
|
101
|
+
show_verbose()
|
|
102
|
+
converter(source_file, output_file, compress_level, compress_dict_size, block_size, thread, substyle, None)
|
|
103
|
+
|
|
104
|
+
elif src.suffix == ".mdd":
|
|
105
|
+
if out and not out.suffix == ".fstdd":
|
|
106
|
+
click.echo(click.style("For mdd source, output file must have .fstdd extension", fg="red"), err=True)
|
|
107
|
+
ctx.exit(code=1)
|
|
108
|
+
if not output_file:
|
|
109
|
+
output_file = str(src.with_suffix(".fstdd"))
|
|
110
|
+
overwrite_confirm(ctx, output_file)
|
|
111
|
+
show_verbose()
|
|
112
|
+
converter(source_file, output_file, compress_level, compress_dict_size, block_size, thread, substyle, None)
|
|
113
|
+
|
|
114
|
+
else:
|
|
115
|
+
# see src as txt or fstdx, then convert to fstdx
|
|
116
|
+
if out and not out.suffix == ".fstdx":
|
|
117
|
+
click.echo(click.style("For txt or fstdx source, output file must have .fstdx extension", fg="red"), err=True)
|
|
118
|
+
ctx.exit(code=1)
|
|
119
|
+
if not output_file:
|
|
120
|
+
output_file = src.with_suffix(".fstdx")
|
|
121
|
+
overwrite_confirm(ctx, output_file)
|
|
122
|
+
writer = fstd.FstdxWriter()
|
|
123
|
+
show_verbose()
|
|
124
|
+
writer.compile_fstdx(source_file, output_file, "{}", block_size, compress_level, compress_dict_size, thread, False, verbose >= 1)
|
|
125
|
+
|
|
126
|
+
click.echo(click.style(f"{output_file} written successfully", fg="bright_green"))
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
if __name__ == "__main__":
|
|
130
|
+
cli()
|
fstdtools/convert.py
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import os.path
|
|
2
|
+
import fstd
|
|
3
|
+
import json
|
|
4
|
+
from concurrent.futures import ThreadPoolExecutor
|
|
5
|
+
|
|
6
|
+
from tqdm import tqdm
|
|
7
|
+
|
|
8
|
+
from .mdict.readmdict import MDX, MDD
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def get_meta(source, substyle=False, passcode=None):
|
|
12
|
+
meta = {}
|
|
13
|
+
if source.endswith('.mdx'):
|
|
14
|
+
encoding = ''
|
|
15
|
+
md = MDX(source, encoding, substyle, passcode)
|
|
16
|
+
if source.endswith('.mdd'):
|
|
17
|
+
md = MDD(source, passcode)
|
|
18
|
+
|
|
19
|
+
for key, value in md.header.items():
|
|
20
|
+
# key has been decode from UTF-16 and encode again with UTF-8
|
|
21
|
+
key = key.decode('UTF-8').lower().title()
|
|
22
|
+
value = value.decode('UTF-8')
|
|
23
|
+
meta[key] = value
|
|
24
|
+
if value == 'Yes':
|
|
25
|
+
meta[key] = True
|
|
26
|
+
elif value == 'No':
|
|
27
|
+
meta[key] = False
|
|
28
|
+
|
|
29
|
+
return meta
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def convert(source, target, compress_level, compress_dict_size, block_size, thread=0, substyle=False, passcode=None):
|
|
33
|
+
meta_info = get_meta(source, substyle, passcode)
|
|
34
|
+
meta_json_str = json.dumps(meta_info, ensure_ascii=False)
|
|
35
|
+
if source.endswith('.mdx'):
|
|
36
|
+
encoding = ''
|
|
37
|
+
mdx = MDX(source, encoding, substyle, passcode)
|
|
38
|
+
item_count = 0
|
|
39
|
+
keys = []
|
|
40
|
+
values = []
|
|
41
|
+
|
|
42
|
+
print("Extracting raw data from mdx:")
|
|
43
|
+
bar = tqdm(total=len(mdx), unit='rec')
|
|
44
|
+
for key, value in mdx.items():
|
|
45
|
+
if not value.strip():
|
|
46
|
+
bar.write('Skip entry: %s' % key)
|
|
47
|
+
continue
|
|
48
|
+
item_count += 1
|
|
49
|
+
keys.append(key)
|
|
50
|
+
values.append(value)
|
|
51
|
+
bar.update(1)
|
|
52
|
+
bar.close()
|
|
53
|
+
writer = fstd.FstdxWriter()
|
|
54
|
+
writer.compile_fstdx(target, keys, values, meta_json_str, block_size, compress_level, compress_dict_size, thread, False, True)
|
|
55
|
+
elif source.endswith('.mdd'):
|
|
56
|
+
mdd = MDD(source, passcode)
|
|
57
|
+
writer = fstd.FstddWriter()
|
|
58
|
+
executor = ThreadPoolExecutor(max_workers=1)
|
|
59
|
+
future = executor.submit(
|
|
60
|
+
writer.compile_fstdd,
|
|
61
|
+
len(mdd),
|
|
62
|
+
target,
|
|
63
|
+
meta_json_str,
|
|
64
|
+
block_size,
|
|
65
|
+
compress_level,
|
|
66
|
+
thread,
|
|
67
|
+
False
|
|
68
|
+
)
|
|
69
|
+
for key, value in mdd.items():
|
|
70
|
+
fname = key.decode('UTF-8').replace('\\', os.path.sep)
|
|
71
|
+
if not writer.push_file_stream(fname, value):
|
|
72
|
+
break
|
|
73
|
+
ret = future.result()
|
|
74
|
+
if ret != 0:
|
|
75
|
+
print("Compile fstdd failed with error code: %d" % ret)
|
|
76
|
+
else:
|
|
77
|
+
raise ValueError("Unsupported source file type: %s" % source)
|
|
File without changes
|
fstdtools/mdict/lzo.py
ADDED
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
import math
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class FlexBuffer():
|
|
5
|
+
|
|
6
|
+
def __init__(self):
|
|
7
|
+
|
|
8
|
+
self.blockSize = None
|
|
9
|
+
self.c = None
|
|
10
|
+
self.l = None
|
|
11
|
+
self.buf = None
|
|
12
|
+
|
|
13
|
+
def require(self, n):
|
|
14
|
+
|
|
15
|
+
r = self.c - self.l + n
|
|
16
|
+
if r > 0:
|
|
17
|
+
self.l = self.l + self.blockSize * math.ceil(r / self.blockSize)
|
|
18
|
+
#tmp = bytearray(self.l)
|
|
19
|
+
#for i in len(self.buf):
|
|
20
|
+
# tmp[i] = self.buf[i]
|
|
21
|
+
#self.buf = tmp
|
|
22
|
+
self.buf = self.buf + bytearray(self.l - len(self.buf))
|
|
23
|
+
self.c = self.c + n
|
|
24
|
+
return self.buf
|
|
25
|
+
|
|
26
|
+
def alloc(self, initSize, blockSize):
|
|
27
|
+
|
|
28
|
+
if blockSize:
|
|
29
|
+
sz = blockSize
|
|
30
|
+
else:
|
|
31
|
+
sz = 4096
|
|
32
|
+
self.blockSize = self.roundUp(sz)
|
|
33
|
+
self.c = 0
|
|
34
|
+
self.l = self.roundUp(initSize) | 0
|
|
35
|
+
self.l += self.blockSize - (self.l % self.blockSize)
|
|
36
|
+
self.buf = bytearray(self.l)
|
|
37
|
+
return self.buf
|
|
38
|
+
|
|
39
|
+
def roundUp(self, n):
|
|
40
|
+
|
|
41
|
+
r = n % 4
|
|
42
|
+
if r == 0:
|
|
43
|
+
return n
|
|
44
|
+
else:
|
|
45
|
+
return n + 4 - r
|
|
46
|
+
|
|
47
|
+
def reset(self):
|
|
48
|
+
|
|
49
|
+
self.c = 0
|
|
50
|
+
self.l = len(self.buf)
|
|
51
|
+
|
|
52
|
+
def pack(self, size):
|
|
53
|
+
|
|
54
|
+
return self.buf[0:size]
|
|
55
|
+
|
|
56
|
+
def _decompress(inBuf, outBuf):
|
|
57
|
+
|
|
58
|
+
c_top_loop = 1
|
|
59
|
+
c_first_literal_run = 2
|
|
60
|
+
c_match = 3
|
|
61
|
+
c_copy_match = 4
|
|
62
|
+
c_match_done = 5
|
|
63
|
+
c_match_next = 6
|
|
64
|
+
|
|
65
|
+
out = outBuf.buf
|
|
66
|
+
op = 0
|
|
67
|
+
ip = 0
|
|
68
|
+
t = inBuf[ip]
|
|
69
|
+
state = c_top_loop
|
|
70
|
+
m_pos = 0
|
|
71
|
+
ip_end = len(inBuf)
|
|
72
|
+
|
|
73
|
+
if t > 17:
|
|
74
|
+
ip = ip + 1
|
|
75
|
+
t = t - 17
|
|
76
|
+
if t < 4:
|
|
77
|
+
state = c_match_next
|
|
78
|
+
else:
|
|
79
|
+
out = outBuf.require(t)
|
|
80
|
+
while True:
|
|
81
|
+
out[op] = inBuf[ip]
|
|
82
|
+
op = op + 1
|
|
83
|
+
ip = ip + 1
|
|
84
|
+
t = t - 1
|
|
85
|
+
if not t > 0: break
|
|
86
|
+
state = c_first_literal_run
|
|
87
|
+
|
|
88
|
+
while True:
|
|
89
|
+
if_block = False
|
|
90
|
+
|
|
91
|
+
##
|
|
92
|
+
if state == c_top_loop:
|
|
93
|
+
t = inBuf[ip]
|
|
94
|
+
ip = ip + 1
|
|
95
|
+
if t >= 16:
|
|
96
|
+
state = c_match
|
|
97
|
+
continue
|
|
98
|
+
if t == 0:
|
|
99
|
+
while inBuf[ip] == 0:
|
|
100
|
+
t = t + 255
|
|
101
|
+
ip = ip + 1
|
|
102
|
+
t = t + 15 + inBuf[ip]
|
|
103
|
+
ip = ip + 1
|
|
104
|
+
|
|
105
|
+
t = t + 3
|
|
106
|
+
out = outBuf.require(t)
|
|
107
|
+
while True:
|
|
108
|
+
out[op] = inBuf[ip]
|
|
109
|
+
op = op + 1
|
|
110
|
+
ip = ip + 1
|
|
111
|
+
t = t - 1
|
|
112
|
+
if not t > 0: break
|
|
113
|
+
# emulate c switch
|
|
114
|
+
state = c_first_literal_run
|
|
115
|
+
|
|
116
|
+
##
|
|
117
|
+
if state == c_first_literal_run:
|
|
118
|
+
t = inBuf[ip]
|
|
119
|
+
ip = ip + 1
|
|
120
|
+
if t >= 16:
|
|
121
|
+
state = c_match
|
|
122
|
+
continue
|
|
123
|
+
m_pos = op - 0x801 - (t >> 2) - (inBuf[ip] << 2)
|
|
124
|
+
ip = ip + 1
|
|
125
|
+
out = outBuf.require(3)
|
|
126
|
+
out[op] = out[m_pos]
|
|
127
|
+
op = op + 1
|
|
128
|
+
m_pos = m_pos + 1
|
|
129
|
+
out[op] = out[m_pos]
|
|
130
|
+
op = op + 1
|
|
131
|
+
m_pos = m_pos + 1
|
|
132
|
+
out[op] = out[m_pos]
|
|
133
|
+
op = op + 1
|
|
134
|
+
|
|
135
|
+
state = c_match_done
|
|
136
|
+
continue
|
|
137
|
+
|
|
138
|
+
##
|
|
139
|
+
if state == c_match:
|
|
140
|
+
if t >= 64:
|
|
141
|
+
m_pos = op - 1 - ((t >> 2) & 7) - (inBuf[ip] << 3)
|
|
142
|
+
ip = ip + 1
|
|
143
|
+
t = (t >> 5) - 1
|
|
144
|
+
state = c_copy_match
|
|
145
|
+
continue
|
|
146
|
+
elif t >= 32:
|
|
147
|
+
t = t & 31
|
|
148
|
+
if t == 0:
|
|
149
|
+
while inBuf[ip] == 0:
|
|
150
|
+
t = t + 255
|
|
151
|
+
ip = ip + 1
|
|
152
|
+
t = t + 31 + inBuf[ip]
|
|
153
|
+
ip = ip + 1
|
|
154
|
+
m_pos = op - 1 - ((inBuf[ip] + (inBuf[ip + 1] << 8)) >> 2)
|
|
155
|
+
ip = ip + 2
|
|
156
|
+
elif t >= 16:
|
|
157
|
+
m_pos = op - ((t & 8) << 11)
|
|
158
|
+
t = t & 7
|
|
159
|
+
if t == 0:
|
|
160
|
+
while inBuf[ip] == 0:
|
|
161
|
+
t = t + 255
|
|
162
|
+
ip = ip + 1
|
|
163
|
+
t = t + 7 + inBuf[ip]
|
|
164
|
+
ip = ip + 1
|
|
165
|
+
m_pos = m_pos - ((inBuf[ip] + (inBuf[ip + 1] << 8)) >> 2)
|
|
166
|
+
ip = ip + 2
|
|
167
|
+
if m_pos == op:
|
|
168
|
+
break
|
|
169
|
+
m_pos = m_pos - 0x4000
|
|
170
|
+
else:
|
|
171
|
+
m_pos = op - 1 - (t >> 2) - (inBuf[ip] << 2);
|
|
172
|
+
ip = ip + 1
|
|
173
|
+
out = outBuf.require(2)
|
|
174
|
+
out[op] = out[m_pos]
|
|
175
|
+
op = op + 1
|
|
176
|
+
m_pos = m_pos + 1
|
|
177
|
+
out[op] = out[m_pos]
|
|
178
|
+
op = op + 1
|
|
179
|
+
state = c_match_done
|
|
180
|
+
continue
|
|
181
|
+
|
|
182
|
+
if t >= 6 and (op - m_pos) >= 4:
|
|
183
|
+
if_block = True
|
|
184
|
+
t += 2
|
|
185
|
+
out = outBuf.require(t)
|
|
186
|
+
while True:
|
|
187
|
+
out[op] = out[m_pos]
|
|
188
|
+
op += 1
|
|
189
|
+
m_pos += 1
|
|
190
|
+
t -= 1
|
|
191
|
+
if not t > 0: break
|
|
192
|
+
#emulate c switch
|
|
193
|
+
state = c_copy_match
|
|
194
|
+
|
|
195
|
+
##
|
|
196
|
+
if state == c_copy_match:
|
|
197
|
+
if not if_block:
|
|
198
|
+
t += 2
|
|
199
|
+
out = outBuf.require(t)
|
|
200
|
+
while True:
|
|
201
|
+
out[op] = out[m_pos]
|
|
202
|
+
op += 1
|
|
203
|
+
m_pos += 1
|
|
204
|
+
t -= 1
|
|
205
|
+
if not t > 0: break
|
|
206
|
+
#emulating c switch
|
|
207
|
+
state = c_match_done
|
|
208
|
+
|
|
209
|
+
##
|
|
210
|
+
if state == c_match_done:
|
|
211
|
+
t = inBuf[ip - 2] & 3
|
|
212
|
+
if t == 0:
|
|
213
|
+
state = c_top_loop
|
|
214
|
+
continue
|
|
215
|
+
#emulate c switch
|
|
216
|
+
state = c_match_next
|
|
217
|
+
|
|
218
|
+
##
|
|
219
|
+
if state == c_match_next:
|
|
220
|
+
out = outBuf.require(1)
|
|
221
|
+
out[op] = inBuf[ip]
|
|
222
|
+
op += 1
|
|
223
|
+
ip += 1
|
|
224
|
+
if t > 1:
|
|
225
|
+
out = outBuf.require(1)
|
|
226
|
+
out[op] = inBuf[ip]
|
|
227
|
+
op += 1
|
|
228
|
+
ip += 1
|
|
229
|
+
if t > 2:
|
|
230
|
+
out = outBuf.require(1)
|
|
231
|
+
out[op] = inBuf[ip]
|
|
232
|
+
op += 1
|
|
233
|
+
ip += 1
|
|
234
|
+
t = inBuf[ip]
|
|
235
|
+
ip += 1
|
|
236
|
+
state = c_match
|
|
237
|
+
continue
|
|
238
|
+
|
|
239
|
+
return bytes(outBuf.pack(op))
|
|
240
|
+
|
|
241
|
+
def decompress(input, initSize = 16000, blockSize = 8192):
|
|
242
|
+
output = FlexBuffer()
|
|
243
|
+
output.alloc(initSize, blockSize)
|
|
244
|
+
return _decompress(bytearray(input), output)
|
|
245
|
+
|
|
246
|
+
|