ChocolateBird/scripts/struct.gd

219 lines
6.7 KiB
GDScript3
Raw Normal View History

#warning-ignore-all:shadowed_variable
#warning-ignore-all:unused_argument
# leftover_bits is array of form [count, value]
# array is used for reference semantics as get and put operations may mutate it
class StructType:
func get_value(buffer: StreamPeer, leftover_bits: Array):
return
func put_value(buffer: StreamPeer, value, leftover_bits: Array):
return
class U8 extends StructType:
func get_value(buffer: StreamPeer, leftover_bits: Array):
return buffer.get_u8()
func put_value(buffer: StreamPeer, value, leftover_bits: Array):
buffer.put_u8(value)
class S8 extends StructType:
func get_value(buffer: StreamPeer, leftover_bits: Array):
return buffer.get_8()
func put_value(buffer: StreamPeer, value, leftover_bits: Array):
buffer.put_8(value)
class U16 extends StructType:
func get_value(buffer: StreamPeer, leftover_bits: Array):
return buffer.get_u16()
func put_value(buffer: StreamPeer, value, leftover_bits: Array):
buffer.put_u16(value)
class S16 extends StructType:
func get_value(buffer: StreamPeer, leftover_bits: Array):
return buffer.get_16()
func put_value(buffer: StreamPeer, value, leftover_bits: Array):
buffer.put_16(value)
class U24 extends StructType:
func get_value(buffer: StreamPeer, leftover_bits: Array):
return buffer.get_u16() | (buffer.get_u8() << 16)
func put_value(buffer: StreamPeer, value, leftover_bits: Array):
buffer.put_u16(value & 0xFFFF)
buffer.put_u8(value >> 16)
class S24 extends StructType:
func get_value(buffer: StreamPeer, leftover_bits: Array):
var unsigned = buffer.get_u16() | (buffer.get_u8() << 16)
return unsigned - (2 * (unsigned & 0x800000))
func put_value(buffer: StreamPeer, value, leftover_bits: Array):
var unsigned = value % 0x1000000
buffer.put_u16(unsigned & 0xFFFF)
buffer.put_u8(unsigned >> 16)
class U32 extends StructType:
func get_value(buffer: StreamPeer, leftover_bits: Array):
return buffer.get_u32()
func put_value(buffer: StreamPeer, value, leftover_bits: Array):
buffer.put_u32(value)
class S32 extends StructType:
func get_value(buffer: StreamPeer, leftover_bits: Array):
return buffer.get_32()
func put_value(buffer: StreamPeer, value, leftover_bits: Array):
buffer.put_32(value)
class UBits extends StructType:
var bits = 8
func _init(bits: int):
self.bits = bits
func get_value(buffer: StreamPeer, leftover_bits: Array):
while leftover_bits[0] < bits:
leftover_bits[1] |= buffer.get_u8() << leftover_bits[0]
leftover_bits[0] += 8
var value = leftover_bits[1] & ((1 << bits)-1)
leftover_bits[1] = leftover_bits[1] >> bits
leftover_bits[0] -= bits
return value
func put_value(buffer: StreamPeer, value, leftover_bits: Array):
2023-08-03 21:02:41 +09:30
leftover_bits[1] |= value << leftover_bits[0]
leftover_bits[0] += bits
while leftover_bits[0] >= 8:
buffer.put_8(leftover_bits[1] & 0xFF)
leftover_bits[0] -= 8
leftover_bits[1] = leftover_bits[1] >> 8
class Struct extends StructType:
var members := [] # Array of [name, StructType]
func get_value(buffer: StreamPeer, leftover_bits: Array):
var result = {}
for member in members:
var key: String = member[0]
var structType: StructType = member[1]
result[key] = structType.get_value(buffer, leftover_bits)
return result
func put_value(buffer: StreamPeer, value, leftover_bits: Array):
for member in members:
var key: String = member[0]
var structType: StructType = member[1]
if not (key in value):
print_debug('Key "%s" missing from value supplied' % key)
return
structType.put_value(buffer, value[key], leftover_bits)
class StructArrayType extends StructType:
var count: int
var structType: StructType
func _init(count, structType) -> void:
self.count = count
self.structType = structType
func get_value(buffer: StreamPeer, leftover_bits: Array):
# Might be a bit too much branching but oh well
if self.structType is U8:
var result = PoolByteArray()
# Slight optimization over calling the method
for i in self.count:
result.append(buffer.get_u8())
return result
var result = []
for i in self.count:
result.append(self.structType.get_value(buffer, leftover_bits))
return result
func put_value(buffer: StreamPeer, value, leftover_bits: Array):
if len(value) < self.count:
print_debug('Not enough values supplied')
return
for i in self.count:
self.structType.put_value(buffer, value[i], leftover_bits)
static func get_base_structarraytypes() -> Dictionary:
return {
'u8': U8.new(),
'u16': U16.new(),
'u24': U24.new(),
'u32': U32.new(),
's8': S8.new(),
's16': S16.new(),
's24': S24.new(),
's32': S32.new(),
}
static func get_structarraytype(type: String, existing_structs: Dictionary):
var tokens := type.split(' ', false)
var t: String = tokens[-1]
var inner_type
if t in existing_structs:
inner_type = existing_structs[t]
elif t[0] == 'u':
var b := int(t.substr(1))
if b > 0:
inner_type = UBits.new(b)
existing_structs['u%d'%b] = inner_type # Cache it for future use
if not inner_type:
print_debug('typestring "%s" has no matches for "%s" in existing structs' % [type, t])
return
var l := len(tokens)
if l == 1:
return inner_type
# Our parsing goal is to turn 'a of b of c of d' into StructArrayType<StructArrayType<StructArrayType<d, c>, b>, a>
# Our strategy is to parse backwards over the tokens, changing inner_type at each point
# a of b of c of (d)
# a of b of (c of d)
# a of (b of c of d)
# (a of b of c of d)
# done
var i := l-2
while i > -1:
match tokens[i]:
'of':
i -= 1
var l1 = int(tokens[i])
if l1 > 1:
inner_type = StructArrayType.new(l1, inner_type) # Might be worth caching these later on if we use them more
i -= 1
var k:
print_debug('Invalid keyword used in type designator: "%s"' % k)
return
return inner_type
2023-08-04 14:18:17 +09:30
static func parse_struct_definitions_from_tsv_file(tsv_file: File, existing_structs: Dictionary) -> void:
var current_struct: Struct
var line_num := 0 # Currently only used for step-through debugging
while tsv_file.get_position() < tsv_file.get_len():
var line := tsv_file.get_csv_line('\t')
line_num += 1
var size = line.size()
if size < 2:
continue
# Size is at least 2
var type := line[0]
var label := line[1]
if type == 'struct':
# New struct declaration
current_struct = Struct.new()
existing_structs[label] = current_struct
elif type and label:
# TODO: Maybe store the trailing comments somewhere?
current_struct.members.append([label, get_structarraytype(type, existing_structs)])
static func parse_struct_definitions_from_tsv_filename(filename: String, existing_structs: Dictionary) -> int:
var file := File.new()
match file.open(filename, File.READ):
OK:
parse_struct_definitions_from_tsv_file(file, existing_structs)
return OK
var error:
return error