#!/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 = [ "", "", "", "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", "", # 40 "", "", "RA80", "RA81", "RA82", "RA83", "RA74", "", "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)