You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
176 lines
4.5 KiB
Python
176 lines
4.5 KiB
Python
3 years ago
|
#!/usr/bin/env python3
|
||
|
# -*- coding: utf-8 -*-
|
||
|
|
||
|
import os
|
||
|
import sys
|
||
|
import types
|
||
|
import platform
|
||
|
import ctypes
|
||
|
import binascii
|
||
|
|
||
|
|
||
|
class XQImgHdr(ctypes.Structure):
|
||
|
_fields_ = [("magic", ctypes.c_uint), # HDR1
|
||
|
("sign", ctypes.c_uint), # offset of sign block
|
||
|
("crc32", ctypes.c_uint), # crc32 check sum
|
||
|
("type", ctypes.c_ushort), # ROM type (12 = miwifi_ssh.bin)
|
||
|
("model", ctypes.c_short), # device number
|
||
|
("files", ctypes.c_uint * 8)] # array of section-offset
|
||
|
|
||
|
class XQImgFile(ctypes.Structure):
|
||
|
_fields_ = [("magic", ctypes.c_ushort), # BE BA
|
||
|
("rsvd0", ctypes.c_ushort),
|
||
|
("addr", ctypes.c_uint), # Flash Address
|
||
|
("size", ctypes.c_uint), # size of file
|
||
|
("mtd", ctypes.c_short), # mtd number for flashing
|
||
|
("dummy", ctypes.c_short),
|
||
|
("name", ctypes.c_char * 32)] # Filename
|
||
|
|
||
|
xqModelList = [
|
||
|
"<unk0>",
|
||
|
"<unk1>",
|
||
|
"<unk2>",
|
||
|
"R1CM", # 3
|
||
|
"R2D", # 4
|
||
|
"R1CL",
|
||
|
"R2CM",
|
||
|
"R3",
|
||
|
"R3D", # 8
|
||
|
"R3L",
|
||
|
"R3P", # 10
|
||
|
"P01",
|
||
|
"R3A",
|
||
|
"R3G", # 13
|
||
|
"R4",
|
||
|
"R4C",
|
||
|
"D01",
|
||
|
"R4A",
|
||
|
"R4CM",
|
||
|
"R4AC",
|
||
|
"R3GV2", # 20
|
||
|
"R2600",
|
||
|
"R2100", # 22
|
||
|
"RM2100", # 23
|
||
|
"R3600", # 24
|
||
|
"R1350",
|
||
|
"R2200",
|
||
|
"R2350", # 27
|
||
|
"IR1200G",
|
||
|
"R1800",
|
||
|
"R2100D", # 30
|
||
|
"RA67",
|
||
|
"RA69",
|
||
|
"RA71",
|
||
|
"CR6006", # 34
|
||
|
"CR6008",
|
||
|
"CR6009",
|
||
|
"RA70",
|
||
|
"RA75",
|
||
|
"RA72",
|
||
|
"<unk40>", # 40
|
||
|
"<unk41>",
|
||
|
"<unk42>",
|
||
|
"RA80",
|
||
|
"RA81",
|
||
|
"RA82",
|
||
|
"RA83",
|
||
|
"RA74",
|
||
|
"<unk48>",
|
||
|
"YY01",
|
||
|
"RB01", # 50
|
||
|
"RB03" # 51
|
||
|
]
|
||
|
|
||
|
def get_modelid_by_name(name):
|
||
|
for i, m in enumerate(xqModelList):
|
||
|
if m.lower() == name.lower():
|
||
|
return i
|
||
|
return -1
|
||
|
|
||
|
|
||
|
class XQImage():
|
||
|
model = None
|
||
|
type = 0
|
||
|
header = XQImgHdr()
|
||
|
version = None
|
||
|
files = [] # list of files
|
||
|
|
||
|
def __init__(self, model = None, type = 0):
|
||
|
self.model = None
|
||
|
self.type = 0
|
||
|
self.header = XQImgHdr()
|
||
|
self.version = None
|
||
|
self.files = []
|
||
|
if model is None:
|
||
|
self.model = None
|
||
|
else:
|
||
|
if isinstance(model, int):
|
||
|
self.model = model
|
||
|
else:
|
||
|
self.model = get_modelid_by_name(model)
|
||
|
self.type = type
|
||
|
|
||
|
def add_version(self, version, hardware = 0, channel = 'release'):
|
||
|
self.version = None
|
||
|
if version is None:
|
||
|
return
|
||
|
data = "config core 'version'\n"
|
||
|
data += "\t" + "option ROM '{}'\n".format(version)
|
||
|
if channel:
|
||
|
data += "\t" + "option CHANNEL '{}'\n".format(channel.lower())
|
||
|
if hardware is not None:
|
||
|
if isinstance(hardware, int):
|
||
|
if hardware == 0 and self.model:
|
||
|
hardware = xqModelList[self.model]
|
||
|
else:
|
||
|
hardware = xqModelList[hardware]
|
||
|
data += "\t" + "option HARDWARE '{}'\n".format(hardware.upper())
|
||
|
self.version = data.encode('ascii')
|
||
|
if len(self.version) & 3 != 0:
|
||
|
self.version += b'\x00' * (4 - len(self.version) & 3)
|
||
|
self.add_file(self.version, 'xiaoqiang_version')
|
||
|
|
||
|
def add_file(self, data, name, mtd = None):
|
||
|
file = types.SimpleNamespace()
|
||
|
file.data = data
|
||
|
file.header = XQImgFile()
|
||
|
file.header.magic = int.from_bytes(b'\xBE\xBA', byteorder='little')
|
||
|
file.header.rsvd0 = 0
|
||
|
file.header.addr = 0xFFFFFFFF
|
||
|
file.header.size = len(data)
|
||
|
file.header.mtd = 0xFFFF if mtd is None else mtd
|
||
|
file.header.dummy = 0
|
||
|
file.header.name = name.encode('ascii')
|
||
|
self.files.append(file)
|
||
|
|
||
|
def get_image(self, sign):
|
||
|
buf = bytearray()
|
||
|
self.header = XQImgHdr()
|
||
|
self.header.magic = int.from_bytes(b'HDR1', byteorder='little')
|
||
|
self.header.sign = 0
|
||
|
self.header.crc32 = 0
|
||
|
self.header.type = self.type
|
||
|
self.header.model = self.model
|
||
|
buf += bytes(self.header)
|
||
|
for i, f in enumerate(self.files):
|
||
|
self.header.files[i] = len(buf)
|
||
|
buf += bytes(f.header)
|
||
|
buf += f.data
|
||
|
self.header.sign = len(buf)
|
||
|
buf += sign
|
||
|
for i in range(ctypes.sizeof(self.header)):
|
||
|
buf[i] = bytes(self.header)[i]
|
||
|
self.header.crc32 = 0xFFFFFFFF - binascii.crc32(buf[12:]) # JAMCRC
|
||
|
for i in range(12):
|
||
|
buf[i] = bytes(self.header)[i]
|
||
|
return buf
|
||
|
|
||
|
def save_image(self, sign, filename):
|
||
|
self.outfilename = filename
|
||
|
buf = self.get_image(sign)
|
||
|
with open(filename, 'wb') as file:
|
||
|
file.write(buf)
|
||
|
|
||
|
|
||
|
|