Package pype32 :: Module utils
[hide private]
[frames] | no frames]

Source Code for Module pype32.utils

  1  #!/usr/bin/python 
  2  # -*- coding: utf-8 -*-  
  3   
  4  # Copyright (c) 2013, Nahuel Riva  
  5  # All rights reserved.  
  6  #  
  7  # Redistribution and use in source and binary forms, with or without  
  8  # modification, are permitted provided that the following conditions are met:  
  9  #  
 10  #     * Redistributions of source code must retain the above copyright notice,  
 11  #       this list of conditions and the following disclaimer.  
 12  #     * Redistributions in binary form must reproduce the above copyright  
 13  #       notice,this list of conditions and the following disclaimer in the  
 14  #       documentation and/or other materials provided with the distribution.  
 15  #     * Neither the name of the copyright holder nor the names of its  
 16  #       contributors may be used to endorse or promote products derived from  
 17  #       this software without specific prior written permission.  
 18  #  
 19  # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"  
 20  # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE  
 21  # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE  
 22  # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE  
 23  # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR  
 24  # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF  
 25  # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS  
 26  # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN  
 27  # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)  
 28  # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE  
 29  # POSSIBILITY OF SUCH DAMAGE.  
 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   
51 -def powerOfTwo(value):
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
64 -def allZero(buffer):
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
82 -class WriteData(object):
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
99 - def __len__(self):
100 return len(self.data.buf[self.data.tell():])
101
102 - def __str__(self):
103 return self.data.getvalue()
104
105 - def writeByte(self, byte):
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
114 - def writeWord(self, word):
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
123 - def writeDword(self, dword):
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
132 - def writeQword(self, qword):
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
150 - def setOffset(self, value):
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
163 - def skipBytes(self, nroBytes):
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
172 - def tell(self):
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
181 - def __del__(self):
182 self.data.close() 183 del self.data
184
185 -class ReadData(object):
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
204 - def __len__(self):
205 return len(self.data[self.offset:])
206
207 - def readDword(self):
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
218 - def readWord(self):
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
229 - def readByte(self):
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
240 - def readQword(self):
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
251 - def readString(self):
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
264 - def readAlignedString(self, align = 4):
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
303 - def skipBytes(self, nroBytes):
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
312 - def setOffset(self, value):
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 #if value >= len(self.data): 322 # raise excep.WrongOffsetValueException("Wrong offset value. Must be less than %d" % len(self.data)) 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
348 - def tell(self):
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