1"""Buffers are character arrays that may contain null bytes.
2
3There are a number of variants depending on:
4- how the buffer is allocated (for output buffers), and
5- whether and how the size is passed into and/or out of the called function.
6"""
7
8
9from bgenType import Type, InputOnlyMixIn, OutputOnlyMixIn, InputOnlyType, OutputOnlyType
10from bgenOutput import *
11
12
13# Map common types to their format characters
14type2format = {
15    'long': 'l',
16    'int': 'i',
17    'short': 'h',
18    'char': 'b',
19    'unsigned long': 'l',
20    'unsigned int': 'i',
21    'unsigned short': 'h',
22    'unsigned char': 'b',
23}
24
25
26# ----- PART 1: Fixed character buffers -----
27
28
29class FixedInputOutputBufferType(InputOnlyType):
30
31    """Fixed buffer -- passed as (inbuffer, outbuffer)."""
32
33    def __init__(self, size, datatype = 'char', sizetype = 'int', sizeformat = None):
34        self.typeName = "Buffer"
35        self.size = str(size)
36        self.datatype = datatype
37        self.sizetype = sizetype
38        self.sizeformat = sizeformat or type2format[sizetype]
39        self.label_needed = 0
40
41    def getArgDeclarations(self, name, reference=False, constmode=False, outmode=False):
42        if reference:
43            raise RuntimeError, "Cannot pass buffer types by reference"
44        return (self.getBufferDeclarations(name, constmode, outmode) +
45                self.getSizeDeclarations(name, outmode))
46
47    def getBufferDeclarations(self, name, constmode=False, outmode=False):
48        return self.getInputBufferDeclarations(name, constmode) + \
49                self.getOutputBufferDeclarations(name, constmode, outmode)
50
51    def getInputBufferDeclarations(self, name, constmode=False):
52        if constmode:
53            const = "const "
54        else:
55            const = ""
56        return ["%s%s *%s__in__" % (const, self.datatype, name)]
57
58    def getOutputBufferDeclarations(self, name, constmode=False, outmode=False):
59        if constmode:
60            raise RuntimeError, "Cannot use const output buffer"
61        if outmode:
62            out = "*"
63        else:
64            out = ""
65        return ["%s%s %s__out__[%s]" % (self.datatype, out, name, self.size)]
66
67    def getSizeDeclarations(self, name, outmode=False):
68        if outmode:
69            out = "*"
70        else:
71            out = ""
72        return ["%s%s %s__len__" %(self.sizetype, out, name)]
73
74    def getAuxDeclarations(self, name):
75        return ["int %s__in_len__" %(name)]
76
77    def getargsFormat(self):
78        return "s#"
79
80    def getargsArgs(self, name):
81        return "&%s__in__, &%s__in_len__" % (name, name)
82
83    def getargsCheck(self, name):
84        Output("if (%s__in_len__ != %s)", name, self.size)
85        OutLbrace()
86        Output('PyErr_SetString(PyExc_TypeError, "buffer length should be %s");',
87               self.size)
88        Output("goto %s__error__;", name)
89        self.label_needed = 1
90        OutRbrace()
91        self.transferSize(name)
92
93    def transferSize(self, name):
94        Output("%s__len__ = %s__in_len__;", name, name)
95
96    def passOutput(self, name):
97        return "%s__in__, %s__out__" % (name, name)
98
99    def mkvalueFormat(self):
100        return "s#"
101
102    def mkvalueArgs(self, name):
103        return "%s__out__, (int)%s" % (name, self.size)
104
105    def cleanup(self, name):
106        if self.label_needed:
107            DedentLevel()
108            Output(" %s__error__: ;", name)
109            IndentLevel()
110
111
112class FixedCombinedInputOutputBufferType(FixedInputOutputBufferType):
113
114    """Like fixed buffer -- but same parameter is input and output."""
115
116    def passOutput(self, name):
117        return "(%s *)memcpy(%s__out__, %s__in__, %s)" % \
118            (self.datatype, name,   name,     self.size)
119
120
121class InputOnlyBufferMixIn(InputOnlyMixIn):
122
123    def getOutputBufferDeclarations(self, name, constmode=False, outmode=False):
124        return []
125
126
127class OutputOnlyBufferMixIn(OutputOnlyMixIn):
128
129    def getInputBufferDeclarations(self, name, constmode=False):
130        return []
131
132class OptionalInputBufferMixIn:
133
134    """Add to input buffers if the buffer may be omitted: pass None in Python
135    and the C code will get a NULL pointer and zero size"""
136
137    def getargsFormat(self):
138        return "z#"
139
140
141class FixedInputBufferType(InputOnlyBufferMixIn, FixedInputOutputBufferType):
142
143    """Fixed size input buffer -- passed without size information.
144
145    Instantiate with the size as parameter.
146    """
147
148    def passInput(self, name):
149        return "%s__in__" % name
150
151class OptionalFixedInputBufferType(OptionalInputBufferMixIn, FixedInputBufferType):
152    pass
153
154class FixedOutputBufferType(OutputOnlyBufferMixIn, FixedInputOutputBufferType):
155
156    """Fixed size output buffer -- passed without size information.
157
158    Instantiate with the size as parameter.
159    """
160
161    def passOutput(self, name):
162        return "%s__out__" % name
163
164
165class VarInputBufferType(FixedInputBufferType):
166
167    """Variable size input buffer -- passed as (buffer, size).
168
169    Instantiate without size parameter.
170    """
171
172    def __init__(self, datatype = 'char', sizetype = 'int', sizeformat = None):
173        FixedInputBufferType.__init__(self, "0", datatype, sizetype, sizeformat)
174
175    def getargsCheck(self, name):
176        Output("%s__len__ = %s__in_len__;", name, name)
177
178    def passInput(self, name):
179        return "%s__in__, %s__len__" % (name, name)
180
181class ReverseInputBufferMixin:
182    """ Mixin for input buffers that are passed as (size, buffer) """
183
184    def passInput(self, name):
185        return "%s__len__, %s__in__" % (name, name)
186
187class OptionalVarInputBufferType(OptionalInputBufferMixIn, VarInputBufferType):
188    pass
189
190# ----- PART 2: Structure buffers -----
191
192
193class StructInputOutputBufferType(FixedInputOutputBufferType):
194
195    """Structure buffer -- passed as a structure pointer.
196
197    Instantiate with the struct type as parameter.
198    """
199
200    def __init__(self, type):
201        FixedInputOutputBufferType.__init__(self, "sizeof(%s)" % type)
202        self.typeName = self.type = type
203
204    def getInputBufferDeclarations(self, name, constmode=False):
205        if constmode:
206            const = "const "
207        else:
208            const = ""
209        return ["%s%s *%s__in__" % (const, self.type, name)]
210
211    def getSizeDeclarations(self, name, outmode=False):
212        return []
213
214    def getAuxDeclarations(self, name):
215        return ["int %s__in_len__" % (name)]
216
217    def getOutputBufferDeclarations(self, name, constmode=False, outmode=False):
218        if constmode:
219            raise RuntimeError, "Cannot use const output buffer"
220        if outmode:
221            out = "*"
222        else:
223            out = ""
224        return ["%s%s %s__out__" % (self.type, out, name)]
225
226    def getargsArgs(self, name):
227        return "(char **)&%s__in__, &%s__in_len__" % (name, name)
228
229    def transferSize(self, name):
230        pass
231
232    def passInput(self, name):
233        return "%s__in__" % name
234
235    def passOutput(self, name):
236        return "%s__in__, &%s__out__" % (name, name)
237
238    def mkvalueArgs(self, name):
239        return "(char *)&%s__out__, (int)%s" % (name, self.size)
240
241
242class StructCombinedInputOutputBufferType(StructInputOutputBufferType):
243
244    """Like structure buffer -- but same parameter is input and output."""
245
246    def passOutput(self, name):
247        return "(%s *)memcpy((char *)%s__out__, (char *)%s__in__, %s)" % \
248            (self.type,          name,              name,     self.size)
249
250
251class StructInputBufferType(InputOnlyBufferMixIn, StructInputOutputBufferType):
252
253    """Fixed size input buffer -- passed as a pointer to a structure.
254
255    Instantiate with the struct type as parameter.
256    """
257
258
259class StructByValueBufferType(StructInputBufferType):
260
261    """Fixed size input buffer -- passed as a structure BY VALUE.
262
263    Instantiate with the struct type as parameter.
264    """
265
266    def passInput(self, name):
267        return "*%s__in__" % name
268
269
270class StructOutputBufferType(OutputOnlyBufferMixIn, StructInputOutputBufferType):
271
272    """Fixed size output buffer -- passed as a pointer to a structure.
273
274    Instantiate with the struct type as parameter.
275    """
276
277    def getSizeDeclarations(self, name, outmode=False):
278        return []
279
280    def getAuxDeclarations(self, name):
281        return []
282
283    def passOutput(self, name):
284        return "&%s__out__" % name
285
286
287class ArrayOutputBufferType(OutputOnlyBufferMixIn, StructInputOutputBufferType):
288
289    """Fixed size output buffer -- declared as a typedef, passed as an array.
290
291    Instantiate with the struct type as parameter.
292    """
293
294    def getSizeDeclarations(self, name, outmode=False):
295        return []
296
297    def getAuxDeclarations(self, name):
298        return []
299
300    def passOutput(self, name):
301        return "%s__out__" % name
302