diff options
| -rw-r--r-- | tests/test_parse.py | 5 | ||||
| -rw-r--r-- | viewstate/parse.py | 246 |
2 files changed, 125 insertions, 126 deletions
diff --git a/tests/test_parse.py b/tests/test_parse.py index 570ab96..62f0f23 100644 --- a/tests/test_parse.py +++ b/tests/test_parse.py @@ -6,7 +6,7 @@ from os.path import join from viewstate import * -class TestNewParse(object): +class TestParse(object): def test_const_value(self): vs = ViewState(raw=b'\xff\x01\x67') assert vs.decode() is True @@ -20,9 +20,6 @@ class TestNewParse(object): vs = ViewState(raw=b'\xff\x01\x05' + bytes([len(s)]) + s.encode()) assert vs.decode() == s - -@pytest.mark.skip() -class TestParse(object): def test_simple_dict(self): vs = ViewState(raw=b'\xff\x01\x18\x02\x05\x01a\x05\x01b\x05\x01c\x05\x01d') assert vs.decode() == {'a': 'b', 'c': 'd'} diff --git a/viewstate/parse.py b/viewstate/parse.py index 99fe677..75b82a5 100644 --- a/viewstate/parse.py +++ b/viewstate/parse.py @@ -81,6 +81,7 @@ class String(Parser): s = remain[:n] return s.decode(), remain[n:] + class Enum(Parser): marker = 0x0b @@ -93,6 +94,7 @@ class Enum(Parser): final = 'Enum: {}, val: {}'.format(enum, val) return final, remain + class Color(Parser): marker = 0x0a @@ -102,145 +104,145 @@ class Color(Parser): # Originally reported in https://github.com/yuvadm/viewstate/issues/2 return 'Color: unknown', b[2:] + class Pair(Parser): marker = 0x0f def parse(self, b): - first, remain = parse(b) - second, remain = parse(remain) + first, remain = Parser().parse(b) + second, remain = Parser().parse(remain) return (first, second), remain -def parse_triplet(b): - first, remain = parse(b) - second, remain = parse(remain) - third, remain = parse(remain) - return (first, second, third), remain -def parse_datetime(b): - print([x for x in b[:8]]) - return datetime(2000, 1, 1), b[8:] +class Triplet(Parser): + marker = 0x10 -def parse_unit(b): - print([x for x in b[:12]]) - return 'Unit: ', b[12:] + def parse(self, b): + first, remain = Parser().parse(b) + second, remain = Parser().parse(remain) + third, remain = Parser().parse(remain) + return (first, second, third), remain -def parse_rgba(b): - return 'RGBA({},{},{},{})'.format(*b[:4]), b[4:] -def parse_str_array(b): - n, remain = parse_int(b) - l = [] - for _ in range(n): - if not remain[0]: - val, remain = '', remain[1:] - else: - val, remain = parse_string(remain) - l.append(val) - return l, remain +class Datetime(Parser): + marker = 0x06 + + def parse(self, b): + #print([x for x in b[:8]]) + return datetime(2000, 1, 1), b[8:] + + +class Unit(Parser): + marker = 0x1b + + def parse(self, b): + #print([x for x in b[:12]]) + return 'Unit: ', b[12:] + + +class RGBA(Parser): + marker = 0x09 + + def parse(self, b): + return 'RGBA({},{},{},{})'.format(*b[:4]), b[4:] + + +class StringArray(Parser): + marker = 0x15 + + def parse(self, b): + n, remain = Integer().parse(b) + l = [] + for _ in range(n): + if not remain[0]: + val, remain = '', remain[1:] + else: + val, remain = String().parse(remain) + l.append(val) + return l, remain + -def parse_array(b): - n, remain = parse_int(b) - l = [] - for _ in range(n): - val, remain = parse(remain) - l.append(val) - return l, remain +class Array(Parser): + marker = 0x16 + + def parse(self, b): + n, remain = Integer().parse(b) + l = [] + for _ in range(n): + val, remain = Parser().parse(remain) + l.append(val) + return l, remain -def parse_stringref(b): - val, remain = parse_int(b) - return 'Stringref #{}'.format(val), remain -def parse_formatted_string(b): - if b[0] == 0x29: - s1, remain = parse_string(b[1:]) - s2, remain = parse_string(remain) - return 'Formatted string: {} {}'.format(s2, s1), remain - elif b[0] == 0x2b: - i, remain = parse_int(b[1:]) - s, remain = parse_string(remain) - return 'Formatted string: {} type ref {}'.format(s, i), remain - else: - raise ViewStateException('Unknown formatted string type marker {}'.format(b[:20])) +class StringRef(Parser): + marker = 0x1f -def parse_sparse_array(b): - type, remain = parse_type(b) - length, remain = parse_int(remain) - n, remain = parse_int(remain) - l = [None] * length - for _ in range(n): - idx, remain = parse_int(remain) - val, remain = parse(remain) - l[idx] = val - return l, remain + def parse(self, b): + val, remain = Integer().parse(b) + return 'Stringref #{}'.format(val), remain -def parse_dict(b): - n = b[0] - d = {} - remain = b[1:] - for _ in range(n): - k, remain = parse(remain) - v, remain = parse(remain) - d[k] = v - return d, remain -def parse_type(b): - if b[0] in (0x29, 0x2a): - return parse_string(b[1:]) - elif b[0] == 0x2b: - return parse_int(b[1:]) - else: - raise ViewStateException('Unknown type flag at {} bytes {}'.format(len(b), b[:20])) +class FormattedString(Parser): + marker = 0x28 -def parse_typed_array(b): - typeval, remain = parse_type(b) - n, remain = parse_int(remain) - l = [] - for _ in range(n): - val, remain = parse(remain) - l.append(val) - return l, remain + def parse(self, b): + if b[0] == 0x29: + s1, remain = String().parse(b[1:]) + s2, remain = String().parse(remain) + return 'Formatted string: {} {}'.format(s2, s1), remain + elif b[0] == 0x2b: + i, remain = Integer().parse(b[1:]) + s, remain = String().parse(remain) + return 'Formatted string: {} type ref {}'.format(s, i), remain + else: + raise ViewStateException('Unknown formatted string type marker {}'.format(b[:20])) + + +class SparseArray(Parser): + marker = 0x3c + + def parse(self, b): + type, remain = Type().parse(b) + length, remain = Integer().parse(remain) + n, remain = Integer().parse(remain) + l = [None] * length + for _ in range(n): + idx, remain = Integer().parse(remain) + val, remain = Parser().parse(remain) + l[idx] = val + return l, remain -def parse(b): - if not b: - return None - else: - assert type(b) == bytes().__class__ - if 100 <= b[0] <= 104: - return parse_const(b[0]), b[1:] - elif b[0] == 0x02: - return parse_int(b[1:]) - elif b[0] in (0x05, 0x1e): - return parse_string(b[1:]) - elif b[0] == 0x06: - return parse_datetime(b[1:]) - elif b[0] == 0x09: - return parse_rgba(b[1:]) - elif b[0] == 0x10: - return parse_triplet(b[1:]) - elif b[0] == 0x0a: - return parse_color(b[1:]) - elif b[0] == 0x0b: - return parse_enum(b[1:]) - elif b[0] == 0x0f: - return parse_pair(b[1:]) - elif b[0] == 0x14: - return parse_typed_array(b[1:]) - elif b[0] == 0x15: - return parse_str_array(b[1:]) - elif b[0] == 0x16: - return parse_array(b[1:]) - elif b[0] == 0x18: - return parse_dict(b[1:]) - elif b[0] == 0x1b: - return parse_unit(b[1:]) - elif b[0] == 0x1f: - return parse_stringref(b[1:]) - elif b[0] == 0x28: - return parse_formatted_string(b[1:]) - elif b[0] == 0x3c: - return parse_sparse_array(b[1:]) - else: - raise ViewStateException('Unable to parse remainder of {} bytes {}'.format(len(b), b[:20])) - return b, bytes() +class Dict(Parser): + marker = 0x18 + def parse(self, b): + n = b[0] + d = {} + remain = b[1:] + for _ in range(n): + k, remain = Parser().parse(remain) + v, remain = Parser().parse(remain) + d[k] = v + return d, remain + +class Type(Parser): + def parse(self, b): + if b[0] in (0x29, 0x2a): + return String().parse(b[1:]) + elif b[0] == 0x2b: + return Integer().parse(b[1:]) + else: + raise ViewStateException('Unknown type flag at {} bytes {}'.format(len(b), b[:20])) + +class TypedArray(Parser): + marker = 0x14 + + def parse(self, b): + typeval, remain = Type().parse(b) + n, remain = Integer().parse(remain) + l = [] + for _ in range(n): + val, remain = Parser().parse(remain) + l.append(val) + return l, remain |
