Prepare parsing RGN files.
This commit is contained in:
parent
f4d367e572
commit
d33ed7ef55
@ -1,4 +1,5 @@
|
|||||||
"""Library for firmware reading/writing."""
|
"""Library for firmware reading/writing."""
|
||||||
|
|
||||||
from .gcd import *
|
from .gcd import *
|
||||||
|
from .rgn import *
|
||||||
from .chksum import *
|
from .chksum import *
|
||||||
|
138
grmn/rgn.py
Normal file
138
grmn/rgn.py
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Thanks to Herbert Oppmann (herby) for all your work!
|
||||||
|
|
||||||
|
from .chksum import ChkSum
|
||||||
|
from .rgnbin import RgnBin
|
||||||
|
from struct import unpack
|
||||||
|
import configparser
|
||||||
|
|
||||||
|
RGN_SIG = b"KpGr"
|
||||||
|
|
||||||
|
# RGN structure might be: RGN > BIN or RGN > RGN > BIN
|
||||||
|
# RGN = outside hull
|
||||||
|
# BIN = firmware + hwid + checksum
|
||||||
|
|
||||||
|
class ParseException(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class Rgn:
|
||||||
|
def __init__(self, filename: str=None):
|
||||||
|
self.filename = filename
|
||||||
|
self.struct = []
|
||||||
|
if filename is not None:
|
||||||
|
self.load()
|
||||||
|
|
||||||
|
def load(self):
|
||||||
|
if self.filename is None:
|
||||||
|
return False
|
||||||
|
last_tlv6 = None
|
||||||
|
last_tlv7 = None
|
||||||
|
with open(self.filename, "rb") as f:
|
||||||
|
sig = f.read(4)
|
||||||
|
if sig != RGN_SIG:
|
||||||
|
raise ParseException("Signature mismatch ({}, should be {})!".format(repr(sig), repr(RGN_SIG)))
|
||||||
|
self.version = unpack("<H", f.read(2))[0]
|
||||||
|
print("Version: {}".format(self.version))
|
||||||
|
while True:
|
||||||
|
cur_offset = f.tell()
|
||||||
|
header = f.read(5)
|
||||||
|
if len(header) == 0:
|
||||||
|
print("End of file reached.")
|
||||||
|
break
|
||||||
|
(length, type_id) = unpack("<Lc", header)
|
||||||
|
print("Found record type: {} with {} Bytes length.".format(type_id, length))
|
||||||
|
rec = RgnRecord.factory(type_id, length, offset=cur_offset)
|
||||||
|
payload = f.read(length)
|
||||||
|
rec.set_payload(payload)
|
||||||
|
self.add_rec(rec)
|
||||||
|
f.close()
|
||||||
|
|
||||||
|
def add_rec(self, new_rec):
|
||||||
|
self.struct.append(new_rec)
|
||||||
|
|
||||||
|
def print_struct(self):
|
||||||
|
"""
|
||||||
|
Prints the structure of the parsed GCD file
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
def print_struct_full(self):
|
||||||
|
"""
|
||||||
|
Prints the structure of the parsed GCD file
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
def validate(self, print_stats: bool=False):
|
||||||
|
"""
|
||||||
|
Checks and verifies all checksums in the GCD.
|
||||||
|
"""
|
||||||
|
# RGN has no checksum, but embedded BIN has
|
||||||
|
|
||||||
|
def dump_to_files(self, output_basename: str):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def from_recipe(recipe_file: str):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def save(self, filename):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class RgnRecord():
|
||||||
|
def __init__(self, type_id, expected_length, payload=None, offset=None):
|
||||||
|
self.type_id = type_id
|
||||||
|
self.length = expected_length
|
||||||
|
self.is_binary = False
|
||||||
|
self.payload = payload
|
||||||
|
self.offset = offset
|
||||||
|
self.is_parsed = False
|
||||||
|
|
||||||
|
def set_payload(self, new_payload):
|
||||||
|
self.payload = new_payload
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def factory(type_id, length: int = None, offset: int = None):
|
||||||
|
if type_id == b"D":
|
||||||
|
new_rec = RgnRecordD(type_id, length)
|
||||||
|
elif type_id == b"A":
|
||||||
|
new_rec = RgnRecordA(type_id, length)
|
||||||
|
elif type_id == b"R":
|
||||||
|
new_rec = RgnRecordR(type_id, length)
|
||||||
|
new_rec.is_binary = True
|
||||||
|
else:
|
||||||
|
raise ParseException("Unknown record type: {} at offset 0x{:0x}".format(type_id, offset))
|
||||||
|
new_rec.offset = offset
|
||||||
|
return new_rec
|
||||||
|
|
||||||
|
class RgnRecordD(RgnRecord):
|
||||||
|
"""
|
||||||
|
Data record (2 Bytes)
|
||||||
|
- ushort - Version
|
||||||
|
"""
|
||||||
|
|
||||||
|
def parse(self):
|
||||||
|
self.is_parsed = True
|
||||||
|
|
||||||
|
class RgnRecordA(RgnRecord):
|
||||||
|
"""
|
||||||
|
Application record
|
||||||
|
- ushort - Application version
|
||||||
|
- string - Builder
|
||||||
|
- string - BuildDate
|
||||||
|
- string - BuildTime
|
||||||
|
"""
|
||||||
|
|
||||||
|
def parse(self):
|
||||||
|
self.is_parsed = True
|
||||||
|
|
||||||
|
class RgnRecordR(RgnRecord):
|
||||||
|
"""
|
||||||
|
Region record
|
||||||
|
- ushort - Region ID
|
||||||
|
- uint - Delay in ms
|
||||||
|
- uint - Region size (is record length - 10)
|
||||||
|
- byte[Region size] - Contents
|
||||||
|
"""
|
||||||
|
|
||||||
|
def parse(self):
|
||||||
|
self.is_parsed = True
|
26
grmn/rgnbin.py
Normal file
26
grmn/rgnbin.py
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Thanks to Herbert Oppmann (herby) for all your work!
|
||||||
|
|
||||||
|
from . import devices
|
||||||
|
from .chksum import ChkSum
|
||||||
|
from struct import unpack
|
||||||
|
|
||||||
|
# RGN structure might be: RGN > BIN or RGN > RGN > BIN
|
||||||
|
# RGN = outside hull
|
||||||
|
# BIN = firmware + hwid + checksum
|
||||||
|
|
||||||
|
class ParseException(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class RgnBin:
|
||||||
|
def __init__(self, filename: str=None):
|
||||||
|
self.filename = filename
|
||||||
|
self.struct = []
|
||||||
|
if filename is not None:
|
||||||
|
self.load()
|
||||||
|
|
||||||
|
def load(self):
|
||||||
|
if self.filename is None:
|
||||||
|
return False
|
||||||
|
with open(self.filename, "rb") as f:
|
||||||
|
f.close()
|
18
rgnstruct.py
Normal file
18
rgnstruct.py
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
"""
|
||||||
|
Prints out the structure of the given RGN file.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from grmn import Rgn
|
||||||
|
import sys
|
||||||
|
|
||||||
|
FILE = sys.argv[1]
|
||||||
|
|
||||||
|
print("Opening {}".format(FILE))
|
||||||
|
|
||||||
|
rgn = Rgn(FILE)
|
||||||
|
|
||||||
|
#rgn.print_struct()
|
||||||
|
#rgn.validate(True)
|
Loading…
x
Reference in New Issue
Block a user