just so everone knows the project isn't dead
I've recently been urged to improve the DATA backend
or rather how it works in the frontend...
granularity between endian selection has been a hassle, actually more than that really...
so I've worked on an idea that would improve that through automation.
note that the old system is still provided as a final override,
rather than backwards compatibility, since that's been out the window since the death of UMC 3.0a
(at least I tried guys, but for those who don't know, that blew up in my face)
anyways, here's how it works...
you define a base struct type with a `big` member/attribute:
Code:
big = '\xfe\xff'
little = '\xff\xfe'
big_string = string(2)
HEADER = struct(
magic = string(4),
big = lambda value=None, **kw: big_string( None if value is None else ( big if value else little ) ) == big, # value should be either None, True, or False
)
I know this example is a bit unintuitive, but I'm using a practical use case with a Byte Order Mark (0xFEFF for big and 0xFFFE for little)
the `big` attribute uses an augment that returns True or False if the BOM is big,
with included logic for write operations where `value` will be None, True, or False.
after that, you define your base data type which dereferences the struct (yes I'm actually using my pointer system,
and defining this stuff outside of the R/W operation functions):
Code:
# note that deref() will return a deref object if an R/W operation is not being performed when called
u32 = U( 4, big = deref( 0, HEADER ) )
basically
when you call the u32() definition
it will see that it's `big` argument holds a callable object/augment
when reading, that augment will return the HEADER struct instance at addr 0
and since it's a struct on the `big` argument, the u32 definition's read function will retrueve the struct's ['big'] member, which will be either True or False
note that if there is no HEADER instance at addr 0, the deref object will create it when called
but you should almost always call a header-struct first, as shown here:
Code:
def ugeImportModel(*args,**kw):
header = HEADER()
value = u32() # endian determined by header.big
something else I've been reworking is field() which has been turned into a struct-type:
Code:
myField = field(
__size__: [int, struct, augment] = 1, # (in bytes) determined by ceil( member sum / 8 ) if unspecified
__addr__: [int, struct, augment],
member1 = 3, # 00000111
member2 = 1, # 00001000
member3 = 1, # 00010000
member4 = 1, # 00100000
member5 = 2 # 11000000
)
here's an example reworked from my BRMDL script:
Code:
Influence = field( # Tcll: thanks BJ :)
Len = 4, # 0x0000000F
Adr = 12, # 0x0000FFF0
link_index = 16 ) # 0xFFFF0000
)
as you can probably tell, the byte-size of the field will be auto-determined but you can specify if you need to oversize it
(I'm also working on __align__ for struct/array types which should align the value within an allocated space)
also, use if the Influence field can be any of:
inf = Len,Adr,link_index = Influence()
inf.Adr
inf['Len']
and you may have also noticed above that the definition of u32 uses a new data type call
while data types like bu16 and bf32 are still provided for ease of use, you may override these with your own definitions that are more flexible with retrieving needed information from data structs.
the base types look like this:
Code:
u8 = u( size: [int, struct, augment] = 1, offset: [int, struct, augment], big: [bool, struct, augment] )
s8 = s( size: [int, struct, augment] = 1, offset: [int, struct, augment], big: [bool, struct, augment] )
f8 = f( format: UGE_FLOAT_FORMAT = UGE_IEEE754, size: [int, struct, augment] = 1, offset: [int, struct, augment], big: [bool, struct, augment] ) # no longer compatible with any byte size under IEEE754
h8 = h( size: [int, struct, augment] = 1, offset: [int, struct, augment], big: [bool, struct, augment] )
yes you're reading correctly, I'm restricting IEEE754 to the existing size specs.
bf(5) was cool, but it wasn't standard, and as such, anything written with it would likely be incompatible when an official standard is actually released.
funny enough though, I actually plan on releasing custom standards for float definitions (not by this release though)
and finally, union() is being added as another struct-type object
basically, it works almost exactly like a struct(), but all members occupy the same address space
also, changes are being made to how virtual files are managed
rather than JUST holding the data as an array('B'), the UGEFile class will actually emulate a file stream, where 3rd-party modules like pillow can manage them appropriately without needing stream wrappers like StringIO()
the UGEFile object will also have it's own global `big` attribute, which will be the final fallback for all data objects relying on endian.
so yeah, quite a bit of change going on for UGE