marshal-structure 1.1.1 → 2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +2 -1
- data/.autotest +0 -1
- data/History.txt +15 -0
- data/Manifest.txt +7 -0
- data/README.rdoc +16 -21
- data/Rakefile +1 -7
- data/lib/marshal/structure.rb +74 -542
- data/lib/marshal/structure/allocation_counter.rb +172 -0
- data/lib/marshal/structure/parser.rb +276 -0
- data/lib/marshal/structure/test_case.rb +95 -0
- data/lib/marshal/structure/tokenizer.rb +449 -0
- data/test/test_marshal_structure.rb +18 -152
- data/test/test_marshal_structure_allocation_counter.rb +163 -0
- data/test/test_marshal_structure_parser.rb +97 -0
- data/test/test_marshal_structure_tokenizer.rb +344 -0
- metadata +98 -90
- metadata.gz.sig +0 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: ef879e59c6e30f4e9a9794f4b712dbff947c508f
|
4
|
+
data.tar.gz: 7639105aa9aba80c6c7a8ea2293ed783ca3e22e2
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 905840c1775e2787f813ccbc1396b22434b5b41c36eb05136f4d21e3c478f8f3fb676b777c243446712f9fd362b8088c88f115f824e1efcf1b3d0797b656269d
|
7
|
+
data.tar.gz: c95e398a52ac662f5de25770e56077c58dbdf1803b9f79f4364f5e13ab73f611f41312362ef6efefea09e77093a9e0dd6fa0fbe97651e450e6179905762d4188
|
checksums.yaml.gz.sig
ADDED
Binary file
|
data.tar.gz.sig
CHANGED
@@ -1 +1,2 @@
|
|
1
|
-
|
1
|
+
��>Ϡِϣ�&�6�fi'��O���֦�W�M�C[���QO��b<�C3M2�\⌝{��-zv�L�Ή��p+����u_�#S��X��#U�t1�����j��()y(&��;��?Y�s�-�C)c����c[fwv��r1�(����*��Ԩ��h�S��k34��덋��BF��`�B0
|
2
|
+
I���A�1`�A��Z@Vh�qR�c�L�o�h�;���l�0�O)+9b��>�͖NGw��b]4�ޒ{7
|
data/.autotest
CHANGED
data/History.txt
CHANGED
@@ -1,3 +1,18 @@
|
|
1
|
+
=== 2.0 / 2012-05-16
|
2
|
+
|
3
|
+
* API Change
|
4
|
+
* Split #construct into a Tokenizer and Parser. The Structure class is now
|
5
|
+
mostly empty.
|
6
|
+
|
7
|
+
* Enhancements
|
8
|
+
* Added a Tokenizer allows examination of a stream without the creation of
|
9
|
+
excessive objects.
|
10
|
+
* Added a Parser which can be used as a model for further examination of
|
11
|
+
Marshal streams.
|
12
|
+
* Added an ObjectCounter which counts the number of allocations that will be
|
13
|
+
made when loading the stream.
|
14
|
+
* Added Marshal::Structure#load which loads the object using Marshal.
|
15
|
+
|
1
16
|
=== 1.1.1 / 2011-10-06
|
2
17
|
|
3
18
|
* Bug fix
|
data/Manifest.txt
CHANGED
@@ -5,4 +5,11 @@ README.rdoc
|
|
5
5
|
Rakefile
|
6
6
|
bin/marshal_structure
|
7
7
|
lib/marshal/structure.rb
|
8
|
+
lib/marshal/structure/allocation_counter.rb
|
9
|
+
lib/marshal/structure/parser.rb
|
10
|
+
lib/marshal/structure/test_case.rb
|
11
|
+
lib/marshal/structure/tokenizer.rb
|
8
12
|
test/test_marshal_structure.rb
|
13
|
+
test/test_marshal_structure_allocation_counter.rb
|
14
|
+
test/test_marshal_structure_parser.rb
|
15
|
+
test/test_marshal_structure_tokenizer.rb
|
data/README.rdoc
CHANGED
@@ -1,18 +1,17 @@
|
|
1
1
|
= marshal-structure
|
2
2
|
|
3
|
-
|
3
|
+
home :: https://github.com/drbrain/marshal-structure
|
4
|
+
rdoc :: http://docs.seattlerb.org/marshal-structure
|
5
|
+
bugs :: https://github.com/drbrain/marshal-structure/issues
|
4
6
|
|
5
|
-
==
|
7
|
+
== Description
|
6
8
|
|
7
|
-
|
9
|
+
Tools to inspect and analyze Ruby's Marshal serialization format. Supports
|
10
|
+
the Marshal 4.8 format which is emitted by ruby 1.8 through 2.x.
|
8
11
|
|
9
|
-
==
|
12
|
+
== Examples
|
10
13
|
|
11
|
-
|
12
|
-
|
13
|
-
== SYNOPSIS:
|
14
|
-
|
15
|
-
From the command line:
|
14
|
+
To dump the structure of a Marshal stream:
|
16
15
|
|
17
16
|
ruby -rpp -rmarshal/structure \
|
18
17
|
-e 'pp Marshal::Structure.load Marshal.dump "hello"'
|
@@ -24,21 +23,17 @@ Fancier usage:
|
|
24
23
|
|
25
24
|
ms = Marshal::Structure.new Marshal.dump %w[hello world]
|
26
25
|
|
27
|
-
# print the
|
28
|
-
pp ms.
|
29
|
-
|
30
|
-
# print ruby objects in Marshal stream
|
31
|
-
pp ms.objects
|
32
|
-
|
33
|
-
== REQUIREMENTS:
|
26
|
+
# print the stream structure
|
27
|
+
pp ms.structure
|
34
28
|
|
35
|
-
|
29
|
+
# show how many allocations are required to load the stream
|
30
|
+
p ms.count_allocations
|
36
31
|
|
37
|
-
==
|
32
|
+
== Installation
|
38
33
|
|
39
34
|
gem install marshal-structure
|
40
35
|
|
41
|
-
==
|
36
|
+
== Developers
|
42
37
|
|
43
38
|
After checking out the source, run:
|
44
39
|
|
@@ -47,11 +42,11 @@ After checking out the source, run:
|
|
47
42
|
This task will install any missing dependencies, run the tests/specs,
|
48
43
|
and generate the RDoc.
|
49
44
|
|
50
|
-
==
|
45
|
+
== License
|
51
46
|
|
52
47
|
(The MIT License)
|
53
48
|
|
54
|
-
Copyright (c)
|
49
|
+
Copyright (c) Eric Hodel
|
55
50
|
|
56
51
|
Permission is hereby granted, free of charge, to any person obtaining
|
57
52
|
a copy of this software and associated documentation files (the
|
data/Rakefile
CHANGED
@@ -4,8 +4,8 @@ require 'rubygems'
|
|
4
4
|
require 'hoe'
|
5
5
|
|
6
6
|
Hoe.plugin :git
|
7
|
-
Hoe.plugin :isolate
|
8
7
|
Hoe.plugin :minitest
|
8
|
+
Hoe.plugin :travis
|
9
9
|
|
10
10
|
Hoe.spec 'marshal-structure' do
|
11
11
|
developer 'Eric Hodel', 'drbrain@segment7.net'
|
@@ -15,12 +15,6 @@ Hoe.spec 'marshal-structure' do
|
|
15
15
|
self.readme_file = 'README.rdoc'
|
16
16
|
self.extra_rdoc_files << 'README.rdoc' # HACK fix in Hoe
|
17
17
|
|
18
|
-
if respond_to? :isolate_dir= then # HACK Hoe issue #7
|
19
|
-
self.isolate_dir = 'tmp/isolate'
|
20
|
-
else
|
21
|
-
warn 'please: gem install isolate'
|
22
|
-
end
|
23
|
-
|
24
18
|
extra_dev_deps << ['ben_string', '~> 1']
|
25
19
|
end
|
26
20
|
|
data/lib/marshal/structure.rb
CHANGED
@@ -1,164 +1,73 @@
|
|
1
1
|
##
|
2
2
|
# Marshal::Structure dumps a nested Array describing the structure of a
|
3
|
-
# Marshal stream.
|
3
|
+
# Marshal stream. Marshal format 4.8 (Ruby 1.8 through 2.x) is supported.
|
4
4
|
#
|
5
|
-
#
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
##
|
25
|
-
# nil type prefix
|
26
|
-
|
27
|
-
TYPE_NIL = '0'
|
28
|
-
|
29
|
-
##
|
30
|
-
# true type prefix
|
31
|
-
|
32
|
-
TYPE_TRUE = 'T'
|
33
|
-
|
34
|
-
##
|
35
|
-
# false type prefix
|
36
|
-
|
37
|
-
TYPE_FALSE = 'F'
|
38
|
-
|
39
|
-
##
|
40
|
-
# Fixnum type prefix
|
41
|
-
|
42
|
-
TYPE_FIXNUM = 'i'
|
43
|
-
|
44
|
-
##
|
45
|
-
# An object that has been extended with a module
|
46
|
-
|
47
|
-
TYPE_EXTENDED = 'e'
|
48
|
-
|
49
|
-
##
|
50
|
-
# A subclass of a built-in type
|
51
|
-
|
52
|
-
TYPE_UCLASS = 'C'
|
53
|
-
|
54
|
-
##
|
55
|
-
# A ruby Object
|
56
|
-
|
57
|
-
TYPE_OBJECT = 'o'
|
58
|
-
|
59
|
-
##
|
60
|
-
# A wrapped C pointer
|
61
|
-
|
62
|
-
TYPE_DATA = 'd'
|
63
|
-
|
64
|
-
##
|
65
|
-
# An object saved with _dump
|
66
|
-
|
67
|
-
TYPE_USERDEF = 'u'
|
68
|
-
|
69
|
-
##
|
70
|
-
# An object saved with marshal_dump
|
71
|
-
|
72
|
-
TYPE_USRMARSHAL = 'U'
|
73
|
-
|
74
|
-
##
|
75
|
-
# A Float
|
76
|
-
|
77
|
-
TYPE_FLOAT = 'f'
|
78
|
-
|
79
|
-
##
|
80
|
-
# A Bignum
|
81
|
-
|
82
|
-
TYPE_BIGNUM = 'l'
|
83
|
-
|
84
|
-
##
|
85
|
-
# A String
|
86
|
-
|
87
|
-
TYPE_STRING = '"'
|
88
|
-
|
89
|
-
##
|
90
|
-
# A Regexp
|
91
|
-
|
92
|
-
TYPE_REGEXP = '/'
|
93
|
-
|
94
|
-
##
|
95
|
-
# An Array
|
96
|
-
|
97
|
-
TYPE_ARRAY = '['
|
98
|
-
|
99
|
-
##
|
100
|
-
# A Hash
|
101
|
-
|
102
|
-
TYPE_HASH = '{'
|
103
|
-
|
104
|
-
##
|
105
|
-
# A Hash with a default value (not proc)
|
106
|
-
|
107
|
-
TYPE_HASH_DEF = '}'
|
108
|
-
|
109
|
-
##
|
110
|
-
# A Struct
|
111
|
-
|
112
|
-
TYPE_STRUCT = 'S'
|
5
|
+
# Examples:
|
6
|
+
#
|
7
|
+
# To dump the structure of a Marshal stream:
|
8
|
+
#
|
9
|
+
# ruby -rpp -rmarshal/structure \
|
10
|
+
# -e 'pp Marshal::Structure.load Marshal.dump "hello"'
|
11
|
+
#
|
12
|
+
# Fancier usage:
|
13
|
+
#
|
14
|
+
# require 'pp'
|
15
|
+
# require 'marshal/structure'
|
16
|
+
#
|
17
|
+
# ms = Marshal::Structure.new Marshal.dump %w[hello world]
|
18
|
+
#
|
19
|
+
# # print the stream structure
|
20
|
+
# pp ms.structure
|
21
|
+
#
|
22
|
+
# # show how many allocations are required to load the stream
|
23
|
+
# p ms.count_allocations
|
113
24
|
|
114
|
-
##
|
115
|
-
# An old-style Module (reference, not content)
|
116
|
-
#
|
117
|
-
# I'm not sure what makes this old. The byte stream is identical to
|
118
|
-
# TYPE_MODULE
|
119
25
|
|
120
|
-
|
26
|
+
class Marshal::Structure
|
121
27
|
|
122
28
|
##
|
123
|
-
#
|
29
|
+
# Generic error class for Marshal::Structure
|
124
30
|
|
125
|
-
|
31
|
+
class Error < RuntimeError
|
32
|
+
end
|
126
33
|
|
127
34
|
##
|
128
|
-
#
|
129
|
-
|
130
|
-
TYPE_MODULE = 'm'
|
35
|
+
# Raised when the Marshal stream is at the end
|
131
36
|
|
132
|
-
|
133
|
-
# A Symbol
|
37
|
+
class EndOfMarshal < Error
|
134
38
|
|
135
|
-
|
39
|
+
##
|
40
|
+
# Number of bytes of Marshal stream consumed
|
136
41
|
|
137
|
-
|
138
|
-
# A reference to a previously Symbol
|
42
|
+
attr_reader :consumed
|
139
43
|
|
140
|
-
|
44
|
+
##
|
45
|
+
# Requested number of bytes that was not fulfillable
|
141
46
|
|
142
|
-
|
143
|
-
# Instance variables for a following object
|
47
|
+
attr_reader :requested
|
144
48
|
|
145
|
-
|
49
|
+
##
|
50
|
+
# Creates a new EndOfMarshal exception. Marshal::Structure previously
|
51
|
+
# read +consumed+ bytes and was unable to fulfill the request for
|
52
|
+
# +requested+ additional bytes.
|
146
53
|
|
147
|
-
|
148
|
-
|
54
|
+
def initialize consumed, requested
|
55
|
+
@consumed = consumed
|
56
|
+
@requested = requested
|
149
57
|
|
150
|
-
|
58
|
+
super "consumed #{consumed} bytes, requested #{requested} more"
|
59
|
+
end
|
60
|
+
end
|
151
61
|
|
152
62
|
##
|
153
|
-
#
|
154
|
-
# actual object won't be present in this list.
|
63
|
+
# Version of Marshal::Structure you are using
|
155
64
|
|
156
|
-
|
65
|
+
VERSION = '2.0'
|
157
66
|
|
158
67
|
##
|
159
|
-
#
|
68
|
+
# The Marshal stream
|
160
69
|
|
161
|
-
attr_reader :
|
70
|
+
attr_reader :stream
|
162
71
|
|
163
72
|
##
|
164
73
|
# Returns the structure of the Marshaled object +obj+ as nested Arrays.
|
@@ -178,24 +87,18 @@ class Marshal::Structure
|
|
178
87
|
data = obj.to_s
|
179
88
|
elsif obj.respond_to? :read then
|
180
89
|
data = obj.read
|
181
|
-
if data.empty?
|
182
|
-
raise EOFError, "end of file reached"
|
183
|
-
end
|
90
|
+
raise EOFError, "end of file reached" if data.empty?
|
184
91
|
elsif obj.respond_to? :getc then # FIXME - don't read all of it upfront
|
185
92
|
data = ''
|
186
|
-
|
93
|
+
|
94
|
+
while c = obj.getc do
|
95
|
+
data << c.chr
|
96
|
+
end
|
187
97
|
else
|
188
98
|
raise TypeError, "instance of IO needed"
|
189
99
|
end
|
190
100
|
|
191
|
-
|
192
|
-
minor = data[1].ord
|
193
|
-
|
194
|
-
if major != MAJOR_VERSION or minor > MINOR_VERSION then
|
195
|
-
raise TypeError, "incompatible marshal file format (can't be read)\n\tformat version #{MAJOR_VERSION}.#{MINOR_VERSION} required; #{major}.#{minor} given"
|
196
|
-
end
|
197
|
-
|
198
|
-
new(data).construct
|
101
|
+
new(data).structure
|
199
102
|
end
|
200
103
|
|
201
104
|
##
|
@@ -220,418 +123,47 @@ class Marshal::Structure
|
|
220
123
|
# Prepares processing of +stream+
|
221
124
|
|
222
125
|
def initialize stream
|
223
|
-
@
|
224
|
-
@
|
225
|
-
|
226
|
-
@stream = stream
|
227
|
-
@byte_array = stream.bytes.to_a
|
228
|
-
@consumed = 2
|
229
|
-
end
|
230
|
-
|
231
|
-
##
|
232
|
-
# Adds +obj+ to the objects list
|
233
|
-
|
234
|
-
def add_object obj
|
235
|
-
return if
|
236
|
-
[NilClass, TrueClass, FalseClass, Symbol, Fixnum].any? { |c| c === obj }
|
237
|
-
|
238
|
-
index = @objects.size
|
239
|
-
@objects << obj
|
240
|
-
index
|
126
|
+
@stream = stream
|
127
|
+
@tokenizer = Marshal::Structure::Tokenizer.new stream
|
241
128
|
end
|
242
129
|
|
243
130
|
##
|
244
|
-
#
|
131
|
+
# Counts allocations required to load the Marshal stream. See
|
132
|
+
# Marshal::Structure::AllocationsCounter for a description of how counting
|
133
|
+
# is performed.
|
245
134
|
|
246
|
-
def
|
247
|
-
|
248
|
-
@symbols << symbol
|
249
|
-
index
|
250
|
-
end
|
135
|
+
def count_allocations
|
136
|
+
counter = Marshal::Structure::AllocationCounter.new token_stream
|
251
137
|
|
252
|
-
|
253
|
-
# Creates the structure for the remaining stream.
|
254
|
-
|
255
|
-
def construct
|
256
|
-
type = consume_character
|
257
|
-
|
258
|
-
case type
|
259
|
-
when TYPE_NIL then
|
260
|
-
:nil
|
261
|
-
when TYPE_TRUE then
|
262
|
-
:true
|
263
|
-
when TYPE_FALSE then
|
264
|
-
:false
|
265
|
-
|
266
|
-
when TYPE_ARRAY then
|
267
|
-
[:array, *construct_array]
|
268
|
-
when TYPE_BIGNUM then
|
269
|
-
[:bignum, *construct_bignum]
|
270
|
-
when TYPE_CLASS then
|
271
|
-
ref = store_unique_object Object.allocate
|
272
|
-
|
273
|
-
[:class, ref, get_byte_sequence]
|
274
|
-
when TYPE_DATA then
|
275
|
-
[:data, *construct_data]
|
276
|
-
when TYPE_EXTENDED then
|
277
|
-
[:extended, get_symbol, construct]
|
278
|
-
when TYPE_FIXNUM then
|
279
|
-
[:fixnum, construct_integer]
|
280
|
-
when TYPE_FLOAT then
|
281
|
-
[:float, *construct_float]
|
282
|
-
when TYPE_HASH then
|
283
|
-
[:hash, *construct_hash]
|
284
|
-
when TYPE_HASH_DEF then
|
285
|
-
[:hash_default, *construct_hash_def]
|
286
|
-
when TYPE_IVAR then
|
287
|
-
[:instance_variables, construct, *construct_instance_variables]
|
288
|
-
when TYPE_LINK then
|
289
|
-
[:link, construct_integer]
|
290
|
-
when TYPE_MODULE, TYPE_MODULE_OLD then
|
291
|
-
ref = store_unique_object Object.allocate
|
292
|
-
|
293
|
-
[:module, ref, get_byte_sequence]
|
294
|
-
when TYPE_OBJECT then
|
295
|
-
[:object, *construct_object]
|
296
|
-
when TYPE_REGEXP then
|
297
|
-
[:regexp, *construct_regexp]
|
298
|
-
when TYPE_STRING then
|
299
|
-
[:string, *construct_string]
|
300
|
-
when TYPE_STRUCT then
|
301
|
-
[:struct, *construct_struct]
|
302
|
-
when TYPE_SYMBOL then
|
303
|
-
[:symbol, *construct_symbol]
|
304
|
-
when TYPE_SYMLINK then
|
305
|
-
[:symbol_link, construct_integer]
|
306
|
-
when TYPE_USERDEF then
|
307
|
-
[:user_defined, *construct_user_defined]
|
308
|
-
when TYPE_USRMARSHAL then
|
309
|
-
[:user_marshal, *construct_user_marshal]
|
310
|
-
when TYPE_UCLASS then
|
311
|
-
name = get_symbol
|
312
|
-
|
313
|
-
[:user_class, name, construct]
|
314
|
-
else
|
315
|
-
raise ArgumentError, "load error, unknown type #{type}"
|
316
|
-
end
|
138
|
+
counter.count
|
317
139
|
end
|
318
140
|
|
319
141
|
##
|
320
|
-
#
|
321
|
-
|
322
|
-
def construct_array
|
323
|
-
ref = store_unique_object Object.allocate
|
324
|
-
|
325
|
-
obj = [ref]
|
326
|
-
|
327
|
-
items = construct_integer
|
328
|
-
|
329
|
-
obj << items
|
330
|
-
|
331
|
-
items.times do
|
332
|
-
obj << construct
|
333
|
-
end
|
142
|
+
# Loads the stream with Marshal.load
|
334
143
|
|
335
|
-
|
144
|
+
def load
|
145
|
+
Marshal.load @stream
|
336
146
|
end
|
337
147
|
|
338
148
|
##
|
339
|
-
#
|
149
|
+
# Returns the structure of the Marshal stream.
|
340
150
|
|
341
|
-
def
|
342
|
-
|
343
|
-
size = construct_integer * 2
|
151
|
+
def structure
|
152
|
+
parser = Marshal::Structure::Parser.new token_stream
|
344
153
|
|
345
|
-
|
346
|
-
|
347
|
-
data = consume_bytes size
|
348
|
-
|
349
|
-
data.each_with_index do |data, exp|
|
350
|
-
result += (data * 2**(exp*8))
|
351
|
-
end
|
352
|
-
|
353
|
-
ref = store_unique_object Object.allocate
|
354
|
-
|
355
|
-
[ref, sign, size, result]
|
154
|
+
parser.parse
|
356
155
|
end
|
357
156
|
|
358
157
|
##
|
359
|
-
#
|
360
|
-
|
361
|
-
def construct_data
|
362
|
-
ref = store_unique_object Object.allocate
|
158
|
+
# Returns an Enumerator for the tokens in the Marshal stream.
|
363
159
|
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
##
|
368
|
-
# Creates the body of a +:float+ object
|
369
|
-
|
370
|
-
def construct_float
|
371
|
-
float = get_byte_sequence
|
372
|
-
|
373
|
-
ref = store_unique_object Object.allocate
|
374
|
-
|
375
|
-
[ref, float]
|
376
|
-
end
|
377
|
-
|
378
|
-
##
|
379
|
-
# Creates the body of a +:hash+ object
|
380
|
-
|
381
|
-
def construct_hash
|
382
|
-
ref = store_unique_object Object.allocate
|
383
|
-
|
384
|
-
obj = [ref]
|
385
|
-
|
386
|
-
pairs = construct_integer
|
387
|
-
obj << pairs
|
388
|
-
|
389
|
-
pairs.times do
|
390
|
-
obj << construct
|
391
|
-
obj << construct
|
392
|
-
end
|
393
|
-
|
394
|
-
obj
|
395
|
-
end
|
396
|
-
|
397
|
-
##
|
398
|
-
# Creates the body of a +:hash_def+ object
|
399
|
-
|
400
|
-
def construct_hash_def
|
401
|
-
ref, hash = construct_hash
|
402
|
-
|
403
|
-
[ref, hash, construct]
|
404
|
-
end
|
405
|
-
|
406
|
-
##
|
407
|
-
# Instance variables contain an object followed by a count of instance
|
408
|
-
# variables and their contents
|
409
|
-
|
410
|
-
def construct_instance_variables
|
411
|
-
instance_variables = []
|
412
|
-
|
413
|
-
pairs = construct_integer
|
414
|
-
instance_variables << pairs
|
415
|
-
|
416
|
-
pairs.times do
|
417
|
-
instance_variables << get_symbol
|
418
|
-
instance_variables << construct
|
419
|
-
end
|
420
|
-
|
421
|
-
instance_variables
|
422
|
-
end
|
423
|
-
|
424
|
-
##
|
425
|
-
# Decodes a stored Fixnum
|
426
|
-
|
427
|
-
def construct_integer
|
428
|
-
c = consume_byte
|
429
|
-
|
430
|
-
# The format appears to be a simple integer compression format
|
431
|
-
#
|
432
|
-
# The 0-123 cases are easy, and use one byte
|
433
|
-
# We've read c as unsigned char in a way, but we need to honor
|
434
|
-
# the sign bit. We do that by simply comparing with the +128 values
|
435
|
-
return 0 if c == 0
|
436
|
-
return c - 5 if 4 < c and c < 128
|
437
|
-
|
438
|
-
# negative, but checked known it's instead in 2's compliment
|
439
|
-
return c - 251 if 252 > c and c > 127
|
440
|
-
|
441
|
-
# otherwise c (now in the 1 to 4 range) indicates how many
|
442
|
-
# bytes to read to construct the value.
|
443
|
-
#
|
444
|
-
# Because we're operating on a small number of possible values,
|
445
|
-
# it's cleaner to just unroll the calculate of each
|
446
|
-
|
447
|
-
case c
|
448
|
-
when 1
|
449
|
-
consume_byte
|
450
|
-
when 2
|
451
|
-
consume_byte | (consume_byte << 8)
|
452
|
-
when 3
|
453
|
-
consume_byte | (consume_byte << 8) | (consume_byte << 16)
|
454
|
-
when 4
|
455
|
-
consume_byte | (consume_byte << 8) | (consume_byte << 16) |
|
456
|
-
(consume_byte << 24)
|
457
|
-
|
458
|
-
when 255 # -1
|
459
|
-
consume_byte - 256
|
460
|
-
when 254 # -2
|
461
|
-
(consume_byte | (consume_byte << 8)) - 65536
|
462
|
-
when 253 # -3
|
463
|
-
(consume_byte |
|
464
|
-
(consume_byte << 8) |
|
465
|
-
(consume_byte << 16)) - 16777216 # 2 ** 24
|
466
|
-
when 252 # -4
|
467
|
-
(consume_byte |
|
468
|
-
(consume_byte << 8) |
|
469
|
-
(consume_byte << 16) |
|
470
|
-
(consume_byte << 24)) - 4294967296
|
471
|
-
else
|
472
|
-
raise "Invalid integer size: #{c}"
|
473
|
-
end
|
474
|
-
end
|
475
|
-
|
476
|
-
##
|
477
|
-
# Creates an Object
|
478
|
-
|
479
|
-
def construct_object
|
480
|
-
ref = store_unique_object Object.allocate
|
481
|
-
|
482
|
-
[ref, get_symbol, construct_instance_variables]
|
483
|
-
end
|
484
|
-
|
485
|
-
##
|
486
|
-
# Creates a Regexp
|
487
|
-
|
488
|
-
def construct_regexp
|
489
|
-
ref =store_unique_object Object.allocate
|
490
|
-
|
491
|
-
[ref, get_byte_sequence, consume_byte]
|
492
|
-
end
|
493
|
-
|
494
|
-
##
|
495
|
-
# Creates a String
|
496
|
-
|
497
|
-
def construct_string
|
498
|
-
ref = store_unique_object Object.allocate
|
499
|
-
|
500
|
-
[ref, get_byte_sequence]
|
501
|
-
end
|
502
|
-
|
503
|
-
##
|
504
|
-
# Creates a Struct
|
505
|
-
|
506
|
-
def construct_struct
|
507
|
-
symbols = []
|
508
|
-
values = []
|
509
|
-
|
510
|
-
obj_ref = store_unique_object Object.allocate
|
511
|
-
|
512
|
-
obj = [obj_ref, get_symbol]
|
513
|
-
|
514
|
-
members = construct_integer
|
515
|
-
obj << members
|
516
|
-
|
517
|
-
members.times do
|
518
|
-
obj << get_symbol
|
519
|
-
obj << construct
|
520
|
-
end
|
521
|
-
|
522
|
-
obj
|
523
|
-
end
|
524
|
-
|
525
|
-
##
|
526
|
-
# Creates a Symbol
|
527
|
-
|
528
|
-
def construct_symbol
|
529
|
-
sym = get_byte_sequence
|
530
|
-
|
531
|
-
ref = store_unique_object sym.to_sym
|
532
|
-
|
533
|
-
[ref, sym]
|
534
|
-
end
|
535
|
-
|
536
|
-
##
|
537
|
-
# Creates an object saved by _dump
|
538
|
-
|
539
|
-
def construct_user_defined
|
540
|
-
name = get_symbol
|
541
|
-
|
542
|
-
data = get_byte_sequence
|
543
|
-
|
544
|
-
ref = store_unique_object Object.allocate
|
545
|
-
|
546
|
-
[ref, name, data]
|
547
|
-
end
|
548
|
-
|
549
|
-
##
|
550
|
-
# Creates an object saved by marshal_dump
|
551
|
-
|
552
|
-
def construct_user_marshal
|
553
|
-
name = get_symbol
|
554
|
-
|
555
|
-
obj = Object.allocate
|
556
|
-
|
557
|
-
obj_ref = store_unique_object obj
|
558
|
-
|
559
|
-
[obj_ref, name, construct]
|
560
|
-
end
|
561
|
-
|
562
|
-
##
|
563
|
-
# Consumes +bytes+ from the marshal stream
|
564
|
-
|
565
|
-
def consume bytes
|
566
|
-
raise ArgumentError, "marshal data too short" if @consumed > @stream.size
|
567
|
-
data = @stream[@consumed, bytes]
|
568
|
-
@consumed += bytes
|
569
|
-
data
|
570
|
-
end
|
571
|
-
|
572
|
-
##
|
573
|
-
# Consumes +count+ bytes from the marshal stream as an Array of bytes
|
574
|
-
|
575
|
-
def consume_bytes count
|
576
|
-
consume(count).bytes.to_a
|
577
|
-
end
|
578
|
-
|
579
|
-
##
|
580
|
-
# Consumes one byte from the marshal stream
|
581
|
-
|
582
|
-
def consume_byte
|
583
|
-
raise ArgumentError, "marshal data too short" if
|
584
|
-
@consumed > @byte_array.size
|
585
|
-
|
586
|
-
data = @byte_array[@consumed]
|
587
|
-
@consumed += 1
|
588
|
-
|
589
|
-
data
|
590
|
-
end
|
591
|
-
|
592
|
-
##
|
593
|
-
# Consumes one byte from the marshal stream and returns a character
|
594
|
-
|
595
|
-
def consume_character
|
596
|
-
consume_byte.chr
|
597
|
-
end
|
598
|
-
|
599
|
-
##
|
600
|
-
# Consumes a sequence of bytes from the marshal stream based on the next
|
601
|
-
# integer
|
602
|
-
|
603
|
-
def get_byte_sequence
|
604
|
-
size = construct_integer
|
605
|
-
consume size
|
606
|
-
end
|
607
|
-
|
608
|
-
##
|
609
|
-
# Constructs a Symbol from a TYPE_SYMBOL or TYPE_SYMLINK
|
610
|
-
|
611
|
-
def get_symbol
|
612
|
-
type = consume_character
|
613
|
-
|
614
|
-
case type
|
615
|
-
when TYPE_SYMBOL then
|
616
|
-
[:symbol, *construct_symbol]
|
617
|
-
when TYPE_SYMLINK then
|
618
|
-
num = construct_integer
|
619
|
-
[:symbol_link, num]
|
620
|
-
else
|
621
|
-
raise ArgumentError, "expected TYPE_SYMBOL or TYPE_SYMLINK, got #{type.inspect}"
|
622
|
-
end
|
623
|
-
end
|
624
|
-
|
625
|
-
##
|
626
|
-
# Stores a reference to +obj+
|
627
|
-
|
628
|
-
def store_unique_object obj
|
629
|
-
if Symbol === obj then
|
630
|
-
add_symlink obj
|
631
|
-
else
|
632
|
-
add_object obj
|
633
|
-
end
|
160
|
+
def token_stream
|
161
|
+
@tokenizer.tokens
|
634
162
|
end
|
635
163
|
|
636
164
|
end
|
637
165
|
|
166
|
+
require 'marshal/structure/allocation_counter'
|
167
|
+
require 'marshal/structure/parser'
|
168
|
+
require 'marshal/structure/tokenizer'
|
169
|
+
|