Skip to content

Instantly share code, notes, and snippets.

@wildbook
Last active January 24, 2019 23:38
Show Gist options
  • Save wildbook/6e15db8f5f91e099668477e84ee587f7 to your computer and use it in GitHub Desktop.
Save wildbook/6e15db8f5f91e099668477e84ee587f7 to your computer and use it in GitHub Desktop.
Ports moonshadow565's SiphoningStrike structs from C# to Rust
import re
import os
import sys
# Version 1
# USAGE:
# corrode.py
# MISSING:
# detect fucked floats - "(reader.ReadByte() - 128) / 100.0f;"
# bunch of types
# sized_string
# sized_string_null
# string_null
# Vec
# .. and guaranteed a lot more ..
template_base = (
'#[packet_id({packet_id})]' '\n'
'#[derive(Deserialize, Serialize, Copy, Clone, Debug, Default)]' '\n'
'pub struct {packet_name} {{' '\n'
'{fields}'
'}}' '\n'
)
template_bitfield_field = (
' {field_name}: bool = bitfield & {field_index} != 0,' '\n'
)
template_bitfield_serialization_field = (
' if self.{field_name} {{' '\n'
' byte |= {field_index};' '\n'
' }}' '\n'
)
template_bitfield = (
'make_bitfield! {{' '\n'
' #[derive(Copy, Clone, Debug, Default)]' '\n'
' pub struct {name} = bitfield: u8 {{' '\n'
'{bitfield_fields}'
' }}' '\n'
'}}' '\n'
'' '\n'
'impl serde::Serialize for {name} {{' '\n'
' fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>' '\n'
' where' '\n'
' S: serde::Serializer,' '\n'
' {{' '\n'
' let mut byte = 0;' '\n'
'{serialize_fields}'
' s.serialize_u8(byte)' '\n'
' }}' '\n'
'}}'
)
template_field = (
'{serde}'
' pub {field_name}: {field_type},' '\n'
)
builtins = {
# Convert
"short" : "i16",
"byte" : "u8",
"int" : "i32",
"float" : "f32",
"uint" : "u32",
"string": "String",
"uint" : "u32"
}
def fix_case(input):
output = re.sub(r'([A-Z]+)', lambda m: '_' + m.group(1).lower(), input)
output = re.sub(r'^_', lambda m: '', output)
return output
def get_serde_tag(type, name, csharp):
serde = ''
if type == 'String':
fixed = re.search('this\.{name} = reader\.ReadFixedString\(([0-9]*)\);'.format(name = name), csharp)
zero_terminated = re.search('this\.{name} = reader\.ReadZeroTerminatedString\(([0-9]*)\);'.format(name = name), csharp)
if fixed:
length = fixed.group(1)
serde = ' #[serde(with = "crate::string_{length}")]\n'.format(length = length)
elif zero_terminated:
serde = ' #[serde(with = "crate::string_null")]\n'
else:
0/0 # crash.
return serde
def get_bitfield_struct(packet_name, bitfields_r, csharp):
bitfield_out = ''
bitfields = re.finditer('this\.(.*?) = \(bitfield', csharp)
serialize_fields = ''
bitfield_fields = ''
for bitfield_field in bitfields_r:
serde = ''
bitfield_field_name = bitfield_field.group(1)
bitfield_field_index = bitfield_field.group(2)
serialize_fields += template_bitfield_serialization_field.format(
field_name = fix_case(bitfield_field_name),
field_index = bitfield_field_index
)
bitfield_fields += template_bitfield_field.format(
field_name = fix_case(bitfield_field_name),
field_index = bitfield_field_index
)
bitfield_out += template_bitfield.format(
name = packet_name + '_Bitfield',
serialize_fields = serialize_fields,
bitfield_fields = bitfield_fields
)
return '' if bitfield_out == '' else '\n' + bitfield_out
def port_packet_file(csharp):
packet_name = re.search(r'class (.*?) ', csharp).group(1)
packet_id = re.search(r' : GamePacket(?:, [\w]*)* *\/\/ 0x([A-Fa-f\d]{0,2})', csharp).group(1)
found_bitfield = False
fields_r = re.finditer(r'public (\w*?) (\w*?) \{', csharp)
bitfields_r = list(re.finditer(r'this\.([^ ]*?) = \(bitfield & ([0-9]*)\) != 0;', csharp))
fields = '';
for field in fields_r:
type = builtins[field.group(1)] if field.group(1) in builtins else field.group(1)
name = field.group(2)
serde = get_serde_tag(type, name, csharp)
if not (name in map(lambda x: x.group(1), bitfields_r)):
fields += template_field.format(
serde = serde,
field_name = fix_case(name),
field_type = type)
elif not found_bitfield:
fields += template_field.format(
serde = serde,
field_name = 'bitfield',
field_type = packet_name + '_Bitfield')
found_bitfield = True
out = template_base.format(
packet_id = packet_id,
packet_name = packet_name,
fields = fields
)
out += get_bitfield_struct(packet_name, bitfields_r, csharp)
return out
root = "SiphoningStrike-master/SiphoningStrike/Game"
for file in os.listdir(root):
if file.endswith(".cs"):
print(os.path.join(root, file))
with open(filename, 'r') as cs_file:
with open(filename[:-2] + 'rs', 'w+') as rs_file:
csharp = cs_file.read()
rs_file.write(port_packet_file(os.path.join(root, file)))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment