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 Auxiliary classes and functions.
33
34 @group Read/Write data stream objects:
35 ReadData, WriteData
36 """
37
38 __revision__ = "$Id$"
39
40 __all__ = [
41 "ReadData",
42 "WriteData",
43 ]
44
45 import excep
46
47 from cStringIO import StringIO as cstringio
48 from StringIO import StringIO
49 from struct import pack, unpack
50
52 """
53 Tries to determine if a given value is a power of two.
54
55 @type value: int
56 @param value: Value to test if it is power of two.
57
58 @rtype: bool
59 @return: C{True} if the value is power of two,
60 C{False} if it doesn't.
61 """
62 return value != 0 and (value & (value - 1)) == 0
63
65 """
66 Tries to determine if a buffer is empty.
67
68 @type buffer: str
69 @param buffer: Buffer to test if it is empty.
70
71 @rtype: bool
72 @return: C{True} if the given buffer is empty, i.e. full of zeros,
73 C{False} if it doesn't.
74 """
75 allZero = True
76 for byte in buffer:
77 if byte != "\x00":
78 allZero = False
79 break
80 return allZero
81
83 """Return a WriteData-like stream object for writing."""
84 - def __init__(self, data, endianness = "<", signed = False):
85 """
86 @type data: str
87 @param data: Data to create the L{WriteData} object.
88
89 @type endianness: str
90 @param endianness: (Optional) Indicates the endianness used to write the data. The C{<} indicates little-endian while C{>} indicates big-endian.
91
92 @type signed: bool
93 @param signed: (Optional) If set to C{True} the data will be treated as signed. If set to C{False} it will be treated as unsigned.
94 """
95 self.data = StringIO(data)
96 self.endianness = endianness
97 self.signed = signed
98
100 return len(self.data.buf[self.data.tell():])
101
103 return self.data.getvalue()
104
106 """
107 Writes a byte into the L{WriteData} stream object.
108
109 @type byte: int
110 @param byte: Byte value to write into the stream.
111 """
112 self.data.write(pack("B" if not self.signed else "b", byte))
113
115 """
116 Writes a word value into the L{WriteData} stream object.
117
118 @type word: int
119 @param word: Word value to write into the stream.
120 """
121 self.data.write(pack(self.endianness + ("H" if not self.signed else "h"), word))
122
124 """
125 Writes a dword value into the L{WriteData} stream object.
126
127 @type dword: int
128 @param dword: Dword value to write into the stream.
129 """
130 self.data.write(pack(self.endianness + ("L" if not self.signed else "l"), dword))
131
133 """
134 Writes a qword value into the L{WriteData} stream object.
135
136 @type qword: int
137 @param qword: Qword value to write into the stream.
138 """
139 self.data.write(pack(self.endianness + ("Q" if not self.signed else "q"), qword))
140
141 - def write(self, dataToWrite):
142 """
143 Writes data into the L{WriteData} stream object.
144
145 @type dataToWrite: str
146 @param dataToWrite: Data to write into the stream.
147 """
148 self.data.write(dataToWrite)
149
151 """
152 Sets the offset of the L{WriteData} stream object in wich the data is written.
153
154 @type value: int
155 @param value: Integer value that represent the offset we want to start writing in the L{WriteData} stream.
156
157 @raise WrongOffsetValueException: The value is beyond the total length of the data.
158 """
159 if value >= len(self.data.getvalue()):
160 raise excep.WrongOffsetValueException("Wrong offset value. Must be less than %d" % len(self.data))
161 self.data.seek(value)
162
164 """
165 Skips the specified number as parameter to the current value of the L{WriteData} stream.
166
167 @type nroBytes: int
168 @param nroBytes: The number of bytes to skip.
169 """
170 self.data.seek(nroBytes + self.data.tell())
171
173 """
174 Returns the current position of the offset in the L{WriteData} sream object.
175
176 @rtype: int
177 @return: The value of the current offset in the stream.
178 """
179 return self.data.tell()
180
182 self.data.close()
183 del self.data
184
186 """Returns a ReadData-like stream object."""
187 - def __init__(self, data, endianness = "<", signed = False):
188 """
189 @type data: str
190 @param data: The data from which we want to read.
191
192 @type endianness: str
193 @param endianness: (Optional) Indicates the endianness used to read the data. The C{<} indicates little-endian while C{>} indicates big-endian.
194
195 @type signed: bool
196 @param signed: (Optional) If set to C{True} the data will be treated as signed. If set to C{False} it will be treated as unsigned.
197 """
198 self.data = data
199 self.offset = 0
200 self.endianness = endianness
201 self.signed = signed
202 self.log = False
203
205 return len(self.data[self.offset:])
206
208 """
209 Reads a dword value from the L{ReadData} stream object.
210
211 @rtype: int
212 @return: The dword value read from the L{ReadData} stream.
213 """
214 dword = unpack(self.endianness + ('L' if not self.signed else 'l'), self.readAt(self.offset, 4))[0]
215 self.offset += 4
216 return dword
217
219 """
220 Reads a word value from the L{ReadData} stream object.
221
222 @rtype: int
223 @return: The word value read from the L{ReadData} stream.
224 """
225 word = unpack(self.endianness + ('H' if not self.signed else 'h'), self.readAt(self.offset, 2))[0]
226 self.offset += 2
227 return word
228
230 """
231 Reads a byte value from the L{ReadData} stream object.
232
233 @rtype: int
234 @return: The byte value read from the L{ReadData} stream.
235 """
236 byte = unpack('B' if not self.signed else 'b', self.readAt(self.offset, 1))[0]
237 self.offset += 1
238 return byte
239
241 """
242 Reads a qword value from the L{ReadData} stream object.
243
244 @rtype: int
245 @return: The qword value read from the L{ReadData} stream.
246 """
247 qword = unpack(self.endianness + ('Q' if not self.signed else 'b'), self.readAt(self.offset, 8))[0]
248 self.offset += 8
249 return qword
250
252 """
253 Reads an ASCII string from the L{ReadData} stream object.
254
255 @rtype: str
256 @return: An ASCII string read form the stream.
257 """
258 resultStr = ""
259 while self.data[self.offset] != "\x00":
260 resultStr += self.data[self.offset]
261 self.offset += 1
262 return resultStr
263
265 """
266 Reads an ASCII string aligned to the next align-bytes boundary.
267
268 @type align: int
269 @param align: (Optional) The value we want the ASCII string to be aligned.
270
271 @rtype: str
272 @return: A 4-bytes aligned (default) ASCII string.
273 """
274 s = self.readString()
275 r = align - len(s) % align
276 while r:
277 s += self.data[self.offset]
278 self.offset += 1
279 r -= 1
280 return s
281
282 - def read(self, nroBytes):
283 """
284 Reads data from the L{ReadData} stream object.
285
286 @type nroBytes: int
287 @param nroBytes: The number of bytes to read.
288
289 @rtype: str
290 @return: A string containing the read data from the L{ReadData} stream object.
291
292 @raise DataLengthException: The number of bytes tried to be read are more than the remaining in the L{ReadData} stream.
293 """
294 if nroBytes > len(self.data[self.offset:]):
295 if self.log:
296 print "Warning: Trying to read: %d bytes - only %d bytes left" % (nroBytes, len(self.data[self.offset:]))
297 nroBytes = len(self.data[self.offset:])
298
299 resultStr = self.data[self.offset:self.offset + nroBytes]
300 self.offset += nroBytes
301 return resultStr
302
304 """
305 Skips the specified number as parameter to the current value of the L{ReadData} stream.
306
307 @type nroBytes: int
308 @param nroBytes: The number of bytes to skip.
309 """
310 self.offset += nroBytes
311
313 """
314 Sets the offset of the L{ReadData} stream object in wich the data is read.
315
316 @type value: int
317 @param value: Integer value that represent the offset we want to start reading in the L{ReadData} stream.
318
319 @raise WrongOffsetValueException: The value is beyond the total length of the data.
320 """
321
322
323 self.offset = value
324
325 - def readAt(self, offset, size):
326 """
327 Reads as many bytes indicated in the size parameter at the specific offset.
328
329 @type offset: int
330 @param offset: Offset of the value to be read.
331
332 @type size: int
333 @param size: This parameter indicates how many bytes are going to be read from a given offset.
334
335 @rtype: str
336 @return: A packed string containing the read data.
337 """
338 if offset > len(self.data):
339 if self.log:
340 print "Warning: Trying to read: %d bytes - only %d bytes left" % (nroBytes, len(self.data[self.offset:]))
341 offset = len(self.data[self.offset:])
342 tmpOff = self.tell()
343 self.setOffset(offset)
344 r = self.read(size)
345 self.setOffset(tmpOff)
346 return r
347
349 """
350 Returns the current position of the offset in the L{ReadData} sream object.
351
352 @rtype: int
353 @return: The value of the current offset in the stream.
354 """
355 return self.offset
356