190 lines
5.7 KiB
GDScript3
190 lines
5.7 KiB
GDScript3
|
#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 << bits
|
||
|
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
|