Skip to content

Commit

Permalink
Merge pull request #6 from bdr00/dev
Browse files Browse the repository at this point in the history
version 0.9.0.6
  • Loading branch information
bnbdr authored Sep 10, 2017
2 parents fbdc3b7 + 7e21662 commit 4685d62
Show file tree
Hide file tree
Showing 22 changed files with 363 additions and 119 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ celerybeat-schedule

# dotenv
.env
.idea/

# virtualenv
venv/
Expand All @@ -87,3 +88,4 @@ ENV/

# Rope project settings
.ropeproject
MANIFEST
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ none
- Python 3.5.2

## License
This project is licensed under the MIT License - see the [LICENSE.md](LICENSE.md) file for details
This project is licensed under the MIT License - see the [LICENSE](LICENSE.txt) file for details

## Remarks
[]()|[]()
Expand Down
10 changes: 8 additions & 2 deletions examples/dump_json.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
from __future__ import print_function
import json
from typedef import *
from typedef.tools import TypeEncoder


S = struct([
(DWORD, 'd'),
Expand All @@ -9,11 +11,15 @@
(DWORD, 'build'),
struct([
(WORD, 'mj'),
(WORD, 'mn')
(WORD, 'mn'),
struct([
(BYTE, 'b1'),
(BYTE, 'b2')
], 'even_inner')
], 'inn')
])
])

s = S(b'\xff\xff\xff\xffaaaa\x01\x00\x02\x00')
s = S(b'\xff\xff\xff\xffaaaa\x01\x00\x02\x00' + '\x00' + '\x02'+'!'*2) # two '!' for padding, main struct must be aligned to 4
print('dumping json for: {}'.format(repr(s)))
print(json.dumps(s, cls=TypeEncoder, indent=2))
2 changes: 2 additions & 0 deletions examples/parse_pe_header.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
from __future__ import print_function
import json
from typedef import *
from typedef.tools import TypeEncoder


