mirror of
https://github.com/Xeeynamo/sotn-decomp.git
synced 2024-10-07 02:24:01 +00:00
Extract Equipment data as JSON
This commit is contained in:
parent
63d6e3cf20
commit
ed940319d6
3
Makefile
3
Makefile
@ -325,6 +325,9 @@ $(BUILD_DIR)/$(ASSETS_DIR)/%.tiledef.json.o: $(ASSETS_DIR)/%.tiledef.json
|
||||
$(BUILD_DIR)/$(ASSETS_DIR)/%.spriteparts.json.o: $(ASSETS_DIR)/%.spriteparts.json
|
||||
./tools/splat_ext/spriteparts.py $< $(BUILD_DIR)/$(ASSETS_DIR)/$*.bin
|
||||
$(LD) -r -b binary -o $(BUILD_DIR)/$(ASSETS_DIR)/$*.o $(BUILD_DIR)/$(ASSETS_DIR)/$*.bin
|
||||
$(BUILD_DIR)/$(ASSETS_DIR)/%.equipment.json.o: $(ASSETS_DIR)/%.equipment.json
|
||||
./tools/splat_ext/equipment.py $< $(BUILD_DIR)/$(ASSETS_DIR)/$*.bin
|
||||
$(LD) -r -b binary -o $(BUILD_DIR)/$(ASSETS_DIR)/$*.o $(BUILD_DIR)/$(ASSETS_DIR)/$*.bin
|
||||
$(BUILD_DIR)/$(ASSETS_DIR)/%.spritepartslist.json.o: $(ASSETS_DIR)/%.spritepartslist.json
|
||||
./tools/splat_ext/spritepartslist.py $< $(BUILD_DIR)/$(ASSETS_DIR)/$*.s
|
||||
$(AS) $(AS_FLAGS) -o $(BUILD_DIR)/$(ASSETS_DIR)/$*.o $(BUILD_DIR)/$(ASSETS_DIR)/$*.s
|
||||
|
@ -33,7 +33,7 @@ segments:
|
||||
- [0x2BC0, data]
|
||||
- [0x3C40, data]
|
||||
- [0x4A00, data]
|
||||
- [0x4B04, raw, equipment_data]
|
||||
- [0x4B04, equipment, equipments]
|
||||
- [0x7718, raw, accessory_data]
|
||||
- [0x8000, data]
|
||||
- [0x8900, data]
|
||||
|
@ -691,33 +691,35 @@ typedef struct {
|
||||
// D_800A4B04 it is assumed the equip data starts from here
|
||||
// https://github.com/3snowp7im/SotN-Randomizer/blob/master/src/stats.js
|
||||
typedef struct {
|
||||
/* 800a4b38 */ const char* name;
|
||||
/* 800a4b3C */ const char* description;
|
||||
/* 800a4b40 */ u16 attack;
|
||||
/* 800a4b42 */ u16 defense;
|
||||
/* 800a4b44 */ u16 element;
|
||||
/* 800a4b46 */ u8 unk0E;
|
||||
/* 800a4b46 */ u8 entId;
|
||||
/* 800a4b48 */ u16 unk10;
|
||||
/* 800a4b4A */ u16 unk12;
|
||||
/* 800a4b4C */ u16 unk14;
|
||||
/* 800a4b4E */ u16 unk16;
|
||||
/* 800a4b50 */ u8 unk18;
|
||||
/* 800a4b51 */ u8 isConsumable;
|
||||
/* 800a4b52 */ u16 unk1A;
|
||||
/* 800a4b54 */ u16 unk1C;
|
||||
/* 800a4b56 */ u16 unk1E;
|
||||
/* 800a4b58 */ u16 unk20;
|
||||
/* 800a4b5A */ u16 unk22;
|
||||
/* 800a4b5C */ u16 mpUsage;
|
||||
/* 800a4b5E */ u16 unk26;
|
||||
/* 800a4b60 */ u8 unk28; // somewhat range-related
|
||||
/* 800a4b61 */ u8 unk29;
|
||||
/* 800a4b62 */ u16 unk2A;
|
||||
/* 800a4b64 */ u16 icon;
|
||||
/* 800a4b66 */ u16 palette;
|
||||
/* 800a4b68 */ u16 unk30;
|
||||
/* 800a4b6A */ u16 unk32;
|
||||
/* 0x00 */ const char* name;
|
||||
/* 0x04 */ const char* description;
|
||||
/* 0x08 */ s16 attack;
|
||||
/* 0x0A */ s16 defense;
|
||||
/* 0x0C */ u16 element;
|
||||
/* 0x0E */ u8 damageScale;
|
||||
/* 0x0F */ u8 weaponId;
|
||||
/* 0x10 */ u16 unk10;
|
||||
/* 0x12 */ u8 playerAnim;
|
||||
/* 0x13 */ u8 unk13;
|
||||
/* 0x14 */ u8 unk14;
|
||||
/* 0x15 */ u8 lockDuration;
|
||||
/* 0x16 */ u16 chainable;
|
||||
/* 0x18 */ u8 specialMove;
|
||||
/* 0x19 */ u8 isConsumable;
|
||||
/* 0x1A */ u8 enemyInvincibilityFrames;
|
||||
/* 0x1B */ u8 unk1B;
|
||||
/* 0x1C */ u16 unk1C;
|
||||
/* 0x1E */ u16 unk1E;
|
||||
/* 0x20 */ u16 unk20;
|
||||
/* 0x22 */ u16 unk22;
|
||||
/* 0x24 */ u16 mpUsage;
|
||||
/* 0x26 */ u16 stunFrames;
|
||||
/* 0x28 */ u16 hitType;
|
||||
/* 0x2A */ u16 hitEffect;
|
||||
/* 0x2C */ u16 icon;
|
||||
/* 0x2E */ u16 palette;
|
||||
/* 0x30 */ u16 criticalRate;
|
||||
/* 0x32 */ u16 unk32;
|
||||
} Equipment; /* size=0x34 */
|
||||
|
||||
// Defines armor, cloak and rings
|
||||
|
142
tools/splat_ext/equipment.py
Executable file
142
tools/splat_ext/equipment.py
Executable file
@ -0,0 +1,142 @@
|
||||
#!/usr/bin/python3
|
||||
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
from typing import Optional
|
||||
from pathlib import Path
|
||||
|
||||
sys.path.append(f"{os.getcwd()}/tools/n64splat")
|
||||
sys.path.append(f"{os.getcwd()}/tools/splat_ext")
|
||||
from util import options, log
|
||||
from segtypes.n64.segment import N64Segment
|
||||
import utils
|
||||
|
||||
item_size = 0x34 # sizeof(Equipment)
|
||||
|
||||
|
||||
def serialize_equipment(content: str) -> bytearray:
|
||||
obj = json.loads(content)
|
||||
item_count = len(obj)
|
||||
serialized_data = bytearray()
|
||||
for i in range(0, item_count):
|
||||
item = obj[i]
|
||||
serialized_data += utils.from_ptr_str(item["name_addr"])
|
||||
serialized_data += utils.from_ptr_str(item["desc_addr"])
|
||||
serialized_data += utils.from_16(item["attack"])
|
||||
serialized_data += utils.from_16(item["defense"])
|
||||
serialized_data += utils.from_16(item["element"])
|
||||
serialized_data += utils.from_u8(item["damageScale"])
|
||||
serialized_data += utils.from_u8(item["weaponId"])
|
||||
serialized_data += utils.from_16(item["unk10"])
|
||||
serialized_data += utils.from_u8(item["playerAnim"])
|
||||
serialized_data += utils.from_u8(item["unk13"])
|
||||
serialized_data += utils.from_u8(item["unk14"])
|
||||
serialized_data += utils.from_u8(item["lockDuration"])
|
||||
serialized_data += utils.from_16(item["chainable"])
|
||||
serialized_data += utils.from_u8(item["specialMove"])
|
||||
serialized_data += utils.from_bool(item["isConsumable"])
|
||||
serialized_data += utils.from_u8(item["enemyInvincibilityFrames"])
|
||||
serialized_data += utils.from_u8(item["unk1B"])
|
||||
serialized_data += utils.from_16(item["unk1C"])
|
||||
serialized_data += utils.from_16(item["unk1E"])
|
||||
serialized_data += utils.from_16(item["unk20"])
|
||||
serialized_data += utils.from_16(item["unk22"])
|
||||
serialized_data += utils.from_16(item["mpUsage"])
|
||||
serialized_data += utils.from_16(item["stunFrames"])
|
||||
serialized_data += utils.from_16(item["hitType"])
|
||||
serialized_data += utils.from_16(item["hitEffect"])
|
||||
serialized_data += utils.from_16(item["menuIcon"])
|
||||
serialized_data += utils.from_16(item["menuPalette"])
|
||||
serialized_data += utils.from_16(item["criticalRate"])
|
||||
serialized_data += utils.from_16(item["unk32"])
|
||||
|
||||
expected_data_size = item_count * item_size
|
||||
assert (len(serialized_data) == expected_data_size)
|
||||
|
||||
return serialized_data
|
||||
|
||||
|
||||
class PSXSegEquipment(N64Segment):
|
||||
def __init__(self, rom_start, rom_end, type, name, vram_start, args, yaml):
|
||||
super().__init__(rom_start, rom_end, type, name, vram_start, args, yaml),
|
||||
|
||||
def out_path(self) -> Optional[Path]:
|
||||
return options.opts.asset_path / self.dir / self.name
|
||||
|
||||
def src_path(self) -> Optional[Path]:
|
||||
return options.opts.asset_path / self.dir / f"{self.name}.equipment.json"
|
||||
|
||||
def split(self, rom_bytes):
|
||||
path = self.src_path()
|
||||
path.parent.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
data = self.parse_equipment(
|
||||
rom_bytes[self.rom_start:self.rom_end], rom_bytes)
|
||||
with open(path, "w") as f:
|
||||
f.write(json.dumps(data, indent=4))
|
||||
|
||||
def parse_equipment(self, data: bytearray, rom: bytearray) -> list:
|
||||
def get_ptr_data(src_ptr_data):
|
||||
return rom[utils.to_u32(src_ptr_data) - (self.vram_start - self.rom_start):]
|
||||
|
||||
count = int(len(data) / item_size)
|
||||
expected_data_size = count * item_size
|
||||
if len(data) != expected_data_size:
|
||||
log.write(
|
||||
f"data for '{self.name}' is {expected_data_size - len(data)} too long. Data might look incorrect.", status="warn")
|
||||
|
||||
items = []
|
||||
for i in range(0, count):
|
||||
item_data = data[i * item_size:][:item_size]
|
||||
item = {
|
||||
# debugging stuff
|
||||
"id": i,
|
||||
"id_hex": hex(i)[2:].upper(),
|
||||
"ram_addr": hex(self.vram_start + i * item_size)[2:].upper(),
|
||||
"name_resolved": utils.sotn_menu_name_to_str(get_ptr_data(item_data[0x00:])),
|
||||
"desc_resolved": utils.sotn_menu_desc_to_str(get_ptr_data(item_data[0x04:])),
|
||||
# debugging stuff ends
|
||||
|
||||
"name_addr": utils.to_ptr_str(item_data[0x00:]),
|
||||
"desc_addr": utils.to_ptr_str(item_data[0x04:]),
|
||||
"attack": utils.to_s16(item_data[0x08:]),
|
||||
"defense": utils.to_s16(item_data[0x0A:]),
|
||||
"element": utils.to_u16(item_data[0x0C:]),
|
||||
"damageScale": utils.to_u8(item_data[0x0E:]),
|
||||
"weaponId": utils.to_u8(item_data[0x0F:]),
|
||||
"unk10": utils.to_u16(item_data[0x10:]),
|
||||
"playerAnim": utils.to_u8(item_data[0x12:]),
|
||||
"unk13": utils.to_u8(item_data[0x13:]),
|
||||
"unk14": utils.to_u8(item_data[0x14:]),
|
||||
"lockDuration": utils.to_u8(item_data[0x15:]),
|
||||
"chainable": utils.to_u16(item_data[0x16:]),
|
||||
"specialMove": utils.to_u8(item_data[0x18:]),
|
||||
"isConsumable": utils.to_bool(item_data[0x19:]),
|
||||
"enemyInvincibilityFrames": utils.to_u8(item_data[0x1A:]),
|
||||
"unk1B": utils.to_u8(item_data[0x1B:]),
|
||||
"unk1C": utils.to_u16(item_data[0x1C:]),
|
||||
"unk1E": utils.to_u16(item_data[0x1E:]),
|
||||
"unk20": utils.to_u16(item_data[0x20:]),
|
||||
"unk22": utils.to_u16(item_data[0x22:]),
|
||||
"mpUsage": utils.to_u16(item_data[0x24:]),
|
||||
"stunFrames": utils.to_u16(item_data[0x26:]),
|
||||
"hitType": utils.to_u16(item_data[0x28:]),
|
||||
"hitEffect": utils.to_u16(item_data[0x2A:]),
|
||||
"menuIcon": utils.to_u16(item_data[0x2C:]),
|
||||
"menuPalette": utils.to_u16(item_data[0x2E:]),
|
||||
"criticalRate": utils.to_u16(item_data[0x30:]),
|
||||
"unk32": utils.to_u16(item_data[0x32:]),
|
||||
}
|
||||
items.append(item)
|
||||
return items
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
input_file_name = sys.argv[1]
|
||||
output_file_name = sys.argv[2]
|
||||
|
||||
with open(input_file_name, "r") as f_in:
|
||||
data = serialize_equipment(f_in.read())
|
||||
with open(output_file_name, "wb") as f_out:
|
||||
f_out.write(data)
|
@ -1,6 +1,5 @@
|
||||
#!/usr/bin/python3
|
||||
|
||||
import ctypes
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
@ -11,23 +10,21 @@ sys.path.append(f"{os.getcwd()}/tools/n64splat")
|
||||
sys.path.append(f"{os.getcwd()}/tools/splat_ext")
|
||||
from util import options
|
||||
from segtypes.n64.segment import N64Segment
|
||||
import utils
|
||||
|
||||
item_size = 0xA # sizeof(LayoutObject)
|
||||
|
||||
|
||||
def parse_layoutobj(data: bytearray) -> list:
|
||||
def to_s16(data):
|
||||
return ctypes.c_short(data[0] | (data[1] << 8)).value
|
||||
|
||||
count = int(len(data) / item_size)
|
||||
items = []
|
||||
for i in range(0, count):
|
||||
item = {
|
||||
"x": to_s16(data[i * item_size + 0:]),
|
||||
"y": to_s16(data[i * item_size + 2:]),
|
||||
"objectId": to_s16(data[i * item_size + 4:]),
|
||||
"objectRoomIndex": to_s16(data[i * item_size + 6:]),
|
||||
"subId": to_s16(data[i * item_size + 8:]),
|
||||
"x": utils.to_s16(data[i * item_size + 0:]),
|
||||
"y": utils.to_s16(data[i * item_size + 2:]),
|
||||
"objectId": utils.to_s16(data[i * item_size + 4:]),
|
||||
"objectRoomIndex": utils.to_s16(data[i * item_size + 6:]),
|
||||
"subId": utils.to_s16(data[i * item_size + 8:]),
|
||||
}
|
||||
if item["x"] == -1 and item["y"] == -1:
|
||||
break
|
||||
|
@ -1,6 +1,5 @@
|
||||
#!/usr/bin/python3
|
||||
|
||||
import ctypes
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
@ -53,7 +52,6 @@ class PSXSegRoomdef(N64Segment):
|
||||
f.write(json.dumps(data, indent=4))
|
||||
|
||||
def parse_roomdef(self, data: bytearray) -> list:
|
||||
|
||||
count = int(len(data) / item_size)
|
||||
expected_data_size = count * item_size + 4
|
||||
if len(data) != expected_data_size:
|
||||
|
@ -1,6 +1,5 @@
|
||||
#!/usr/bin/python3
|
||||
|
||||
import ctypes
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
@ -11,29 +10,27 @@ sys.path.append(f"{os.getcwd()}/tools/n64splat")
|
||||
sys.path.append(f"{os.getcwd()}/tools/splat_ext")
|
||||
from util import options
|
||||
from segtypes.n64.segment import N64Segment
|
||||
import utils
|
||||
|
||||
item_size = 0x18 # sizeof(SpritePart)
|
||||
|
||||
|
||||
def parse_spriteparts(data: bytearray) -> list:
|
||||
def to_s16(data):
|
||||
return ctypes.c_short(data[0] | (data[1] << 8)).value
|
||||
|
||||
count = to_s16(data[0:])
|
||||
count = utils.to_s16(data[0:])
|
||||
items = []
|
||||
for i in range(0, count):
|
||||
items.append({
|
||||
"flags": to_s16(data[2 + i * item_size + 0:]),
|
||||
"offsetx": to_s16(data[2 + i * item_size + 2:]),
|
||||
"offsety": to_s16(data[2 + i * item_size + 4:]),
|
||||
"width": to_s16(data[2 + i * item_size + 6:]),
|
||||
"height": to_s16(data[2 + i * item_size + 8:]),
|
||||
"clut": to_s16(data[2 + i * item_size + 10:]),
|
||||
"tileset": to_s16(data[2 + i * item_size + 12:]),
|
||||
"left": to_s16(data[2 + i * item_size + 14:]),
|
||||
"top": to_s16(data[2 + i * item_size + 16:]),
|
||||
"right": to_s16(data[2 + i * item_size + 18:]),
|
||||
"bottom": to_s16(data[2 + i * item_size + 20:]),
|
||||
"flags": utils.to_s16(data[2 + i * item_size + 0:]),
|
||||
"offsetx": utils.to_s16(data[2 + i * item_size + 2:]),
|
||||
"offsety": utils.to_s16(data[2 + i * item_size + 4:]),
|
||||
"width": utils.to_s16(data[2 + i * item_size + 6:]),
|
||||
"height": utils.to_s16(data[2 + i * item_size + 8:]),
|
||||
"clut": utils.to_s16(data[2 + i * item_size + 10:]),
|
||||
"tileset": utils.to_s16(data[2 + i * item_size + 12:]),
|
||||
"left": utils.to_s16(data[2 + i * item_size + 14:]),
|
||||
"top": utils.to_s16(data[2 + i * item_size + 16:]),
|
||||
"right": utils.to_s16(data[2 + i * item_size + 18:]),
|
||||
"bottom": utils.to_s16(data[2 + i * item_size + 20:]),
|
||||
})
|
||||
return items
|
||||
|
||||
|
@ -13,6 +13,8 @@ sys.path.append(f"{os.getcwd()}/tools/splat_ext")
|
||||
from util import options
|
||||
from segtypes.n64.segment import N64Segment
|
||||
from util.symbols import spim_context
|
||||
import utils
|
||||
|
||||
|
||||
def generate_assembly_spritepartslist(writer: io.BufferedWriter, name: str, content: str):
|
||||
obj = json.loads(content)
|
||||
@ -39,24 +41,18 @@ class PSXSegSpritepartslist(N64Segment):
|
||||
path = self.src_path()
|
||||
path.parent.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
data = self.parse_spritepartslist(rom_bytes[self.rom_start:self.rom_end])
|
||||
data = self.parse_spritepartslist(
|
||||
rom_bytes[self.rom_start:self.rom_end])
|
||||
with open(path, "w") as f:
|
||||
f.write(json.dumps(data, indent=4))
|
||||
|
||||
def parse_spritepartslist(self, data: bytearray):
|
||||
def to_u32(data):
|
||||
return ctypes.c_uint32(
|
||||
data[0] |
|
||||
(data[1] << 8) |
|
||||
(data[2] << 16) |
|
||||
(data[3] << 24)).value
|
||||
|
||||
sprite_parts_list = [
|
||||
0
|
||||
]
|
||||
idx = 1
|
||||
while True:
|
||||
addr = to_u32(data[idx * 4:])
|
||||
addr = utils.to_u32(data[idx * 4:])
|
||||
idx += 1
|
||||
if addr == 0:
|
||||
break
|
||||
|
@ -13,6 +13,8 @@ sys.path.append(f"{os.getcwd()}/tools/splat_ext")
|
||||
from util import options
|
||||
from segtypes.n64.segment import N64Segment
|
||||
from util.symbols import spim_context
|
||||
import utils
|
||||
|
||||
|
||||
def generate_assembly_tiledef(writer: io.BufferedWriter, name: str, content: str):
|
||||
obj = json.loads(content)
|
||||
@ -46,18 +48,11 @@ class PSXSegTiledef(N64Segment):
|
||||
f.write(json.dumps(data, indent=4))
|
||||
|
||||
def parse_tiledef(self, data: bytearray):
|
||||
def to_u32(data):
|
||||
return ctypes.c_uint32(
|
||||
data[0] |
|
||||
(data[1] << 8) |
|
||||
(data[2] << 16) |
|
||||
(data[3] << 24)).value
|
||||
|
||||
return {
|
||||
"gfxPage": self.get_symbol(to_u32(data[0:])).given_name,
|
||||
"gfxIndex": self.get_symbol(to_u32(data[4:])).given_name,
|
||||
"clut": self.get_symbol(to_u32(data[8:])).given_name,
|
||||
"collision": self.get_symbol(to_u32(data[12:])).given_name,
|
||||
"gfxPage": self.get_symbol(utils.to_u32(data[0:])).given_name,
|
||||
"gfxIndex": self.get_symbol(utils.to_u32(data[4:])).given_name,
|
||||
"clut": self.get_symbol(utils.to_u32(data[8:])).given_name,
|
||||
"collision": self.get_symbol(utils.to_u32(data[12:])).given_name,
|
||||
}
|
||||
|
||||
|
||||
|
103
tools/splat_ext/utils.py
Normal file
103
tools/splat_ext/utils.py
Normal file
@ -0,0 +1,103 @@
|
||||
import ctypes
|
||||
|
||||
subchar81_dict = {
|
||||
0x44: 0x2E, # '.'
|
||||
0x43: 0x2C, # ','
|
||||
0x49: 0x21, # '!'
|
||||
0x66: 0x27, # '''
|
||||
0x68: 0x22, # '"'
|
||||
0x69: 0x28, # '('
|
||||
0x6A: 0x29, # ')'
|
||||
0x6D: 0x5B, # '['
|
||||
0x6E: 0x5D, # ']'
|
||||
0x7C: 0x2D, # '-'
|
||||
0x93: 0x25 # '%'
|
||||
}
|
||||
|
||||
|
||||
def from_s32(num):
|
||||
return num.to_bytes(4, byteorder='little', signed=True)
|
||||
|
||||
|
||||
def to_s32(data):
|
||||
return int.from_bytes(data, byteorder='little', signed=True)
|
||||
|
||||
|
||||
def from_u32(num):
|
||||
return bytes([(num >> i) & 0xff for i in range(0, 32, 8)])
|
||||
|
||||
|
||||
def to_u32(data):
|
||||
return (data[0] << 0) | (data[1] << 8) | (data[2] << 16) | (data[3] << 24)
|
||||
|
||||
|
||||
def from_16(num):
|
||||
return bytes([num & 0xff, (num >> 8) & 0xff])
|
||||
|
||||
|
||||
def to_s16(data):
|
||||
return ctypes.c_int16(data[0] | (data[1] << 8)).value
|
||||
|
||||
|
||||
def to_u16(data):
|
||||
return data[0] | (data[1] << 8)
|
||||
|
||||
|
||||
def from_u8(num):
|
||||
return bytes([num])
|
||||
|
||||
|
||||
def to_u8(data):
|
||||
return data[0]
|
||||
|
||||
|
||||
def from_bool(val):
|
||||
return bytes([int(val)])
|
||||
|
||||
|
||||
def to_bool(data):
|
||||
return bool(data[0])
|
||||
|
||||
|
||||
def from_ptr_str(ptr_str):
|
||||
num = int(ptr_str, 16)
|
||||
return from_u32(num)
|
||||
|
||||
|
||||
def to_ptr_str(data):
|
||||
return f"0x{to_u32(data):08X}"
|
||||
|
||||
|
||||
def sotn_menu_name_to_str(data: bytearray) -> str:
|
||||
end_of_str = data.find(0xFF)
|
||||
assert (end_of_str >= 0)
|
||||
if end_of_str == 0:
|
||||
return ""
|
||||
|
||||
utf8 = bytearray(data[:end_of_str])
|
||||
for i in range(len(utf8)):
|
||||
utf8[i] += 0x20
|
||||
return utf8.decode('utf-8')
|
||||
|
||||
|
||||
def sotn_menu_desc_to_str(data: bytearray) -> str:
|
||||
utf8 = []
|
||||
while data[0] not in {0xFF, 0x00}:
|
||||
if data[0] == 0x81:
|
||||
ch = subchar81_dict.get(data[1])
|
||||
if ch is None:
|
||||
raise Exception(
|
||||
f"subchar {data[0]:02X} {data[1]:02X} not recognised")
|
||||
data = data[2:]
|
||||
elif data[0] == 0x82:
|
||||
if 0x4F <= data[1] <= 0x58:
|
||||
ch = data[1] - 0x4F + 0x30 # from '0' to '9'
|
||||
else:
|
||||
raise Exception(
|
||||
f"subchar {data[0]:02X} {data[1]:02X} not recognised")
|
||||
data = data[2:]
|
||||
else:
|
||||
ch = data[0]
|
||||
data = data[1:]
|
||||
utf8.append(ch)
|
||||
return bytes(utf8).decode('utf-8')
|
Loading…
Reference in New Issue
Block a user