mrpin-amf 2.1.8
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
- data/.gitignore +9 -0
- data/README.rdoc +52 -0
- data/Rakefile +59 -0
- data/benchmark.rb +86 -0
- data/doc/amf3-speification.pdf +0 -0
- data/ext/rocketamf_ext/class_mapping.c +483 -0
- data/ext/rocketamf_ext/constants.h +52 -0
- data/ext/rocketamf_ext/deserializer.c +776 -0
- data/ext/rocketamf_ext/deserializer.h +28 -0
- data/ext/rocketamf_ext/extconf.rb +18 -0
- data/ext/rocketamf_ext/remoting.c +184 -0
- data/ext/rocketamf_ext/rocketamf_ext.c +38 -0
- data/ext/rocketamf_ext/serializer.c +834 -0
- data/ext/rocketamf_ext/serializer.h +29 -0
- data/ext/rocketamf_ext/utility.h +4 -0
- data/lib/amf/common/hash_with_type.rb +20 -0
- data/lib/amf/ext.rb +22 -0
- data/lib/amf/pure/amf_constants.rb +42 -0
- data/lib/amf/pure/deserializer.rb +354 -0
- data/lib/amf/pure/errors/all_files.rb +2 -0
- data/lib/amf/pure/errors/amf_error.rb +5 -0
- data/lib/amf/pure/errors/amf_error_incomplete.rb +5 -0
- data/lib/amf/pure/helpers/all_files.rb +8 -0
- data/lib/amf/pure/helpers/cache_objects.rb +18 -0
- data/lib/amf/pure/helpers/cache_strings.rb +14 -0
- data/lib/amf/pure/helpers/io_helper_base.rb +19 -0
- data/lib/amf/pure/helpers/io_helper_read.rb +67 -0
- data/lib/amf/pure/helpers/io_helper_write.rb +49 -0
- data/lib/amf/pure/mapping/class_mapper.rb +159 -0
- data/lib/amf/pure/mapping/mapping_set.rb +49 -0
- data/lib/amf/pure/serializer.rb +318 -0
- data/lib/amf/pure.rb +16 -0
- data/lib/amf.rb +140 -0
- data/mrpin-amf.gemspec +24 -0
- data/spec/fixtures/objects/complex/amf3-associative-array.bin +1 -0
- data/spec/fixtures/objects/complex/amf3-byte-array.bin +0 -0
- data/spec/fixtures/objects/complex/amf3-date.bin +0 -0
- data/spec/fixtures/objects/complex/amf3-dictionary.bin +0 -0
- data/spec/fixtures/objects/complex/amf3-dynamic-object.bin +2 -0
- data/spec/fixtures/objects/complex/amf3-empty-array.bin +1 -0
- data/spec/fixtures/objects/complex/amf3-empty-dictionary.bin +0 -0
- data/spec/fixtures/objects/complex/amf3-hash.bin +2 -0
- data/spec/fixtures/objects/complex/amf3-mixed-array.bin +10 -0
- data/spec/fixtures/objects/complex/amf3-primitive-array.bin +1 -0
- data/spec/fixtures/objects/complex/amf3-typed-object.bin +2 -0
- data/spec/fixtures/objects/encoding/amf3-complex-encoded-string-array.bin +1 -0
- data/spec/fixtures/objects/encoding/amf3-encoded-string-ref.bin +0 -0
- data/spec/fixtures/objects/references/amf3-array-ref.bin +1 -0
- data/spec/fixtures/objects/references/amf3-byte-array-ref.bin +1 -0
- data/spec/fixtures/objects/references/amf3-date-ref.bin +0 -0
- data/spec/fixtures/objects/references/amf3-empty-array-ref.bin +1 -0
- data/spec/fixtures/objects/references/amf3-empty-string-ref.bin +1 -0
- data/spec/fixtures/objects/references/amf3-graph-member.bin +0 -0
- data/spec/fixtures/objects/references/amf3-object-ref.bin +0 -0
- data/spec/fixtures/objects/references/amf3-string-ref.bin +0 -0
- data/spec/fixtures/objects/references/amf3-trait-ref.bin +3 -0
- data/spec/fixtures/objects/simple/amf3-0.bin +0 -0
- data/spec/fixtures/objects/simple/amf3-bigNum.bin +0 -0
- data/spec/fixtures/objects/simple/amf3-false.bin +1 -0
- data/spec/fixtures/objects/simple/amf3-float.bin +0 -0
- data/spec/fixtures/objects/simple/amf3-large-max.bin +0 -0
- data/spec/fixtures/objects/simple/amf3-large-min.bin +0 -0
- data/spec/fixtures/objects/simple/amf3-max.bin +1 -0
- data/spec/fixtures/objects/simple/amf3-min.bin +0 -0
- data/spec/fixtures/objects/simple/amf3-null.bin +1 -0
- data/spec/fixtures/objects/simple/amf3-string.bin +1 -0
- data/spec/fixtures/objects/simple/amf3-symbol.bin +1 -0
- data/spec/fixtures/objects/simple/amf3-true.bin +1 -0
- data/spec/helpers/class_mapping_test.rb +4 -0
- data/spec/helpers/class_mapping_test2.rb +3 -0
- data/spec/helpers/fixtures.rb +34 -0
- data/spec/helpers/other_class.rb +4 -0
- data/spec/helpers/ruby_class.rb +4 -0
- data/spec/helpers/test_ruby_class.rb +4 -0
- data/spec/spec-class_mapping.rb +98 -0
- data/spec/spec_deserializer.rb +239 -0
- data/spec/spec_fast_class_mapping.rb +147 -0
- data/spec/spec_helper.rb +8 -0
- data/spec/spec_serializer.rb +267 -0
- metadata +146 -0
@@ -0,0 +1,29 @@
|
|
1
|
+
#include <ruby.h>
|
2
|
+
#ifdef HAVE_RB_STR_ENCODE
|
3
|
+
#include <ruby/st.h>
|
4
|
+
#include <ruby/encoding.h>
|
5
|
+
#else
|
6
|
+
#include <st.h>
|
7
|
+
#endif
|
8
|
+
|
9
|
+
typedef struct {
|
10
|
+
int version;
|
11
|
+
VALUE class_mapper;
|
12
|
+
VALUE stream;
|
13
|
+
long depth;
|
14
|
+
st_table* str_cache;
|
15
|
+
long str_index;
|
16
|
+
st_table* trait_cache;
|
17
|
+
long trait_index;
|
18
|
+
st_table* obj_cache;
|
19
|
+
long obj_index;
|
20
|
+
} AMF_SERIALIZER;
|
21
|
+
|
22
|
+
void ser_write_byte(AMF_SERIALIZER *ser, char byte);
|
23
|
+
void ser_write_int(AMF_SERIALIZER *ser, int num);
|
24
|
+
void ser_write_uint16(AMF_SERIALIZER *ser, long num);
|
25
|
+
void ser_write_uint32(AMF_SERIALIZER *ser, long num);
|
26
|
+
void ser_write_double(AMF_SERIALIZER *ser, double num);
|
27
|
+
void ser_get_string(VALUE obj, VALUE encode, char** str, long* len);
|
28
|
+
|
29
|
+
VALUE ser_serialize(VALUE self, VALUE ver, VALUE obj);
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module AMF
|
2
|
+
# Hash-like object that can store a type string. Used to preserve type information
|
3
|
+
# for unmapped objects after deserialization.
|
4
|
+
class HashWithType < Hash
|
5
|
+
|
6
|
+
#
|
7
|
+
# Properties
|
8
|
+
#
|
9
|
+
|
10
|
+
attr_reader :class_type
|
11
|
+
|
12
|
+
#
|
13
|
+
# Methods
|
14
|
+
#
|
15
|
+
|
16
|
+
def initialize(type)
|
17
|
+
@class_type = type
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
data/lib/amf/ext.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
begin
|
2
|
+
# Fat binaries for Windows
|
3
|
+
RUBY_VERSION =~ /(\d+.\d+)/
|
4
|
+
require "#{$1}/rocketamf_ext"
|
5
|
+
rescue LoadError
|
6
|
+
require 'rocketamf_ext'
|
7
|
+
end
|
8
|
+
|
9
|
+
module AMF
|
10
|
+
# This module holds all the modules/classes that implement AMF's functionality
|
11
|
+
# in C
|
12
|
+
module Ext
|
13
|
+
$DEBUG and warn 'Using C library for AMF.'
|
14
|
+
end
|
15
|
+
|
16
|
+
#:stopdoc:
|
17
|
+
# Import serializer/deserializer
|
18
|
+
Deserializer = AMF::Ext::Deserializer
|
19
|
+
Serializer = AMF::Ext::Serializer
|
20
|
+
|
21
|
+
#:startdoc:
|
22
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module AMF
|
2
|
+
module AMFConstants
|
3
|
+
# AMF3 Type Markers
|
4
|
+
AMF3_MARKER_UNDEFINED = 0x00 #"\000"
|
5
|
+
AMF3_MARKER_NULL = 0x01 #"\001"
|
6
|
+
|
7
|
+
AMF3_MARKER_FALSE = 0x02 #"\002"
|
8
|
+
AMF3_MARKER_TRUE = 0x03 #"\003"
|
9
|
+
|
10
|
+
AMF3_MARKER_INTEGER = 0x04 #"\004"
|
11
|
+
AMF3_MARKER_DOUBLE = 0x05 #"\005"
|
12
|
+
AMF3_MARKER_STRING = 0x06 #"\006"
|
13
|
+
AMF3_MARKER_XML_DOC = 0x07 #"\a" not supported
|
14
|
+
AMF3_MARKER_DATE = 0x08 #"\b"
|
15
|
+
AMF3_MARKER_ARRAY = 0x09 #"\t"
|
16
|
+
AMF3_MARKER_OBJECT = 0x0A #"\n"
|
17
|
+
AMF3_MARKER_XML = 0x0B #"\v" not supported
|
18
|
+
AMF3_MARKER_BYTE_ARRAY = 0x0C #"\f"
|
19
|
+
|
20
|
+
AMF3_MARKER_VECTOR_INT = 0x0D #"\r" not supported
|
21
|
+
AMF3_MARKER_VECTOR_UINT = 0x0E #"\016" not supported
|
22
|
+
AMF3_MARKER_VECTOR_DOUBLE = 0x0F #"\017" not supported
|
23
|
+
AMF3_MARKER_VECTOR_OBJECT = 0x10 #"\020" not supported
|
24
|
+
|
25
|
+
AMF3_MARKER_DICTIONARY = 0x11 #"\021"
|
26
|
+
|
27
|
+
# Other AMF3 Markers
|
28
|
+
AMF3_EMPTY_STRING = 0x01
|
29
|
+
|
30
|
+
AMF3_CLOSE_DYNAMIC_OBJECT = 0x01
|
31
|
+
AMF3_CLOSE_DYNAMIC_ARRAY = 0x01
|
32
|
+
|
33
|
+
# The minimum value for an integer that will avoid promotion to an ActionScript's Number type.
|
34
|
+
INTEGER_MIN = -268_435_456
|
35
|
+
# The maximum value for an integer that will avoid promotion to an ActionScript's Number type.
|
36
|
+
INTEGER_MAX = 268_435_455
|
37
|
+
|
38
|
+
MIN_INT_2_BYTE = 0x80
|
39
|
+
MIN_INT_3_BYTE = 0x4000
|
40
|
+
MIN_INT_4_BYTE = 0x200000
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,354 @@
|
|
1
|
+
module AMF
|
2
|
+
module Pure
|
3
|
+
# Pure ruby deserializer for AMF3 requests
|
4
|
+
class Deserializer
|
5
|
+
|
6
|
+
#
|
7
|
+
# Modules
|
8
|
+
#
|
9
|
+
private
|
10
|
+
include AMF::Pure::IOHelperRead
|
11
|
+
include AMF::AMFConstants
|
12
|
+
|
13
|
+
#
|
14
|
+
# Properties
|
15
|
+
#
|
16
|
+
|
17
|
+
# Used for read_object
|
18
|
+
public
|
19
|
+
attr_reader :source
|
20
|
+
|
21
|
+
# Pass in the class mapper instance to use when deserializing. This
|
22
|
+
# enables better caching behavior in the class mapper and allows
|
23
|
+
# one to change mappings between deserialization attempts.
|
24
|
+
public
|
25
|
+
def initialize(class_mapper)
|
26
|
+
@class_mapper = class_mapper
|
27
|
+
end
|
28
|
+
|
29
|
+
# Deserialize the source using AMF3. Source should either
|
30
|
+
# be a string or StringIO object. If you pass a StringIO object,
|
31
|
+
# it will have its position updated to the end of the deserialized
|
32
|
+
# data.
|
33
|
+
# raise AMFError if error appeared in deserialize, source is nil
|
34
|
+
# raise AMFErrorIncomplete if source is incomplete
|
35
|
+
# return hash {objects: [], incomplete_objects: String}
|
36
|
+
public
|
37
|
+
def deserialize(source)
|
38
|
+
raise AMFError, 'no source to deserialize' if source.nil?
|
39
|
+
|
40
|
+
@source = source.is_a?(StringIO) ? source : StringIO.new(source)
|
41
|
+
|
42
|
+
objects = []
|
43
|
+
|
44
|
+
incomplete_objects = nil
|
45
|
+
|
46
|
+
until @source.eof?
|
47
|
+
|
48
|
+
@cache_strings = []
|
49
|
+
@cache_objects = []
|
50
|
+
@cache_traits = []
|
51
|
+
|
52
|
+
source_position = @source.pos
|
53
|
+
|
54
|
+
begin
|
55
|
+
objects << amf3_deserialize
|
56
|
+
rescue AMFErrorIncomplete, AMFError => e
|
57
|
+
|
58
|
+
@source.pos = source_position
|
59
|
+
|
60
|
+
incomplete_objects = @source.read
|
61
|
+
|
62
|
+
break
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
{
|
67
|
+
objects: objects,
|
68
|
+
incomplete_objects: incomplete_objects
|
69
|
+
}
|
70
|
+
end
|
71
|
+
|
72
|
+
# Reads an object from the deserializer stream and returns it.
|
73
|
+
public
|
74
|
+
def read_object
|
75
|
+
amf3_deserialize
|
76
|
+
end
|
77
|
+
|
78
|
+
private
|
79
|
+
def amf3_deserialize
|
80
|
+
type = read_int8(@source)
|
81
|
+
|
82
|
+
case type
|
83
|
+
when AMF3_MARKER_UNDEFINED
|
84
|
+
nil
|
85
|
+
when AMF3_MARKER_NULL
|
86
|
+
nil
|
87
|
+
when AMF3_MARKER_FALSE
|
88
|
+
false
|
89
|
+
when AMF3_MARKER_TRUE
|
90
|
+
true
|
91
|
+
when AMF3_MARKER_INTEGER
|
92
|
+
amf3_read_integer
|
93
|
+
when AMF3_MARKER_DOUBLE
|
94
|
+
amf3_read_number
|
95
|
+
when AMF3_MARKER_STRING
|
96
|
+
amf3_read_string
|
97
|
+
when AMF3_MARKER_DATE
|
98
|
+
amf3_read_date
|
99
|
+
when AMF3_MARKER_ARRAY
|
100
|
+
amf3_read_array
|
101
|
+
when AMF3_MARKER_OBJECT
|
102
|
+
amf3_read_object
|
103
|
+
when AMF3_MARKER_BYTE_ARRAY
|
104
|
+
amf3_read_byte_array
|
105
|
+
when AMF3_MARKER_VECTOR_INT, AMF3_MARKER_VECTOR_UINT, AMF3_MARKER_VECTOR_DOUBLE, AMF3_MARKER_VECTOR_OBJECT, AMF3_MARKER_XML_DOC, AMF3_MARKER_XML
|
106
|
+
raise AMFError, "Unsupported type: #{type}"
|
107
|
+
when AMF3_MARKER_DICTIONARY
|
108
|
+
amf3_read_dictionary
|
109
|
+
else
|
110
|
+
raise AMFError, "Invalid type: #{type}"
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
private
|
115
|
+
def get_as_reference_object(type)
|
116
|
+
result = nil
|
117
|
+
|
118
|
+
if (type & 0x01) == 0 #is reference?
|
119
|
+
reference = type >> 1
|
120
|
+
result = @cache_objects[reference]
|
121
|
+
end
|
122
|
+
|
123
|
+
result
|
124
|
+
end
|
125
|
+
|
126
|
+
private
|
127
|
+
def get_as_reference_string(type)
|
128
|
+
result = nil
|
129
|
+
|
130
|
+
if (type & 0x01) == 0 #is reference?
|
131
|
+
reference = type >> 1
|
132
|
+
result = @cache_strings[reference]
|
133
|
+
end
|
134
|
+
|
135
|
+
result
|
136
|
+
end
|
137
|
+
|
138
|
+
private
|
139
|
+
def amf3_read_integer
|
140
|
+
result = 0
|
141
|
+
|
142
|
+
n = 0
|
143
|
+
b = read_word8(@source) || 0
|
144
|
+
|
145
|
+
while (b & 0x80) != 0 && n < 3
|
146
|
+
result = result << 7
|
147
|
+
result = result | (b & 0x7f)
|
148
|
+
b = read_word8(@source) || 0
|
149
|
+
n = n + 1
|
150
|
+
end
|
151
|
+
|
152
|
+
if n < 3
|
153
|
+
result = result << 7
|
154
|
+
result = result | b
|
155
|
+
else
|
156
|
+
#Use all 8 bits from the 4th byte
|
157
|
+
result = result << 8
|
158
|
+
result = result | b
|
159
|
+
|
160
|
+
#Check if the integer should be negative
|
161
|
+
if result > INTEGER_MAX
|
162
|
+
result -= (1 << 29)
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
result
|
167
|
+
end
|
168
|
+
|
169
|
+
private
|
170
|
+
def amf3_read_number
|
171
|
+
result = read_double(@source)
|
172
|
+
|
173
|
+
#check for NaN and convert them to nil
|
174
|
+
if result.is_a?(Float) && result.nan?
|
175
|
+
result = nil
|
176
|
+
end
|
177
|
+
|
178
|
+
result
|
179
|
+
end
|
180
|
+
|
181
|
+
private
|
182
|
+
def amf3_read_string
|
183
|
+
result = nil
|
184
|
+
|
185
|
+
type = amf3_read_integer
|
186
|
+
|
187
|
+
result = get_as_reference_string(type)
|
188
|
+
|
189
|
+
if result.nil?
|
190
|
+
length = type >> 1
|
191
|
+
result = ''
|
192
|
+
|
193
|
+
if length > 0
|
194
|
+
|
195
|
+
if length > (@source.size - @source.pos)
|
196
|
+
raise AMFErrorIncomplete.new
|
197
|
+
end
|
198
|
+
|
199
|
+
result = @source.read(length)
|
200
|
+
result.force_encoding('UTF-8') if result.respond_to?(:force_encoding)
|
201
|
+
@cache_strings << result
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
result
|
206
|
+
end
|
207
|
+
|
208
|
+
private
|
209
|
+
def amf3_read_date
|
210
|
+
result = nil
|
211
|
+
|
212
|
+
type = amf3_read_integer
|
213
|
+
|
214
|
+
result = get_as_reference_object(type)
|
215
|
+
|
216
|
+
if result.nil?
|
217
|
+
seconds = read_double(@source).to_f / 1000
|
218
|
+
result = Time.at(seconds)
|
219
|
+
@cache_objects << result
|
220
|
+
end
|
221
|
+
|
222
|
+
result
|
223
|
+
end
|
224
|
+
|
225
|
+
private
|
226
|
+
def amf3_read_array
|
227
|
+
result = nil
|
228
|
+
|
229
|
+
type = amf3_read_integer
|
230
|
+
|
231
|
+
result = get_as_reference_object(type)
|
232
|
+
|
233
|
+
if result.nil?
|
234
|
+
length = type >> 1
|
235
|
+
property_name = amf3_read_string
|
236
|
+
result = property_name.length > 0 ? {} : []
|
237
|
+
@cache_objects << result
|
238
|
+
|
239
|
+
while property_name.length > 0
|
240
|
+
value = amf3_deserialize
|
241
|
+
result[property_name] = value
|
242
|
+
property_name = amf3_read_string
|
243
|
+
end
|
244
|
+
|
245
|
+
0.upto(length - 1) { |i| result[i] = amf3_deserialize }
|
246
|
+
end
|
247
|
+
|
248
|
+
result
|
249
|
+
end
|
250
|
+
|
251
|
+
# dynamic - c an instance of a Class definition with the dynamic trait declared; public variable members can be added and removed from instances dynamically at runtime
|
252
|
+
private
|
253
|
+
def amf3_read_object
|
254
|
+
result = nil
|
255
|
+
|
256
|
+
type = amf3_read_integer
|
257
|
+
|
258
|
+
result = get_as_reference_object(type)
|
259
|
+
|
260
|
+
if result.nil?
|
261
|
+
class_type = type >> 1
|
262
|
+
class_is_reference = (class_type & 0x01) == 0
|
263
|
+
|
264
|
+
if class_is_reference
|
265
|
+
reference = class_type >> 1
|
266
|
+
traits = @cache_traits[reference]
|
267
|
+
else
|
268
|
+
dynamic = (class_type & 0x04) != 0
|
269
|
+
attribute_count = class_type >> 3
|
270
|
+
class_name = amf3_read_string
|
271
|
+
|
272
|
+
class_attributes = []
|
273
|
+
attribute_count.times { class_attributes << amf3_read_string } # Read class members
|
274
|
+
|
275
|
+
traits =
|
276
|
+
{
|
277
|
+
class_name: class_name,
|
278
|
+
members: class_attributes,
|
279
|
+
dynamic: dynamic
|
280
|
+
}
|
281
|
+
@cache_traits << traits
|
282
|
+
end
|
283
|
+
|
284
|
+
result = @class_mapper.create_object(traits[:class_name])
|
285
|
+
@cache_objects << result
|
286
|
+
|
287
|
+
properties = {}
|
288
|
+
|
289
|
+
traits[:members].each do |key|
|
290
|
+
value = amf3_deserialize
|
291
|
+
properties[key] = value
|
292
|
+
end
|
293
|
+
|
294
|
+
if traits[:dynamic]
|
295
|
+
while (key = amf3_read_string) && key.length != 0 do # read next key
|
296
|
+
value = amf3_deserialize
|
297
|
+
properties[key] = value
|
298
|
+
end
|
299
|
+
end
|
300
|
+
|
301
|
+
@class_mapper.object_deserialize(result, properties)
|
302
|
+
end
|
303
|
+
|
304
|
+
result
|
305
|
+
end
|
306
|
+
|
307
|
+
private
|
308
|
+
def amf3_read_byte_array
|
309
|
+
result = nil
|
310
|
+
|
311
|
+
type = amf3_read_integer
|
312
|
+
|
313
|
+
result = get_as_reference_object(type)
|
314
|
+
|
315
|
+
if result.nil?
|
316
|
+
length = type >> 1
|
317
|
+
|
318
|
+
if length > (@source.size - @source.pos)
|
319
|
+
raise AMFErrorIncomplete.new
|
320
|
+
end
|
321
|
+
|
322
|
+
result = StringIO.new(@source.read(length))
|
323
|
+
@cache_objects << result
|
324
|
+
end
|
325
|
+
|
326
|
+
result
|
327
|
+
end
|
328
|
+
|
329
|
+
private
|
330
|
+
def amf3_read_dictionary
|
331
|
+
result = nil
|
332
|
+
|
333
|
+
type = amf3_read_integer
|
334
|
+
|
335
|
+
result = get_as_reference_object(type)
|
336
|
+
|
337
|
+
if result.nil?
|
338
|
+
result = {}
|
339
|
+
@cache_objects << result
|
340
|
+
length = type >> 1
|
341
|
+
weak_keys = read_int8(@source) # Ignore: Not supported in ruby
|
342
|
+
|
343
|
+
0.upto(length - 1) do |i|
|
344
|
+
result[amf3_deserialize] = amf3_deserialize
|
345
|
+
end
|
346
|
+
|
347
|
+
end
|
348
|
+
|
349
|
+
result
|
350
|
+
end
|
351
|
+
|
352
|
+
end #Deserializer
|
353
|
+
end #Pure
|
354
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module AMF
|
2
|
+
module Pure
|
3
|
+
class CacheObjects < Hash #:nodoc:
|
4
|
+
def initialize
|
5
|
+
@cache_index = 0
|
6
|
+
end
|
7
|
+
|
8
|
+
def [](obj)
|
9
|
+
super(obj.object_id)
|
10
|
+
end
|
11
|
+
|
12
|
+
def add_object(value)
|
13
|
+
self[value.object_id] = @cache_index
|
14
|
+
@cache_index += 1
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module AMF
|
2
|
+
module Pure
|
3
|
+
module IOHelperBase
|
4
|
+
|
5
|
+
def byte_order
|
6
|
+
if [0x12345678].pack('L') == "\x12\x34\x56\x78"
|
7
|
+
:BigEndian
|
8
|
+
else
|
9
|
+
:LittleEndian
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def byte_order_little?
|
14
|
+
byte_order == :LittleEndian
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'amf/pure/helpers/io_helper_base'
|
2
|
+
|
3
|
+
module AMF
|
4
|
+
module Pure
|
5
|
+
module IOHelperRead #:nodoc:
|
6
|
+
|
7
|
+
include IOHelperBase
|
8
|
+
|
9
|
+
#
|
10
|
+
# Methods
|
11
|
+
#
|
12
|
+
|
13
|
+
public
|
14
|
+
def read_int8(source)
|
15
|
+
raise AMFErrorIncomplete.new if source.eof?
|
16
|
+
|
17
|
+
source.read(1).unpack('c').first
|
18
|
+
end
|
19
|
+
|
20
|
+
public
|
21
|
+
def read_word8(source)
|
22
|
+
raise AMFErrorIncomplete.new if source.eof?
|
23
|
+
|
24
|
+
source.read(1).unpack('C').first
|
25
|
+
end
|
26
|
+
|
27
|
+
public
|
28
|
+
def read_double(source)
|
29
|
+
bytes_to_read = 8
|
30
|
+
|
31
|
+
raise AMFErrorIncomplete.new if bytes_to_read > (source.size - source.pos)
|
32
|
+
|
33
|
+
source.read(bytes_to_read).unpack('G').first
|
34
|
+
end
|
35
|
+
|
36
|
+
public
|
37
|
+
def read_word16_network(source)
|
38
|
+
bytes_to_read = 2
|
39
|
+
|
40
|
+
raise AMFErrorIncomplete.new if bytes_to_read > (source.size - source.pos)
|
41
|
+
|
42
|
+
source.read(2).unpack('n').first
|
43
|
+
end
|
44
|
+
|
45
|
+
public
|
46
|
+
def read_int16_network(source)
|
47
|
+
bytes_to_read = 2
|
48
|
+
|
49
|
+
raise AMFErrorIncomplete.new if bytes_to_read > (source.size - source.pos)
|
50
|
+
|
51
|
+
result = source.read(bytes_to_read)
|
52
|
+
result.reverse! if byte_order_little? # swap bytes as native=little (and we want network)
|
53
|
+
result.unpack('s').first
|
54
|
+
end
|
55
|
+
|
56
|
+
public
|
57
|
+
def read_word32_network(source)
|
58
|
+
bytes_to_read = 4
|
59
|
+
|
60
|
+
raise AMFErrorIncomplete.new if bytes_to_read > (source.size - source.pos)
|
61
|
+
|
62
|
+
source.read(bytes_to_read).unpack('N').first
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'amf/pure/helpers/io_helper_base'
|
2
|
+
|
3
|
+
module AMF
|
4
|
+
module Pure
|
5
|
+
module IOHelperWrite #:nodoc:
|
6
|
+
|
7
|
+
include IOHelperBase
|
8
|
+
|
9
|
+
def pack_integer(integer)
|
10
|
+
integer = integer & 0x1fffffff
|
11
|
+
|
12
|
+
if integer < AMF::AMFConstants::MIN_INT_2_BYTE
|
13
|
+
[integer].pack('c')
|
14
|
+
elsif integer < AMF::AMFConstants::MIN_INT_3_BYTE
|
15
|
+
[integer >> 7 & 0x7f | 0x80].pack('c') +
|
16
|
+
[integer & 0x7f].pack('c')
|
17
|
+
elsif integer < AMF::AMFConstants::MIN_INT_4_BYTE
|
18
|
+
[integer >> 14 & 0x7f | 0x80].pack('c') +
|
19
|
+
[integer >> 7 & 0x7f | 0x80].pack('c') +
|
20
|
+
[integer & 0x7f].pack('c')
|
21
|
+
else
|
22
|
+
[integer >> 22 & 0x7f | 0x80].pack('c')+
|
23
|
+
[integer >> 15 & 0x7f | 0x80].pack('c')+
|
24
|
+
[integer >> 8 & 0x7f | 0x80].pack('c')+
|
25
|
+
[integer & 0xff].pack('c')
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def pack_double(double)
|
30
|
+
[double].pack('G')
|
31
|
+
end
|
32
|
+
|
33
|
+
def pack_int8(val)
|
34
|
+
[val].pack('c')
|
35
|
+
end
|
36
|
+
|
37
|
+
def pack_int16_network(val)
|
38
|
+
[val].pack('n')
|
39
|
+
end
|
40
|
+
|
41
|
+
def pack_word32_network(val)
|
42
|
+
result = [val].pack('L')
|
43
|
+
result.reverse! if byte_order_little? # swap bytes as native=little (and we want network)
|
44
|
+
result
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|