-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdeserialize.rb
226 lines (199 loc) · 5.34 KB
/
deserialize.rb
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
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
#!/usr/bin/env ruby
module Java
module Deserialize
class DeserializeException < RuntimeError
def inititialize(ex)
@ex = ex
end
end
class ObjectInputStream
def initialize(input, reg)
@input = input
@handles = []
@registry = reg
end
def read_utf
len = @input.read(2).unpack('S>')[0]
@input.read(len)
end
def read_handle
handle = @input.read(4).unpack('I>')[0] - 0x7e0000
@handles[handle]
end
def read_string
read_string_type(@input.read(1).unpack('C')[0])
end
def read_string_type(type)
if type == 0x70
return
elsif type == 0x71
return read_handle
elsif type != 0x74 # TC_BLOCKDATA
raise 'Unexpected type: Not string ' + type.to_s
end
str = read_utf
@handles.push(str)
str
end
def read_blockdata
type = @input.read(1).unpack('C')[0]
raise 'Unexpected type: Not block data' if type != 0x77 # TC_BLOCKDATA
blen = @input.read(1).unpack('C')[0]
bdata = @input.read(blen)
bdata
end
def skip_custom
loop do
type = @input.read(1).unpack('C')[0]
if type == 0x77
blen = @input.read(1).unpack('C')[0]
@input.read(blen)
elsif type == 0x78
return
else
read_object_type(type)
end
end
end
def read_object
data = @input.read(1)
return if data.nil?
type = data.unpack('C')[0]
read_object_type(type)
end
def read_object_type(type)
if type == 0x70
nil
elsif type == 0x71
read_handle
elsif type == 0x72
read_class_desc(type)
elsif type == 0x73
read_ordinary_object
elsif type == 0x74
read_string_type(type)
elsif type == 0x75
read_array
elsif type == 0x7b
read_exception
else
raise 'Unsupported object type ' + type.to_s(16)
end
end
def defaultReadObject(desc)
read_object_fields(desc)
end
def read_object_fields(desc)
fields = {}
for pf in desc[3]
t = pf[1]
if t == 'J' || t == 'D'
val = @input.read(8)
elsif t == 'I' || t == 'F'
val = @input.read(4)
elsif t == 'C' || t == 'S'
val = @input.read(2)
elsif t == 'B' || t == 'Z'
val = @input.read(1)
else
raise 'Invalid value type ' + t.to_s
end
fields[pf[0]] = val
end
for of in desc[4]
val = read_object
fields[of[0]] = val
end
fields
end
def read_ordinary_object
desc = read_class_desc
obj = [desc, nil]
@handles.push(obj)
flags = desc[2]
if flags & 0x8 == 0x8
raise 'Externalizable'
else
fields = {}
obj[1] = fields
chain = []
cur = desc
begin
chain.insert(0, cur)
cur = cur[5]
end while !cur.nil?
for cdesc in chain
tstr = 'L' + cdesc[0].tr('.', '/') + ';'
sdesc = @registry.getDescriptor(tstr)
if !sdesc.nil? && sdesc.fetch('hasReadObject', false)
read = @registry.getHandler(tstr).readObject(self, cdesc)
fields.merge!(read) unless read.nil?
else
fields.merge!(read_object_fields(cdesc))
end
skip_custom if cdesc[2] & 0x01 == 0x01
end
end
obj
end
def read_exception
ex = read_object
raise DeserializeException, ex
end
def read_array
desc = read_class_desc
len = @input.read(4).unpack('I>')[0]
values = []
@handles.push(values)
for i in 0..len - 1
values.push(read_object)
end
values
end
def read_class_desc
type = @input.read(1).unpack('C')[0]
read_class_desc_type(type)
end
def read_class_desc_type(type)
if type == 0x70
nil
elsif type == 0x71
read_handle
elsif type == 0x72
name = read_utf
suid, flags, nfields = @input.read(11).unpack('Q>CS>')
primfields = []
objfields = []
desc = [name, suid, flags, primfields, objfields, nil]
@handles.push(desc)
for i in 0..nfields - 1
tcode = @input.read(1)[0]
fname = read_utf
if tcode == 'L' || tcode == '['
tname = read_string
objfields.push([fname, tname])
else
primfields.push([fname, tcode])
end
end
skip_custom
desc[5] = read_class_desc
desc
elsif type == 0x7d
intfs = []
desc = ['proxy', 0, 0, [], [], nil, intfs]
@handles.push(desc)
nintf = @input.read(4).unpack('L>')[0]
for i in 0..nintf - 1
intfs[i] = read_utf
end
skip_custom
desc[5] = read_class_desc
desc
else
raise 'Not a class descriptor ' + type.to_s(16)
end
end
end
end
end