-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathformatiterator.py
More file actions
126 lines (111 loc) · 4.35 KB
/
Copy pathformatiterator.py
File metadata and controls
126 lines (111 loc) · 4.35 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
from rpython.rlib import jit
from rpython.rlib.rarithmetic import ovfcheck
from rpython.rlib.rstruct.error import StructError
from rpython.rlib.rstruct.nativefmttable import native_is_bigendian, native_fmttable
from rpython.rlib.rstruct.standardfmttable import standard_fmttable
from rpython.rlib.unroll import unrolling_iterable
class FormatIterator(object):
"""
An iterator-like object that follows format strings step by step.
It provides input to the packer/unpacker and accumulates their output.
The subclasses are specialized for either packing, unpacking, or
just computing the size.
"""
_mixin_ = True
_operate_is_specialized_ = False
@jit.look_inside_iff(lambda self, fmt: jit.isconstant(fmt))
def interpret(self, fmt):
# decode the byte order, size and alignment based on the 1st char
table = unroll_native_fmtdescs
self.bigendian = native_is_bigendian
index = 0
if len(fmt) > 0:
c = fmt[0]
index = 1
if c == '@':
pass
elif c == '=':
table = unroll_standard_fmtdescs
elif c == '<':
table = unroll_standard_fmtdescs
self.bigendian = False
elif c == '>' or c == '!':
table = unroll_standard_fmtdescs
self.bigendian = True
else:
index = 0
# interpret the format string,
# calling self.operate() for each format unit
while index < len(fmt):
c = fmt[index]
index += 1
if c.isspace():
continue
if c.isdigit():
repetitions = ord(c) - ord('0')
while True:
if index == len(fmt):
raise StructError("incomplete struct format")
c = fmt[index]
index += 1
if not c.isdigit():
break
try:
repetitions = ovfcheck(repetitions * 10)
repetitions = ovfcheck(repetitions + (ord(c) -
ord('0')))
except OverflowError:
raise StructError("overflow in item count")
assert repetitions >= 0
else:
repetitions = 1
for fmtdesc in table:
if c == fmtdesc.fmtchar:
if self._operate_is_specialized_:
if fmtdesc.alignment > 1:
self.align(fmtdesc.mask)
self.operate(fmtdesc, repetitions)
break
else:
if c == '\0':
raise StructError("embedded null character")
raise StructError("bad char in struct format")
if not self._operate_is_specialized_:
if fmtdesc.alignment > 1:
self.align(fmtdesc.mask)
self.operate(fmtdesc, repetitions)
self.finished()
def finished(self):
pass
class CalcSizeFormatIterator(FormatIterator):
totalsize = 0
def operate(self, fmtdesc, repetitions):
try:
size = ovfcheck(fmtdesc.size * repetitions)
self.totalsize = ovfcheck(self.totalsize + size)
except OverflowError:
raise StructError("total struct size too long")
def align(self, mask):
pad = (-self.totalsize) & mask
try:
self.totalsize = ovfcheck(self.totalsize + pad)
except OverflowError:
raise StructError("total struct size too long")
class FmtDesc(object):
def __init__(self, fmtchar, attrs):
self.fmtchar = fmtchar
self.alignment = 1 # by default
self.needcount = False # by default
self.__dict__.update(attrs)
self.mask = self.alignment - 1
assert self.alignment & self.mask == 0, (
"this module assumes that all alignments are powers of two")
def _freeze_(self):
return True
def table2desclist(table):
items = table.items()
items.sort()
lst = [FmtDesc(key, attrs) for key, attrs in items]
return unrolling_iterable(lst)
unroll_standard_fmtdescs = table2desclist(standard_fmttable)
unroll_native_fmtdescs = table2desclist(native_fmttable)