# used definition from 010editor template: https://www.sweetscape.com/010editor/repository/files/EXE.bt
with pragma.pack(1):
Expand Down
2 changes: 1 addition & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
[metadata]
description-file = README.md
description-file = README.md
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
author='bdr00',
author_email='[email protected]',
url='https://github.com/bdr00/typedef',
download_url='https://github.com/bdr00/typedef/archive/v0.9.0.5.tar.gz',
download_url='https://github.com/bdr00/typedef/archive/v{}.tar.gz'.format(typedef.__version__),
keywords=['typedef', 'struct', 'union', ' pack', 'unpack', 'binary'],
classifiers=[
'Programming Language :: Python :: 2',
Expand Down
1 change: 1 addition & 0 deletions tests/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from sys import version_info
from os import path, remove
import gc
import struct as pystruct
from typedef import *
from typedef.errors import * # for when tests import this module

Expand Down
11 changes: 11 additions & 0 deletions tests/test_array.py
Original file line number Diff line number Diff line change
Expand Up @@ -179,3 +179,14 @@ def test_array_basic_infer(self):

# gc.collect()
# print gc.get_referrers(b)

def test_sizeof(self):
S = struct([
(DWORD, 'd'),
(WORD, 'w')
])
A = S[2]
self.assertEqual(sizeof(A), 16)
a = S[2](b'\x00\x00\x00\x00\xBB\xBB!!aaaabb!!')
self.assertEqual(sizeof(a), sizeof(S) * 2)
self.assertEqual(sizeof(a[0]), sizeof(S))
14 changes: 14 additions & 0 deletions tests/test_init.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,3 +56,17 @@ def test_init_passthrough_sync(self):
data = open(self.test_file_path, 'rb').read()
self.assertEqual(data, bytes(s))
# s.__buffer__.close()


class InitSimpleType(TypedefTestCase):
def test_init_simple_from_file(self):
with warnings.catch_warnings(record=True): # to ignore warning on unclosed file
open(self.test_file_path, 'wb').write(b'\x00\x00\x00\x00\xAA\xBB\xCC\xDD')
f = open(self.test_file_path, 'rb')

self.assertEqual(DWORD(f), 0)
self.assertEqual(WORD(f), WORD(b'\xAA\xBB'))
self.assertEqual(WORD(f), WORD(b'\xCC\xDD'))

with self.assertRaises(pystruct.error) as cm:
BYTE(f)
11 changes: 11 additions & 0 deletions tests/test_primitives.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,3 +66,14 @@ def test_signed_unsigned_big_little_accessors(self):
self.assertEqual(u.signedLittle, pystruct.unpack('<i', b)[0])
self.assertEqual(u.unsignedBig, pystruct.unpack('>I', b)[0])
self.assertEqual(u.signedBig, pystruct.unpack('>i', b)[0])


class Size(TypedefTestCase):
def test_sizeof(self):
self.assertEqual(sizeof(BYTE), 1)
self.assertEqual(sizeof(WORD), 2)
self.assertEqual(sizeof(DWORD), 4)
self.assertEqual(sizeof(QWORD), 8)

self.assertEqual(sizeof(PVOID, Arch.x86), 4)
self.assertEqual(sizeof(PVOID, Arch.x64), 8)
70 changes: 70 additions & 0 deletions tests/test_struct.py
Original file line number Diff line number Diff line change
Expand Up @@ -632,3 +632,73 @@ def test_struct_basic_update(self):
self.assertEqual(s64.p, 0xffffffffffffffff)
self.assertEqual(s64.c, ord('c'))
self.assertEqual(bytes(s64), b'\x33\x33!!!!!!\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFFc!!!!!!!')

def test_struct_type_sizeof(self):
S = struct([
(WORD, 's'),
(PVOID, 'p'),
(BYTE, 'c')
])
s32 = S(b'\x12\x12!!\x00\x00\x00\x00c!!!', target=Arch.x86)
s64 = S(b'\x12\x12!!!!!!\x00\x00\x00\x00\x00\x00\x00\x00c!!!!!!!', target=Arch.x64)
self.assertEqual(sizeof(S, Arch.x86), sizeof(s32))
self.assertEqual(sizeof(S, Arch.x64), sizeof(s64))

def test_struct_type_sizeof_error(self):
S = struct([
(WORD, 's'),
(PVOID, 'p'),
(BYTE, 'c')
])

with self.assertRaises(ArchDependentType) as cm:
bad = sizeof(S)

def test_struct_offsetof(self):
S = struct([
(WORD, 's'),
(PVOID, 'p'),
(BYTE, 'c')
])

s32 = S(b'\x12\x12!!\x00\x00\x00\x00c!!!', target=Arch.x86)
s64 = S(b'\x12\x12!!!!!!\x00\x00\x00\x00\x00\x00\x00\x00c!!!!!!!', target=Arch.x64)

self.assertEqual(offsetof('p', s32), 4)
self.assertEqual(offsetof('p', s64), 8)

def test_struct_type_offsetof(self):
S = struct([
(WORD, 's'),
(PVOID, 'p'),
(BYTE, 'c')
])

s32 = S(b'\x12\x12!!\x00\x00\x00\x00c!!!', target=Arch.x86)
s64 = S(b'\x12\x12!!!!!!\x00\x00\x00\x00\x00\x00\x00\x00c!!!!!!!', target=Arch.x64)

self.assertEqual(offsetof('p', S, target_arch=Arch.x86), 4)
self.assertEqual(offsetof('p', S, target_arch=Arch.x64), 8)

def test_struct_type_offsetof_error(self):
S = struct([
(WORD, 's'),
(PVOID, 'p'),
(BYTE, 'c')
])

with self.assertRaises(ArchDependentType) as cm:
bad = offsetof('p', S)

def test_struct_bad_init_def(self):
with self.assertRaises(UnsupportedInitializationMethod) as cm:
S = struct([])
self.assertEqual(cm.exception.args[0], 'requires field definitions')

with self.assertRaises(UnsupportedInitializationMethod) as cm:
S = struct([list])
self.assertEqual(cm.exception.args[0], 'input must be simple or complex type-definition')

with self.assertRaises(UnsupportedInitializationMethod) as cm:
S = struct([1])
self.assertEqual(cm.exception.args[0], 'unsupported input for type-member tuple')
66 changes: 66 additions & 0 deletions tests/test_union.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,27 @@ def test_union_cannot_be_init_dict(self):
u = U({})
self.assertEqual(cm.exception.args[0], 'union cannot be initialized using a dict/list/tuple; only buffer')

def test_union_with_nameless_struct_reverse_order(self):
pragma.pack.push(1)
clr = union([
(DWORD, 'hex'),
struct([
(BYTE, 'r'),
(BYTE, 'g'),
(BYTE, 'b'),
(BYTE, 'a')
])
])

self.assertEqual(clr.__size__, DWORD.__size__)
self.assertEqual(clr.__offsets__, [(0, 0), (0, 0), (1, 1), (2, 2), (3, 3)])
u = clr(DWORD(0x00AABBCC))
self.assertEqual(u.hex, 0x00AABBCC)
self.assertEqual(u.r, 0xCC)
self.assertEqual(u.g, 0xBB)
self.assertEqual(u.b, 0xAA)
self.assertEqual(u.a, 0)

def test_union_with_nameless_struct(self):
U = union([
struct([
Expand Down Expand Up @@ -116,3 +137,48 @@ def test_union_basic(self):
self.assertEqual(u32.s, 0x2211)
self.assertEqual(u32.i, 0x44332211)
self.assertEqual(u32.p, 0x44332211)

def test_union_sizeof(self):
U = union([
(WORD, 's'),
(PVOID, 'p'),
(BYTE, 'c')
])

u32 = U(target=Arch.x86)
u64 = U(target=Arch.x64)

self.assertEqual(sizeof(u32), sizeof(PVOID, Arch.x86))
self.assertEqual(sizeof(u64), sizeof(PVOID, Arch.x64))

def test_union_type_sizeof(self):
U = union([
(WORD, 's'),
(PVOID, 'p'),
(BYTE, 'c')
])
u32 = U(target=Arch.x86)
u64 = U(target=Arch.x64)
self.assertEqual(sizeof(U, Arch.x86), sizeof(u32))
self.assertEqual(sizeof(U, Arch.x64), sizeof(u64))

def test_union_type_sizeof_error(self):
U = union([
(WORD, 's'),
(PVOID, 'p'),
(BYTE, 'c')
])

with self.assertRaises(ArchDependentType) as cm:
bad = sizeof(U)

def test_union_type_offsetof(self):
U = union([
(WORD, 's'),
(PVOID, 'p'),
(BYTE, 'c')
])

self.assertEqual(offsetof('s', U), 0)
self.assertEqual(offsetof('p', U), 0)
self.assertEqual(offsetof('c', U), 0)
68 changes: 8 additions & 60 deletions typedef/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,66 +3,14 @@
"""
import typedef.api
import typedef.errors
from .primitives import *
from .constants import Endian, Arch, F_SYNC, F_COPY
from .json_encoder import TypeEncoder
from .pragma import pack
import typedef.pragma
from typedef.api import *
from typedef.constants import Endian, Arch, F_SYNC, F_COPY
from typedef.primitives import *

version = (0, 9, 0, 5)
version = (0, 9, 0, 6)
__version__ = '.'.join(map(str, version))
__description__ = 'A somewhat convenient package for packing and unpacking structs, unions, and arrays using C-like syntax'


def sizeof(container):
"""
return the number of bytes the complex-type instance represents
:param container: instance of struct/union/array
:return: number of bytes the container has
"""
return api.sizeof(container)


def struct(members, name=''):
"""
define a struct
:param members: list of type-name tuples, or copmlex types (for anonymous/rval structs/unions)
:param name: name of the struct.
if the struct is a nested definition, this will be the accessor(attribute name) for the struct.
:return: a new struct
definition
"""
return api.struct(members, name)


def union(members, name=''):
"""
define a union
:param members: list of type-name tuples, or copmlex types (for anonymous/rval structs/unions)
:param name: name of the union
if the union is a nested definition, this will be the accessor(attribute name) for the union.
:return: a new union definition
"""
return api.union(members, name)


def array(t, count):
"""
define an array of a specific type
:param t: type for the array
:param count: size of the array
:return: a new array type
"""
return api.array(t, count)


def define(name, sizes, signed=False, end=Endian.Little):
"""
define a new simple-type
:param name: name of the type, will be shown when printing the type ow when used in arrays
:param sizes: an integer specifying the size of the type.
if its size vary between the two architectures, a tuple of sizes should be supplied
:param signed: signed / unsigned
:param end: little / big endianess
:return: a new simple type
"""
return api.define(name, sizes, signed, end)
__all__ = ['pragma', 'Endian', 'Arch', 'F_SYNC', 'F_COPY', 'errors', 'sizeof', 'offsetof', 'struct',
'union',
'array', 'define', 'BYTE', 'WORD', 'DWORD', 'QWORD', 'HALF_PTR', 'PVOID', 'SIZE_T', 'SSIZE_T']
Loading

0 comments on commit 4685d62

Please sign in to comment.