Skip to content

Commit

Permalink
Add meta length mismatch correction and warnings
Browse files Browse the repository at this point in the history
  • Loading branch information
kg583 committed Jun 4, 2024
1 parent 2ea3794 commit 436988a
Showing 1 changed file with 55 additions and 23 deletions.
78 changes: 55 additions & 23 deletions tivars/var.py
Original file line number Diff line number Diff line change
Expand Up @@ -460,13 +460,24 @@ def __str__(self) -> str:
return self.string()

@Section(2, Integer)
def meta_length(self) -> int:
def meta_length(self, value) -> int:
"""
The length of the meta section of the entry
The possible meta lengths are 11 (without flash) or 13 (with flash).
"""

if value == TIEntry.base_meta_length:
if self.raw.meta_length == b'\x0D\x00':
warn(f"Meta data (0x{self.flash_bytes.hex()}) will be lost.",
UserWarning)

if self.flash_only:
warn(f"{type(self)} vars are not compatible with flashless chips.",
UserWarning)

return value

@property
def calc_data_length(self) -> int:
"""
Expand All @@ -492,22 +503,34 @@ def name(self) -> str:
"""

@Section(1, Bits[:])
def version(self) -> int:
def version(self, value) -> int:
"""
The version number of the entry
The version is used to determine model compatibility where necessary.
Only flash files support this entry, and it thus not present if `meta_length` <= 11.
"""

if self.meta_length == TIEntry.base_meta_length:
warn(f"Flashless vars do not maintain version information.",
UserWarning)

return value

@Section(1, Boolean)
def archived(self) -> bool:
def archived(self, value) -> bool:
"""
Whether the entry is archived
Only flash files support this entry, and it thus not present if `meta_length` <= 11.
"""

if self.meta_length == TIEntry.base_meta_length:
warn(f"Flashless vars cannot be archived or unarchived.",
UserWarning)

return value

@Section()
def calc_data(self) -> bytes:
"""
Expand Down Expand Up @@ -706,37 +729,40 @@ def load_bytes(self, data: bytes | BytesIO):
self.raw.version = data.read(1)
self.raw.archived = data.read(1)

if self.raw.archived not in b'\x00\x80':
warn(f"The archive flag ({self.raw.archived.hex()}) is set to an unexpected value.",
BytesWarning)

case TIEntry.base_meta_length:
self.raw.version = b'\x00'
self.raw.archived = b'\x00'

if self.flash_only:
warn(f"{type(self)} vars are not compatible with flashless chips.",
BytesWarning)

case _:
warn(f"The entry meta length has an unexpected value ({self.meta_length}); "
f"attempting to read flash bytes anyway.",
BytesWarning)

self.raw.version = data.read(1)
self.raw.archived = data.read(1)

if self.raw.archived not in b'\x00\x80':
warn(f"The archive flag is set to an unexpected value.",
BytesWarning)
if self.meta_length == TIEntry.flash_meta_length and self.raw.version + self.raw.archived == data_length:
warn(f"The entry meta length is {self.meta_length}, but the flash data is likely missing; "
f"the meta section will be corrected to be flashless.")

# Read data and check length
data_length2 = data.read(2)
if data_length != data_length2:
warn(f"The var entry data lengths are mismatched ({data_length} vs. {data_length2}); "
f"using {data_length2} to read the data section.",
BytesWarning)
self.meta_length = TIEntry.base_meta_length
self.raw.version = b'\x00'
self.raw.archived = b'\x00'

self.raw.calc_data = bytearray(data.read(length := int.from_bytes(data_length2, 'little')))
else:
if self.raw.archived not in b'\x00\x80':
warn(f"The archive flag (0x{self.raw.archived.hex()}) is set to an unexpected value.",
BytesWarning)

# Check length
data_length2 = data.read(2)
if data_length != data_length2:
warn(f"The var entry data lengths are mismatched ({data_length} vs. {data_length2}); "
f"using {data_length} to read the data section.",
BytesWarning)

# Read data
self.raw.calc_data = bytearray(data.read(length := int.from_bytes(data_length, 'little')))

if len(self.calc_data) != length:
warn(f"The data section length is incorrect (expected {length}, got {len(self.calc_data)}).",
Expand All @@ -748,6 +774,10 @@ def load_bytes(self, data: bytes | BytesIO):
warn(f"The version (0x{self.version:02x}) is not recognized.",
BytesWarning)

if self.meta_length == TIEntry.base_meta_length and self.flash_only:
warn(f"{type(self)} vars are not compatible with flashless chips.",
BytesWarning)

def bytes(self) -> bytes:
"""
The bytes contained in this entry, without any var file header or metadata.
Expand Down Expand Up @@ -795,7 +825,9 @@ def load_from_file(self, file: BinaryIO, *, offset: int = 0):
"""

# Skip header
file.seek(55)
header = TIHeader()
header.load_from_file(file)
file.seek(2, 1)

# Seek to offset
while offset:
Expand Down Expand Up @@ -849,7 +881,7 @@ def open(cls, filename: str) -> Self:
file.seek(2, 1)

if remaining := file.read():
if remaining.startswith(b"\x0B\x00") or remaining.startswith(b"\x0D\x00"):
if remaining.startswith(b'\x0B\x00') or remaining.startswith(b'\x0D\x00'):
warn("The selected var file contains multiple entries; only the first will be loaded. "
"Use load_from_file to select a particular entry, or load the entire file into a TIVar object.",
UserWarning)
Expand Down

0 comments on commit 436988a

Please sign in to comment.