-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathRubyMarshal.boo
More file actions
168 lines (146 loc) · 5.12 KB
/
RubyMarshal.boo
File metadata and controls
168 lines (146 loc) · 5.12 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
namespace TURBU.RubyMarshal
import System.IO
import System.Text
import TURBU.Meta
callable UserDefMarshal(sr as BinaryReader) as object
class RubyMarshal():
private _symbols = List[of Hash]()
private _userDefines = System.Collections.Generic.Dictionary[of string, UserDefMarshal]()
def AddUnique(name as string, reader as UserDefMarshal):
_userDefines.Add(name, reader)
def Read(filename as string) as Object:
_symbols.Clear()
resultList as List = List()
using fs = FileStream(filename, FileMode.Open), sr = BinaryReader(fs):
while fs.Position < fs.Length:
versionMajor = sr.Read()
versionMinor = sr.Read()
break unless versionMajor == 4 and versionMinor == 8
result = ReadElement(sr)
resultList.Add(result)
return (result if resultList.Count == 1 else resultList)
private def ReadElement(sr as BinaryReader):
elem = sr.ReadByte()
caseOf elem:
case 0x22: return ReadAsciiString(sr)
case 0x30: return null
case 0x3a: return ReadSymbol(sr)
case 0x3b: return ReadSymlink(sr)
case 0x40: return ReadObjLink(sr)
case 0x46: return false
case 0x49: return ReadIVAR(sr)
case 0x53: return ReadStruct(sr)
case 0x54: return true
case 0x5b: return ReadArray(sr)
case 0x63: return ReadClass(sr)
case 0x66: return ReadFloat(sr)
case 0x69: return ReadInteger(sr)
case 0x6d: return ReadModule(sr)
case 0x6f: return ReadObject(sr)
case 0x75: return ReadUnique(sr)
case 0x7b: return ReadHash(sr)
case 0x7d: return ReadHashDefault(sr)
default: raise "Unknown element type ($(elem.ToString('X')))"
private def ReadFloat(sr as BinaryReader) as double:
var str = ReadAsciiString(sr)
var zIndex = str.IndexOf(char(0))
if zIndex > 0:
str = str[:zIndex]
return double.Parse(str)
private def ReadInteger(sr as BinaryReader) as int:
value as int = sr.ReadSByte()
return 0 if value == 0
if value < 0:
sign = -1
value *= sign
else: sign = 1
return (value - 5) * sign if value > 5 and value < 0xFA
if value < 5:
result = 0
for i in range(value):
result |= sr.ReadByte() << (8 * i)
return result * sign
else: assert false, "Unknown integer size"
private def ReadAsciiString(sr as BinaryReader) as string:
buffer = sr.ReadBytes(ReadInteger(sr))
return Encoding.UTF8.GetString(buffer)
private def ReadStringHash(sr as BinaryReader, name as string) as Hash:
return {'Type': name, 'Name': ReadAsciiString(sr)}
private def ReadSymbol(sr as BinaryReader) as Hash:
result = ReadStringHash(sr, 'Symbol')
_symbols.Add(result)
return result
private def ReadSymlink(sr as BinaryReader) as Hash:
return _symbols[ReadInteger(sr)]
private def ReadObjLink(sr as BinaryReader) as Hash:
return {'Type': 'ObjLink', 'ID': ReadInteger(sr)}
private def ReadIVAR(sr as BinaryReader) as Hash:
assert sr.ReadByte() == 0x22
value = ReadAsciiString(sr)
count = ReadInteger(sr)
encoding1 = ReadElement(sr)
encoding2 = ReadElement(sr)
properties = []
for i in range(1, count):
properties.Add(ReadElement(sr))
return {'Type': 'IVAR', 'Object': value, 'Encoding': {encoding1: encoding2}, 'Props': properties}
private def ReadArray(sr as BinaryReader) as List:
result = []
count = ReadInteger(sr)
for i in range(count):
result.Add(ReadElement(sr))
return result
private def ReadHash(sr as BinaryReader) as Hash:
values = {}
result = {'Type': 'Hash', 'Values': values}
count = ReadInteger(sr)
for i in range(count):
key = ReadElement(sr)
value = ReadElement(sr)
values.Add(key, value)
return result
private def ReadHashDefault(sr as BinaryReader) as Hash:
var result = ReadHash(sr)
result['Default'] = ReadElement(sr)
return result
private def ReadClass(sr as BinaryReader) as Hash:
return ReadStringHash(sr, 'Class')
private def ReadModule(sr as BinaryReader) as Hash:
return ReadStringHash(sr, 'Module')
private def ReadObject(sr as BinaryReader) as Hash:
symbol as object
elem = sr.ReadByte()
caseOf elem:
case 0x3a: symbol = ReadSymbol(sr)['Name']
case 0x3b: symbol = ReadSymlink(sr)['Name']
default: raise "Unknown Object name type ($(elem.ToString('X')))"
values = {}
result = {'Type': 'Object', 'Class': symbol, 'Values': values}
count = ReadInteger(sr)
for i in range(count):
key = ReadElement(sr)
assert key isa int or key isa Hash
if key isa Hash:
kHash = key cast Hash
assert kHash["Type"] == "Symbol"
key = kHash["Name"]
value = ReadElement(sr)
values.Add(key, value) unless values.ContainsKey(key)
return result
private def ReadStruct(sr as BinaryReader) as Hash:
var result = ReadObject(sr)
result['Type'] = 'Struct'
private def ReadUnique(sr as BinaryReader):
elem = sr.ReadByte()
caseOf elem:
case 0x3a: symbol = ReadSymbol(sr)
case 0x3b: symbol = ReadSymlink(sr)
default: raise "Unknown UserDef symbol type ($(elem.ToString('X')))"
userDef = symbol['Name']
buffer = sr.ReadBytes(ReadInteger(sr))
reader as UserDefMarshal
if _userDefines.TryGetValue(userDef, reader):
using ms = MemoryStream(buffer), subReader = BinaryReader(ms):
return reader(subReader)
else:
return {'Type': 'UserDef', 'Name': userDef, 'Data': buffer}