Skip to content

Commit 100a229

Browse files
committed
Separate the lib from scripts
1 parent f210299 commit 100a229

13 files changed

+83
-69
lines changed

.gitignore

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,4 @@
11
__pycache__
2-
/tests/
2+
.*
3+
*.xnb
4+
*.out

stardew.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55

66
import xnbread
77

8-
from readers import *
9-
from readers.basic import _read_str, _u32
8+
from xnbread.readers import *
9+
from xnbread.readers.basic import _read_str, _u32
1010

1111
def _bmxml(factory):
1212
# TODO: parse this xml? Nahhh.

xnbread.py

+1-64
Original file line numberDiff line numberDiff line change
@@ -1,70 +1,7 @@
11
#!/usr/bin/env python3
22
#coding=utf8
33

4-
from readers import *
5-
from util import TODO, define_tuple, dumphex, log
6-
import struct
7-
8-
KNOWN_FLAGS = 0x81
9-
FLAG_BIT_HIDEF = 0x01
10-
FLAG_BIT_COMPRESSED = 0x80
11-
12-
Header = define_tuple('Header', '<3scBBI', 10,
13-
'magic target version flags fsize')
14-
15-
def read_payload(f):
16-
header = Header._make(struct.unpack(Header.format, f.read(Header.size)))
17-
assert header.magic == b'XNB'
18-
assert header.target in b'wmx'
19-
assert header.version == 5
20-
assert header.flags & KNOWN_FLAGS == header.flags
21-
if header.flags & FLAG_BIT_COMPRESSED:
22-
import lzx
23-
dsize, = struct.unpack('<I', f.read(4))
24-
csize = header.fsize - Header.size - 4
25-
data = f.read(csize)
26-
assert len(data) == csize
27-
data = lzx.decompress(data, csize, dsize)
28-
assert len(data) == dsize
29-
else:
30-
csize = header.fsize - Header.size
31-
data = f.read(csize)
32-
assert len(data) == csize
33-
return data
34-
35-
def decode_payload(data):
36-
# now that we have the payload, let's decode it
37-
stream = ByteStream(data)
38-
nreaders = stream.read_7bitint()
39-
reader_names = []
40-
for i in range(nreaders):
41-
name = stream.read_string()
42-
version = stream.read_u32()
43-
assert version == 0, "never seen a non-zero version before"
44-
reader_names.append(name)
45-
factory = ObjectFactory(stream, reader_names)
46-
nshared = stream.read_7bitint()
47-
primary = factory.read()
48-
if nshared != 0:
49-
TODO("Haven't implemented shared resources yet")
50-
return primary
51-
52-
def dump(f, raw=False):
53-
data = read_payload(f)
54-
if raw:
55-
sys.stdout.buffer.write(data)
56-
return
57-
out = decode_payload(data)
58-
if type(out) is dict:
59-
for key in out:
60-
print(key, '==>')
61-
print(out[key])
62-
print()
63-
elif type(out) in (list, tuple):
64-
for pair in enumerate(out):
65-
print('%3d: %s' % pair)
66-
else:
67-
print(out)
4+
from xnbread import dump
685

696
if __name__ == '__main__':
707
import sys

xnbread/__init__.py

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
#!/usr/bin/env python3
2+
#coding=utf8
3+
4+
from .container import read_payload, decode_payload, dump
5+
from . import readers

xnbread/container.py

+69
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
#!/usr/bin/env python3
2+
#coding=utf8
3+
4+
from .readers import *
5+
from .util import TODO, define_tuple, dumphex, log
6+
import struct
7+
8+
KNOWN_FLAGS = 0x81
9+
FLAG_BIT_HIDEF = 0x01
10+
FLAG_BIT_COMPRESSED = 0x80
11+
12+
Header = define_tuple('Header', '<3scBBI', 10,
13+
'magic target version flags fsize')
14+
15+
def read_payload(f):
16+
header = Header._make(struct.unpack(Header.format, f.read(Header.size)))
17+
assert header.magic == b'XNB'
18+
assert header.target in b'wmx'
19+
assert header.version == 5
20+
assert header.flags & KNOWN_FLAGS == header.flags
21+
if header.flags & FLAG_BIT_COMPRESSED:
22+
from . import lzx
23+
dsize, = struct.unpack('<I', f.read(4))
24+
csize = header.fsize - Header.size - 4
25+
data = f.read(csize)
26+
assert len(data) == csize
27+
data = lzx.decompress(data, csize, dsize)
28+
assert len(data) == dsize
29+
else:
30+
csize = header.fsize - Header.size
31+
data = f.read(csize)
32+
assert len(data) == csize
33+
return data
34+
35+
def decode_payload(data):
36+
# now that we have the payload, let's decode it
37+
stream = ByteStream(data)
38+
nreaders = stream.read_7bitint()
39+
reader_names = []
40+
for i in range(nreaders):
41+
name = stream.read_string()
42+
version = stream.read_u32()
43+
assert version == 0, "never seen a non-zero version before"
44+
reader_names.append(name)
45+
factory = ObjectFactory(stream, reader_names)
46+
nshared = stream.read_7bitint()
47+
primary = factory.read()
48+
if nshared != 0:
49+
TODO("Haven't implemented shared resources yet")
50+
return primary
51+
52+
def dump(f, raw=False):
53+
import sys
54+
data = read_payload(f)
55+
if raw:
56+
sys.stdout.buffer.write(data)
57+
return
58+
out = decode_payload(data)
59+
if type(out) is dict:
60+
for key in out:
61+
print(key, '==>')
62+
print(out[key])
63+
print()
64+
elif type(out) in (list, tuple):
65+
for pair in enumerate(out):
66+
print('%3d: %s' % pair)
67+
else:
68+
print(out)
69+

lzx.py xnbread/lzx.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
import struct
88

9-
from util import TODO, clamp, dumphex, log
9+
from .util import TODO, clamp, dumphex, log
1010

1111
# block types:
1212
VERBATIM = 1
File renamed without changes.
File renamed without changes.

readers/factory.py xnbread/readers/factory.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@
77
from collections import namedtuple
88
from functools import partial
99
from inspect import signature
10-
from util import TODO, log, dumphex
10+
11+
from ..util import TODO, log, dumphex
1112

1213
GENERIC_READER_PTN = re.compile(r'([^[`]+)(?:`(\d+)\[(.*)\])?')
1314
PLAIN_TYPE_PTN = re.compile(r'([^,]+)(?:, ([^,]+), Version=([0-9.]+), Culture=([^,]+), PublicKeytoken=([a-f0-9]+))?')
File renamed without changes.
File renamed without changes.
File renamed without changes.

util.py xnbread/util.py

File renamed without changes.

0 commit comments

Comments
 (0)