2019-04-04 19:32:39 -04:00
from __future__ import print_function
2017-06-30 08:53:19 -04:00
# Copyright (c) 2003-2016 CORE Security Technologies
#
# This software is provided under under a slightly modified version
# of the Apache Software License. See the accompanying LICENSE file
# for more information.
#
from struct import pack , unpack , calcsize
class Structure :
""" sublcasses can define commonHdr and/or structure.
each of them is an tuple of either two : ( fieldName , format ) or three : ( fieldName , ' : ' , class ) fields .
[ it can ' t be a dictionary, because order is important]
where format specifies how the data in the field will be converted to / from bytes ( string )
class is the class to use when unpacking ' : ' fields .
each field can only contain one value ( or an array of values for * )
i . e . struct . pack ( ' Hl ' , 1 , 2 ) is valid , but format specifier ' Hl ' is not ( you must use 2 dfferent fields )
format specifiers :
specifiers from module pack can be used with the same format
see struct . __doc__ ( pack / unpack is finally called )
x [ padding byte ]
c [ character ]
b [ signed byte ]
B [ unsigned byte ]
h [ signed short ]
H [ unsigned short ]
l [ signed long ]
L [ unsigned long ]
i [ signed integer ]
I [ unsigned integer ]
q [ signed long long ( quad ) ]
Q [ unsigned long long ( quad ) ]
s [ string ( array of chars ) , must be preceded with length in format specifier , padded with zeros ]
p [ pascal string ( includes byte count ) , must be preceded with length in format specifier , padded with zeros ]
f [ float ]
d [ double ]
= [ native byte ordering , size and alignment ]
@ [ native byte ordering , standard size and alignment ]
! [ network byte ordering ]
< [ little endian ]
> [ big endian ]
usual printf like specifiers can be used ( if started with % )
[ not recommeneded , there is no why to unpack this ]
% 08 x will output an 8 bytes hex
% s will output a string
% s \\x00 will output a NUL terminated string
% d % d will output 2 decimal digits ( against the very same specification of Structure )
. . .
some additional format specifiers :
: just copy the bytes from the field into the output string ( input may be string , other structure , or anything responding to __str__ ( ) ) ( for unpacking , all what ' s left is returned)
z same as : , but adds a NUL byte at the end ( asciiz ) ( for unpacking the first NUL byte is used as terminator ) [ asciiz string ]
u same as z , but adds two NUL bytes at the end ( after padding to an even size with NULs ) . ( same for unpacking ) [ unicode string ]
w DCE - RPC / NDR string ( it ' s a macro for [ ' < L = ( len ( field ) + 1 ) / 2 ' , ' " \\ x00 \\ x00 \\ x00 \\ x00 ' , ' <L=(len(field)+1)/2 ' , ' : ' ]
? - field length of field named ' field ' , formated as specified with ? ( ' ? ' may be ' !H ' for example ) . The input value overrides the real length
? 1 * ? 2 array of elements . Each formated as ' ?2 ' , the number of elements in the array is stored as specified by ' ?1 ' ( ? 1 is optional , or can also be a constant ( number ) , for unpacking )
' xxxx literal xxxx (field ' s value doesn ' t change the output. quotes must not be closed or escaped)
" xxxx literal xxxx (field ' s value doesn ' t change the output. quotes must not be closed or escaped)
_ will not pack the field . Accepts a third argument , which is an unpack code . See _Test_UnpackCode for an example
? = packcode will evaluate packcode in the context of the structure , and pack the result as specified by ? . Unpacking is made plain
? & fieldname " Address of field fieldname " .
For packing it will simply pack the id ( ) of fieldname . Or use 0 if fieldname doesn ' t exists.
For unpacking , it ' s used to know weather fieldname has to be unpacked or not, i.e. by adding a & field you turn another field (fieldname) in an optional field.
"""
commonHdr = ( )
structure = ( )
debug = 0
def __init__ ( self , data = None , alignment = 0 ) :
if not hasattr ( self , ' alignment ' ) :
self . alignment = alignment
self . fields = { }
self . rawData = data
if data is not None :
self . fromString ( data )
else :
self . data = None
@classmethod
def fromFile ( self , file ) :
answer = self ( )
answer . fromString ( file . read ( len ( answer ) ) )
return answer
def setAlignment ( self , alignment ) :
self . alignment = alignment
def setData ( self , data ) :
self . data = data
def packField ( self , fieldName , format = None ) :
if self . debug :
2019-04-04 19:32:39 -04:00
print ( " packField( %s | %s ) " % ( fieldName , format ) )
2017-06-30 08:53:19 -04:00
if format is None :
format = self . formatForField ( fieldName )
2019-04-04 19:32:39 -04:00
if fieldName in self . fields :
2017-06-30 08:53:19 -04:00
ans = self . pack ( format , self . fields [ fieldName ] , field = fieldName )
else :
ans = self . pack ( format , None , field = fieldName )
if self . debug :
2019-04-04 19:32:39 -04:00
print ( " \t answer %r " % ans )
2017-06-30 08:53:19 -04:00
return ans
def getData ( self ) :
if self . data is not None :
return self . data
data = ' '
for field in self . commonHdr + self . structure :
try :
data + = self . packField ( field [ 0 ] , field [ 1 ] )
2019-04-04 19:32:39 -04:00
except Exception as e :
if field [ 0 ] in self . fields :
2017-06-30 08:53:19 -04:00
e . args + = ( " When packing field ' %s | %s | %r ' in %s " % ( field [ 0 ] , field [ 1 ] , self [ field [ 0 ] ] , self . __class__ ) , )
else :
e . args + = ( " When packing field ' %s | %s ' in %s " % ( field [ 0 ] , field [ 1 ] , self . __class__ ) , )
raise
if self . alignment :
if len ( data ) % self . alignment :
data + = ( ' \x00 ' * self . alignment ) [ : - ( len ( data ) % self . alignment ) ]
#if len(data) % self.alignment: data += ('\x00'*self.alignment)[:-(len(data) % self.alignment)]
return data
def fromString ( self , data ) :
self . rawData = data
for field in self . commonHdr + self . structure :
if self . debug :
2019-04-04 19:32:39 -04:00
print ( " fromString( %s | %s | %r ) " % ( field [ 0 ] , field [ 1 ] , data ) )
2017-06-30 08:53:19 -04:00
size = self . calcUnpackSize ( field [ 1 ] , data , field [ 0 ] )
if self . debug :
2019-04-04 19:32:39 -04:00
print ( " size = %d " % size )
2017-06-30 08:53:19 -04:00
dataClassOrCode = str
if len ( field ) > 2 :
dataClassOrCode = field [ 2 ]
try :
self [ field [ 0 ] ] = self . unpack ( field [ 1 ] , data [ : size ] , dataClassOrCode = dataClassOrCode , field = field [ 0 ] )
2019-04-04 19:32:39 -04:00
except Exception as e :
2017-06-30 08:53:19 -04:00
e . args + = ( " When unpacking field ' %s | %s | %r [: %d ] ' " % ( field [ 0 ] , field [ 1 ] , data , size ) , )
raise
size = self . calcPackSize ( field [ 1 ] , self [ field [ 0 ] ] , field [ 0 ] )
if self . alignment and size % self . alignment :
size + = self . alignment - ( size % self . alignment )
data = data [ size : ]
return self
def __setitem__ ( self , key , value ) :
self . fields [ key ] = value
self . data = None # force recompute
def __getitem__ ( self , key ) :
return self . fields [ key ]
def __delitem__ ( self , key ) :
del self . fields [ key ]
def __str__ ( self ) :
return self . getData ( )
def __len__ ( self ) :
# XXX: improve
return len ( self . getData ( ) )
def pack ( self , format , data , field = None ) :
if self . debug :
2019-04-04 19:32:39 -04:00
print ( " pack( %s | %r | %s ) " % ( format , data , field ) )
2017-06-30 08:53:19 -04:00
if field :
addressField = self . findAddressFieldFor ( field )
if ( addressField is not None ) and ( data is None ) :
return ' '
# void specifier
if format [ : 1 ] == ' _ ' :
return ' '
# quote specifier
if format [ : 1 ] == " ' " or format [ : 1 ] == ' " ' :
return format [ 1 : ]
# code specifier
two = format . split ( ' = ' )
if len ( two ) > = 2 :
try :
return self . pack ( two [ 0 ] , data )
except :
fields = { ' self ' : self }
fields . update ( self . fields )
return self . pack ( two [ 0 ] , eval ( two [ 1 ] , { } , fields ) )
# address specifier
two = format . split ( ' & ' )
if len ( two ) == 2 :
try :
return self . pack ( two [ 0 ] , data )
except :
2019-04-04 19:32:39 -04:00
if ( two [ 1 ] in self . fields ) and ( self [ two [ 1 ] ] is not None ) :
2017-06-30 08:53:19 -04:00
return self . pack ( two [ 0 ] , id ( self [ two [ 1 ] ] ) & ( ( 1 << ( calcsize ( two [ 0 ] ) * 8 ) ) - 1 ) )
else :
return self . pack ( two [ 0 ] , 0 )
# length specifier
two = format . split ( ' - ' )
if len ( two ) == 2 :
try :
return self . pack ( two [ 0 ] , data )
except :
return self . pack ( two [ 0 ] , self . calcPackFieldSize ( two [ 1 ] ) )
# array specifier
two = format . split ( ' * ' )
if len ( two ) == 2 :
answer = ' '
for each in data :
answer + = self . pack ( two [ 1 ] , each )
if two [ 0 ] :
if two [ 0 ] . isdigit ( ) :
if int ( two [ 0 ] ) != len ( data ) :
2019-04-04 19:32:39 -04:00
raise Exception ( " Array field has a constant size, and it doesn ' t match the actual value " )
2017-06-30 08:53:19 -04:00
else :
return self . pack ( two [ 0 ] , len ( data ) ) + answer
return answer
# "printf" string specifier
if format [ : 1 ] == ' % ' :
# format string like specifier
return format % data
# asciiz specifier
if format [ : 1 ] == ' z ' :
return str ( data ) + ' \0 '
# unicode specifier
if format [ : 1 ] == ' u ' :
return str ( data ) + ' \0 \0 ' + ( len ( data ) & 1 and ' \0 ' or ' ' )
# DCE-RPC/NDR string specifier
if format [ : 1 ] == ' w ' :
if len ( data ) == 0 :
data = ' \0 \0 '
elif len ( data ) % 2 :
data + = ' \0 '
l = pack ( ' <L ' , len ( data ) / 2 )
return ' %s \0 \0 \0 \0 %s %s ' % ( l , l , data )
if data is None :
2019-04-04 19:32:39 -04:00
raise Exception ( " Trying to pack None " )
2017-06-30 08:53:19 -04:00
# literal specifier
if format [ : 1 ] == ' : ' :
return str ( data )
# struct like specifier
return pack ( format , data )
def unpack ( self , format , data , dataClassOrCode = str , field = None ) :
if self . debug :
2019-04-04 19:32:39 -04:00
print ( " unpack( %s | %r ) " % ( format , data ) )
2017-06-30 08:53:19 -04:00
if field :
addressField = self . findAddressFieldFor ( field )
if addressField is not None :
if not self [ addressField ] :
return
# void specifier
if format [ : 1 ] == ' _ ' :
if dataClassOrCode != str :
fields = { ' self ' : self , ' inputDataLeft ' : data }
fields . update ( self . fields )
return eval ( dataClassOrCode , { } , fields )
else :
return None
# quote specifier
if format [ : 1 ] == " ' " or format [ : 1 ] == ' " ' :
answer = format [ 1 : ]
if answer != data :
2019-04-04 19:32:39 -04:00
raise Exception ( " Unpacked data doesn ' t match constant value ' %r ' should be ' %r ' " % ( data , answer ) )
2017-06-30 08:53:19 -04:00
return answer
# address specifier
two = format . split ( ' & ' )
if len ( two ) == 2 :
return self . unpack ( two [ 0 ] , data )
# code specifier
two = format . split ( ' = ' )
if len ( two ) > = 2 :
return self . unpack ( two [ 0 ] , data )
# length specifier
two = format . split ( ' - ' )
if len ( two ) == 2 :
return self . unpack ( two [ 0 ] , data )
# array specifier
two = format . split ( ' * ' )
if len ( two ) == 2 :
answer = [ ]
sofar = 0
if two [ 0 ] . isdigit ( ) :
number = int ( two [ 0 ] )
elif two [ 0 ] :
sofar + = self . calcUnpackSize ( two [ 0 ] , data )
number = self . unpack ( two [ 0 ] , data [ : sofar ] )
else :
number = - 1
while number and sofar < len ( data ) :
nsofar = sofar + self . calcUnpackSize ( two [ 1 ] , data [ sofar : ] )
answer . append ( self . unpack ( two [ 1 ] , data [ sofar : nsofar ] , dataClassOrCode ) )
number - = 1
sofar = nsofar
return answer
# "printf" string specifier
if format [ : 1 ] == ' % ' :
# format string like specifier
return format % data
# asciiz specifier
if format == ' z ' :
if data [ - 1 ] != ' \x00 ' :
2019-04-04 19:32:39 -04:00
raise Exception ( " %s ' z ' field is not NUL terminated: %r " % ( field , data ) )
2017-06-30 08:53:19 -04:00
return data [ : - 1 ] # remove trailing NUL
# unicode specifier
if format == ' u ' :
if data [ - 2 : ] != ' \x00 \x00 ' :
2019-04-04 19:32:39 -04:00
raise Exception ( " %s ' u ' field is not NUL-NUL terminated: %r " % ( field , data ) )
2017-06-30 08:53:19 -04:00
return data [ : - 2 ] # remove trailing NUL
# DCE-RPC/NDR string specifier
if format == ' w ' :
l = unpack ( ' <L ' , data [ : 4 ] ) [ 0 ]
return data [ 12 : 12 + l * 2 ]
# literal specifier
if format == ' : ' :
return dataClassOrCode ( data )
# struct like specifier
return unpack ( format , data ) [ 0 ]
def calcPackSize ( self , format , data , field = None ) :
# # print " calcPackSize %s:%r" % (format, data)
if field :
addressField = self . findAddressFieldFor ( field )
if addressField is not None :
if not self [ addressField ] :
return 0
# void specifier
if format [ : 1 ] == ' _ ' :
return 0
# quote specifier
if format [ : 1 ] == " ' " or format [ : 1 ] == ' " ' :
return len ( format ) - 1
# address specifier
two = format . split ( ' & ' )
if len ( two ) == 2 :
return self . calcPackSize ( two [ 0 ] , data )
# code specifier
two = format . split ( ' = ' )
if len ( two ) > = 2 :
return self . calcPackSize ( two [ 0 ] , data )
# length specifier
two = format . split ( ' - ' )
if len ( two ) == 2 :
return self . calcPackSize ( two [ 0 ] , data )
# array specifier
two = format . split ( ' * ' )
if len ( two ) == 2 :
answer = 0
if two [ 0 ] . isdigit ( ) :
if int ( two [ 0 ] ) != len ( data ) :
2019-04-04 19:32:39 -04:00
raise Exception ( " Array field has a constant size, and it doesn ' t match the actual value " )
2017-06-30 08:53:19 -04:00
elif two [ 0 ] :
answer + = self . calcPackSize ( two [ 0 ] , len ( data ) )
for each in data :
answer + = self . calcPackSize ( two [ 1 ] , each )
return answer
# "printf" string specifier
if format [ : 1 ] == ' % ' :
# format string like specifier
return len ( format % data )
# asciiz specifier
if format [ : 1 ] == ' z ' :
return len ( data ) + 1
# asciiz specifier
if format [ : 1 ] == ' u ' :
l = len ( data )
return l + ( l & 1 and 3 or 2 )
# DCE-RPC/NDR string specifier
if format [ : 1 ] == ' w ' :
l = len ( data )
return 12 + l + l % 2
# literal specifier
if format [ : 1 ] == ' : ' :
return len ( data )
# struct like specifier
return calcsize ( format )
def calcUnpackSize ( self , format , data , field = None ) :
if self . debug :
2019-04-04 19:32:39 -04:00
print ( " calcUnpackSize( %s | %s | %r ) " % ( field , format , data ) )
2017-06-30 08:53:19 -04:00
# void specifier
if format [ : 1 ] == ' _ ' :
return 0
addressField = self . findAddressFieldFor ( field )
if addressField is not None :
if not self [ addressField ] :
return 0
try :
lengthField = self . findLengthFieldFor ( field )
return self [ lengthField ]
except :
pass
# XXX: Try to match to actual values, raise if no match
# quote specifier
if format [ : 1 ] == " ' " or format [ : 1 ] == ' " ' :
return len ( format ) - 1
# address specifier
two = format . split ( ' & ' )
if len ( two ) == 2 :
return self . calcUnpackSize ( two [ 0 ] , data )
# code specifier
two = format . split ( ' = ' )
if len ( two ) > = 2 :
return self . calcUnpackSize ( two [ 0 ] , data )
# length specifier
two = format . split ( ' - ' )
if len ( two ) == 2 :
return self . calcUnpackSize ( two [ 0 ] , data )
# array specifier
two = format . split ( ' * ' )
if len ( two ) == 2 :
answer = 0
if two [ 0 ] :
if two [ 0 ] . isdigit ( ) :
number = int ( two [ 0 ] )
else :
answer + = self . calcUnpackSize ( two [ 0 ] , data )
number = self . unpack ( two [ 0 ] , data [ : answer ] )
while number :
number - = 1
answer + = self . calcUnpackSize ( two [ 1 ] , data [ answer : ] )
else :
while answer < len ( data ) :
answer + = self . calcUnpackSize ( two [ 1 ] , data [ answer : ] )
return answer
# "printf" string specifier
if format [ : 1 ] == ' % ' :
2019-04-04 19:32:39 -04:00
raise Exception ( " Can ' t guess the size of a printf like specifier for unpacking " )
2017-06-30 08:53:19 -04:00
# asciiz specifier
if format [ : 1 ] == ' z ' :
return data . index ( ' \x00 ' ) + 1
# asciiz specifier
if format [ : 1 ] == ' u ' :
l = data . index ( ' \x00 \x00 ' )
return l + ( l & 1 and 3 or 2 )
# DCE-RPC/NDR string specifier
if format [ : 1 ] == ' w ' :
l = unpack ( ' <L ' , data [ : 4 ] ) [ 0 ]
return 12 + l * 2
# literal specifier
if format [ : 1 ] == ' : ' :
return len ( data )
# struct like specifier
return calcsize ( format )
def calcPackFieldSize ( self , fieldName , format = None ) :
if format is None :
format = self . formatForField ( fieldName )
return self . calcPackSize ( format , self [ fieldName ] )
def formatForField ( self , fieldName ) :
for field in self . commonHdr + self . structure :
if field [ 0 ] == fieldName :
return field [ 1 ]
2019-04-04 19:32:39 -04:00
raise Exception ( " Field %s not found " % fieldName )
2017-06-30 08:53:19 -04:00
def findAddressFieldFor ( self , fieldName ) :
descriptor = ' & %s ' % fieldName
l = len ( descriptor )
for field in self . commonHdr + self . structure :
if field [ 1 ] [ - l : ] == descriptor :
return field [ 0 ]
return None
def findLengthFieldFor ( self , fieldName ) :
descriptor = ' - %s ' % fieldName
l = len ( descriptor )
for field in self . commonHdr + self . structure :
if field [ 1 ] [ - l : ] == descriptor :
return field [ 0 ]
return None
def zeroValue ( self , format ) :
two = format . split ( ' * ' )
if len ( two ) == 2 :
if two [ 0 ] . isdigit ( ) :
return ( self . zeroValue ( two [ 1 ] ) , ) * int ( two [ 0 ] )
if not format . find ( ' * ' ) == - 1 : return ( )
if ' s ' in format : return ' '
if format in [ ' z ' , ' : ' , ' u ' ] : return ' '
if format == ' w ' : return ' \x00 \x00 '
return 0
def clear ( self ) :
for field in self . commonHdr + self . structure :
self [ field [ 0 ] ] = self . zeroValue ( field [ 1 ] )
def dump ( self , msg = None , indent = 0 ) :
if msg is None : msg = self . __class__ . __name__
ind = ' ' * indent
2019-04-04 19:32:39 -04:00
print ( " \n %s " % msg )
2017-06-30 08:53:19 -04:00
fixedFields = [ ]
for field in self . commonHdr + self . structure :
i = field [ 0 ]
if i in self . fields :
fixedFields . append ( i )
if isinstance ( self [ i ] , Structure ) :
self [ i ] . dump ( ' %s %s : { ' % ( ind , i ) , indent = indent + 4 )
2019-04-04 19:32:39 -04:00
print ( " %s } " % ind )
2017-06-30 08:53:19 -04:00
else :
2019-04-04 19:32:39 -04:00
print ( " %s %s : { %r } " % ( ind , i , self [ i ] ) )
2017-06-30 08:53:19 -04:00
# Do we have remaining fields not defined in the structures? let's
# print them
remainingFields = list ( set ( self . fields ) - set ( fixedFields ) )
for i in remainingFields :
if isinstance ( self [ i ] , Structure ) :
self [ i ] . dump ( ' %s %s : { ' % ( ind , i ) , indent = indent + 4 )
2019-04-04 19:32:39 -04:00
print ( " %s } " % ind )
2017-06-30 08:53:19 -04:00
else :
2019-04-04 19:32:39 -04:00
print ( " %s %s : { %r } " % ( ind , i , self [ i ] ) )
2017-06-30 08:53:19 -04:00
class _StructureTest :
alignment = 0
def create ( self , data = None ) :
if data is not None :
return self . theClass ( data , alignment = self . alignment )
else :
return self . theClass ( alignment = self . alignment )
def run ( self ) :
2019-04-04 19:32:39 -04:00
print ( )
print ( " - " * 70 )
2017-06-30 08:53:19 -04:00
testName = self . __class__ . __name__
2019-04-04 19:32:39 -04:00
print ( " starting test: %s ..... " % testName )
2017-06-30 08:53:19 -04:00
a = self . create ( )
self . populate ( a )
a . dump ( " packing..... " )
a_str = str ( a )
2019-04-04 19:32:39 -04:00
print ( " packed: %r " % a_str )
print ( " unpacking..... " )
2017-06-30 08:53:19 -04:00
b = self . create ( a_str )
b . dump ( " unpacked..... " )
2019-04-04 19:32:39 -04:00
print ( " repacking..... " )
2017-06-30 08:53:19 -04:00
b_str = str ( b )
if b_str != a_str :
2019-04-04 19:32:39 -04:00
print ( " ERROR: original packed and repacked don ' t match " )
print ( " packed: %r " % b_str )
2017-06-30 08:53:19 -04:00
class _Test_simple ( _StructureTest ) :
class theClass ( Structure ) :
commonHdr = ( )
structure = (
( ' int1 ' , ' !L ' ) ,
( ' len1 ' , ' !L-z1 ' ) ,
( ' arr1 ' , ' B*<L ' ) ,
( ' z1 ' , ' z ' ) ,
( ' u1 ' , ' u ' ) ,
( ' ' , ' " COCA ' ) ,
( ' len2 ' , ' !H-:1 ' ) ,
( ' ' , ' " COCA ' ) ,
( ' :1 ' , ' : ' ) ,
( ' int3 ' , ' >L ' ) ,
( ' code1 ' , ' >L=len(arr1)*2+0x1000 ' ) ,
)
def populate ( self , a ) :
a [ ' default ' ] = ' hola '
a [ ' int1 ' ] = 0x3131
a [ ' int3 ' ] = 0x45444342
a [ ' z1 ' ] = ' hola '
a [ ' u1 ' ] = ' hola ' . encode ( ' utf_16_le ' )
a [ ' :1 ' ] = ' :1234: '
a [ ' arr1 ' ] = ( 0x12341234 , 0x88990077 , 0x41414141 )
# a['len1'] = 0x42424242
class _Test_fixedLength ( _Test_simple ) :
def populate ( self , a ) :
_Test_simple . populate ( self , a )
a [ ' len1 ' ] = 0x42424242
class _Test_simple_aligned4 ( _Test_simple ) :
alignment = 4
class _Test_nested ( _StructureTest ) :
class theClass ( Structure ) :
class _Inner ( Structure ) :
structure = ( ( ' data ' , ' z ' ) , )
structure = (
( ' nest1 ' , ' : ' , _Inner ) ,
( ' nest2 ' , ' : ' , _Inner ) ,
( ' int ' , ' <L ' ) ,
)
def populate ( self , a ) :
a [ ' nest1 ' ] = _Test_nested . theClass . _Inner ( )
a [ ' nest2 ' ] = _Test_nested . theClass . _Inner ( )
a [ ' nest1 ' ] [ ' data ' ] = ' hola manola '
a [ ' nest2 ' ] [ ' data ' ] = ' chau loco '
a [ ' int ' ] = 0x12345678
class _Test_Optional ( _StructureTest ) :
class theClass ( Structure ) :
structure = (
( ' pName ' , ' <L&Name ' ) ,
( ' pList ' , ' <L&List ' ) ,
( ' Name ' , ' w ' ) ,
( ' List ' , ' <H*<L ' ) ,
)
def populate ( self , a ) :
a [ ' Name ' ] = ' Optional test '
a [ ' List ' ] = ( 1 , 2 , 3 , 4 )
class _Test_Optional_sparse ( _Test_Optional ) :
def populate ( self , a ) :
_Test_Optional . populate ( self , a )
del a [ ' Name ' ]
class _Test_AsciiZArray ( _StructureTest ) :
class theClass ( Structure ) :
structure = (
( ' head ' , ' <L ' ) ,
( ' array ' , ' B*z ' ) ,
( ' tail ' , ' <L ' ) ,
)
def populate ( self , a ) :
a [ ' head ' ] = 0x1234
a [ ' tail ' ] = 0xabcd
a [ ' array ' ] = ( ' hola ' , ' manola ' , ' te traje ' )
class _Test_UnpackCode ( _StructureTest ) :
class theClass ( Structure ) :
structure = (
( ' leni ' , ' <L=len(uno)*2 ' ) ,
( ' cuchi ' , ' _-uno ' , ' leni/2 ' ) ,
( ' uno ' , ' : ' ) ,
( ' dos ' , ' : ' ) ,
)
def populate ( self , a ) :
a [ ' uno ' ] = ' soy un loco! '
a [ ' dos ' ] = ' que haces fiera '
class _Test_AAA ( _StructureTest ) :
class theClass ( Structure ) :
commonHdr = ( )
structure = (
( ' iv ' , ' !L=((init_vector & 0xFFFFFF) << 8) | ((pad & 0x3f) << 2) | (keyid & 3) ' ) ,
( ' init_vector ' , ' _ ' , ' (iv >> 8) ' ) ,
( ' pad ' , ' _ ' , ' ((iv >>2) & 0x3F) ' ) ,
( ' keyid ' , ' _ ' , ' ( iv & 0x03 ) ' ) ,
( ' dataLen ' , ' _-data ' , ' len(inputDataLeft)-4 ' ) ,
( ' data ' , ' : ' ) ,
( ' icv ' , ' >L ' ) ,
)
def populate ( self , a ) :
a [ ' init_vector ' ] = 0x01020304
#a['pad']=int('01010101',2)
a [ ' pad ' ] = int ( ' 010101 ' , 2 )
a [ ' keyid ' ] = 0x07
a [ ' data ' ] = " \xA0 \xA1 \xA2 \xA3 \xA4 \xA5 \xA6 \xA7 \xA8 \xA9 "
a [ ' icv ' ] = 0x05060708
#a['iv'] = 0x01020304
if __name__ == ' __main__ ' :
_Test_simple ( ) . run ( )
try :
_Test_fixedLength ( ) . run ( )
except :
2019-04-04 19:32:39 -04:00
print ( " cannot repack because length is bogus " )
2017-06-30 08:53:19 -04:00
_Test_simple_aligned4 ( ) . run ( )
_Test_nested ( ) . run ( )
_Test_Optional ( ) . run ( )
_Test_Optional_sparse ( ) . run ( )
_Test_AsciiZArray ( ) . run ( )
_Test_UnpackCode ( ) . run ( )
_Test_AAA ( ) . run ( )