ChocolateBird/scripts/struct.gd

190 lines
5.7 KiB
GDScript

#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):
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