mirror of https://github.com/zeldaret/tp.git
225 lines
8.0 KiB
Python
225 lines
8.0 KiB
Python
import struct
|
|
|
|
from dataclasses import dataclass, field
|
|
from typing import List, Tuple
|
|
|
|
from ..builder import AsyncBuilder
|
|
from .. import util
|
|
from ..types import *
|
|
from .base import *
|
|
|
|
|
|
@dataclass(eq=False)
|
|
class Literal(ArbitraryData):
|
|
literal_size: int = 0
|
|
values: List[str] = field(default_factory=list)
|
|
padding_values: List[str] = field(default_factory=list)
|
|
|
|
@property
|
|
def element_size(self):
|
|
return self.literal_size
|
|
|
|
def array_type(self):
|
|
size = self.size // self.element_size
|
|
padding = self.padding // self.element_size
|
|
|
|
if size == 1 and padding == 0:
|
|
return self.element_type()
|
|
else:
|
|
return PaddingArrayType.create(
|
|
self.element_type(),
|
|
self.size // self.element_size,
|
|
self.padding // self.element_size)
|
|
|
|
|
|
def literal_values_per_line(self):
|
|
return 8
|
|
|
|
async def export_declaration_body(self, exporter, builder: AsyncBuilder):
|
|
line_length = self.literal_values_per_line()
|
|
count = self.total_element_count
|
|
if len(self.values) == 0:
|
|
await builder.write(f";")
|
|
elif count == 1:
|
|
await builder.write(f" = {self.values[0]};")
|
|
else:
|
|
await builder.write(f" = {{")
|
|
for values in util.chunks(self.values, line_length):
|
|
line = ", ".join([x for x in values])
|
|
await builder.write(f"\t{line},")
|
|
if self.padding_values:
|
|
await builder.write(f"\t/* padding */")
|
|
for values in util.chunks(self.padding_values, line_length):
|
|
line = ", ".join([x for x in values])
|
|
await builder.write(f"\t{line},")
|
|
await builder.write(f"}};")
|
|
|
|
@dataclass(eq=False)
|
|
class Integer(Literal):
|
|
@staticmethod
|
|
def create_with_data(identifier: Identifier, data_type: Type, literal_size: int, addr: int, data: bytearray, values: List[str], padding_data: bytearray, padding_values: List[str]):
|
|
return Integer(
|
|
identifier=identifier,
|
|
literal_size=literal_size,
|
|
addr=addr,
|
|
size=literal_size * len(values),
|
|
values=values,
|
|
data=data,
|
|
data_type=data_type,
|
|
padding=literal_size * len(padding_values),
|
|
padding_values=padding_values,
|
|
padding_data=padding_data
|
|
)
|
|
|
|
@staticmethod
|
|
def create_without_data(identifier: Identifier, data_type: Type, literal_size: int, addr: int, size: int, padding: int):
|
|
return Integer(
|
|
identifier=identifier,
|
|
literal_size=literal_size,
|
|
addr=addr,
|
|
size=size,
|
|
values=[],
|
|
data_type=data_type,
|
|
padding=padding,
|
|
padding_values=[]
|
|
)
|
|
|
|
@staticmethod
|
|
def u32_from(data: bytearray) -> List[int]:
|
|
assert len(data) % 4 == 0
|
|
return [
|
|
struct.unpack('>I', x)[0]
|
|
for x in util.chunks(data, 4)
|
|
]
|
|
|
|
@staticmethod
|
|
def create_u32(identifier: Identifier, addr: int, data: bytearray, values: List[int], padding_data: bytearray, padding_values: List[int]):
|
|
str_values = [ f"0x{x:08X}" for x in values ]
|
|
str_padding_values = [ f"0x{x:08X}" for x in padding_values ]
|
|
return Integer.create_with_data(identifier, U32, 4, addr, data, str_values, padding_data, str_padding_values)
|
|
|
|
@staticmethod
|
|
def u16_from(data: bytearray) -> List[int]:
|
|
assert len(data) % 2 == 0
|
|
return [
|
|
struct.unpack('>H', x)[0]
|
|
for x in util.chunks(data, 2)
|
|
]
|
|
|
|
@staticmethod
|
|
def create_u16(identifier: Identifier, addr: int, data: bytearray, values: List[int], padding_data: bytearray, padding_values: List[int]):
|
|
str_values = [ f"0x{x:04X}" for x in values ]
|
|
str_padding_values = [ f"0x{x:04X}" for x in padding_values ]
|
|
return Integer.create_with_data(identifier, U16, 2, addr, data, str_values, padding_data, str_padding_values)
|
|
|
|
|
|
|
|
|
|
@dataclass(eq=False)
|
|
class FloatingPoint(Literal):
|
|
@staticmethod
|
|
def create_with_data(identifier: Identifier, data_type: Type, literal_size: int, addr: int, values: List[str], padding_values: List[str]):
|
|
return FloatingPoint(
|
|
identifier=identifier,
|
|
literal_size=literal_size,
|
|
addr=addr,
|
|
size=literal_size * len(values),
|
|
values=values,
|
|
data_type=data_type,
|
|
padding=literal_size * len(padding_values),
|
|
padding_values=padding_values
|
|
)
|
|
|
|
@staticmethod
|
|
def create_without_data(identifier: Identifier, data_type: Type, literal_size: int, addr: int, size: int, padding: int):
|
|
return FloatingPoint(
|
|
identifier=identifier,
|
|
literal_size=literal_size,
|
|
addr=addr,
|
|
size=size,
|
|
values=[],
|
|
data_type=data_type,
|
|
padding=padding,
|
|
padding_values=[]
|
|
)
|
|
|
|
"""
|
|
single floating-point (32-bit)
|
|
"""
|
|
|
|
@staticmethod
|
|
def f32_from(data: bytearray) -> List[Tuple[int,float]]:
|
|
assert len(data) % 4 == 0
|
|
return [
|
|
(struct.unpack('>I', x)[0], util.bytes2float32(x))
|
|
for x in util.chunks(data, 4)
|
|
]
|
|
|
|
@staticmethod
|
|
def string_float32(data: List[Tuple[int,float]]) -> List[str]:
|
|
values = []
|
|
for u32, f32 in data:
|
|
special_value = util.special_float32(f32)
|
|
if special_value:
|
|
values.append(special_value)
|
|
# TODO: Add support for FLOAT_NAN
|
|
if special_value == "FLOAT_NAN":
|
|
return None
|
|
elif f32 in util.float32_exact:
|
|
fractions = util.float32_exact[f32]
|
|
values.append(f"{fractions[0]}.0f / {fractions[1]}.0f")
|
|
else:
|
|
values.append(f"{f32}f")
|
|
return values
|
|
|
|
@staticmethod
|
|
def create_f32(identifier: Identifier, addr: int, values: List[Tuple[int,float]], padding_values: List[Tuple[int,float]]):
|
|
str_values = FloatingPoint.string_float32(values)
|
|
str_padding_values = FloatingPoint.string_float32(padding_values)
|
|
return FloatingPoint.create_with_data(identifier, F32, 4, addr, str_values, str_padding_values)
|
|
|
|
@staticmethod
|
|
def create_f32_without_data(identifier: Identifier, addr: int, size: int, padding: int):
|
|
return FloatingPoint.create_without_data(identifier, F32, 4, addr, size, padding)
|
|
|
|
"""
|
|
double floating-point 64-bit
|
|
"""
|
|
|
|
@staticmethod
|
|
def f64_from(data: bytearray) -> List[Tuple[int,float]]:
|
|
assert len(data) % 8 == 0
|
|
return [
|
|
(struct.unpack('>Q', x)[0], util.bytes2float64(x))
|
|
for x in util.chunks(data, 8)
|
|
]
|
|
|
|
@staticmethod
|
|
def string_float64(data: List[Tuple[int,float]]) -> List[str]:
|
|
values = []
|
|
for u64, f64 in data:
|
|
special_value = util.special_float64(f64)
|
|
if special_value:
|
|
values.append(special_value)
|
|
elif f64 in util.float64_exact:
|
|
fractions = util.float64_exact[f64]
|
|
values.append(f"{fractions[0]}.0 / {fractions[1]}.0")
|
|
else:
|
|
comment = ""
|
|
if u64 == 0x43300000_00000000:
|
|
comment = " /* cast u32 to float */"
|
|
elif u64 == 0x43300000_80000000:
|
|
comment = " /* cast s32 to float */"
|
|
values.append(f"{f64}{comment}")
|
|
return values
|
|
|
|
@staticmethod
|
|
def create_f64(identifier: Identifier, addr: int, values: List[Tuple[int,float]], padding_values: List[Tuple[int,float]]):
|
|
str_values = FloatingPoint.string_float64(values)
|
|
str_padding_values = FloatingPoint.string_float64(padding_values)
|
|
return FloatingPoint.create_with_data(identifier, F64, 8, addr, str_values, str_padding_values)
|
|
|
|
@staticmethod
|
|
def create_f64_without_data(identifier: Identifier, addr: int, size: int, padding: int):
|
|
return FloatingPoint.create_without_data(identifier, F64, 8, addr, size, padding)
|