1
+ #!/usr/bin/env ruby -w
2
+
3
+ # encoding: utf-8
4
+
1
5
module TNetStrings
2
6
def self . dump ( data )
3
7
case data
4
- when String , Symbol then "#{ data . length } :#{ data } ,"
8
+ when String then "#{ data . bytesize } :#{ data . bytes . pack ( 'C*' ) } ,"
9
+ when Symbol then "#{ data . to_s . length } :#{ data . to_s } ,"
5
10
when Fixnum then "#{ data . to_s . length } :#{ data . to_s } #"
6
11
when Float then "#{ data . to_s . length } :#{ data . to_s } ^"
7
12
when TrueClass then "4:true!"
@@ -10,11 +15,17 @@ def self.dump(data)
10
15
when Array then dump_array ( data )
11
16
when Hash then dump_hash ( data )
12
17
else
13
- raise "Can't serialize stuff that's '#{ data . class } '."
18
+ if data . respond_to? ( :to_s )
19
+ s = data . to_s
20
+ "#{ s . length } :#{ s } ,"
21
+ else
22
+ raise "Can't serialize stuff that's '#{ data . class } '."
23
+ end
14
24
end
15
25
end
16
26
17
27
def self . parse ( data )
28
+ raise "Invalid data." if data . empty?
18
29
payload , payload_type , remain = parse_payload ( data )
19
30
20
31
value = case payload_type
@@ -42,7 +53,7 @@ def self.parse_payload(data)
42
53
if len == 0
43
54
payload = ''
44
55
else
45
- payload , extra = extra [ 0 ..len -1 ] , extra [ len ..-1 ]
56
+ payload , extra = extra . byteslice ( 0 ..len -1 ) , extra . byteslice ( len ..-1 )
46
57
end
47
58
payload_type , remain = extra [ 0 ] , extra [ 1 ..-1 ]
48
59
@@ -128,6 +139,22 @@ def test_parse_strings
128
139
assert_equal "" , r
129
140
end
130
141
142
+ def test_parse_utf8_bytes
143
+ n = "3:foo,2:\u00B5 ,4:\xf0 \x9f \x98 \x87 ,"
144
+
145
+ s , r = TNetStrings ::parse ( n )
146
+ assert_equal "foo" , s
147
+ assert_equal "2:µ,4:😇," , r
148
+
149
+ s , r = TNetStrings ::parse ( r )
150
+ assert_equal "µ" , s
151
+ assert_equal "4:\u{1F607} ," . force_encoding ( 'UTF-8' ) , r
152
+
153
+ s , r = TNetStrings ::parse ( r )
154
+ assert_equal "😇" , s
155
+ assert_equal "" , r
156
+ end
157
+
131
158
def test_parse_fixnum
132
159
n = "2:42#"
133
160
@@ -240,6 +267,27 @@ def test_parse_hash
240
267
assert_equal "" , r
241
268
end
242
269
270
+ def test_parse_exceeding
271
+ s = "3:foo,4:true!"
272
+
273
+ v , r = TNetStrings ::parse ( s )
274
+ assert_equal "foo" , v
275
+ assert_equal "4:true!" , r
276
+
277
+ v , r = TNetStrings ::parse ( r )
278
+ assert_equal true , v
279
+ assert_equal "" , r
280
+
281
+ msg = ""
282
+ begin
283
+ v , r = TNetStrings ::parse ( r )
284
+ rescue => e
285
+ msg = e . message
286
+ end
287
+ assert_equal "Invalid data." , msg
288
+ assert_equal "" , r
289
+ end
290
+
243
291
def test_dump_strings
244
292
s = TNetStrings ::dump ( "foobar" )
245
293
assert_equal "6:foobar," , s
@@ -248,6 +296,17 @@ def test_dump_strings
248
296
assert_equal "6:foobar,3:baz," , s
249
297
end
250
298
299
+ def test_dump_byte_strings
300
+ s = TNetStrings ::dump ( "ßöö" )
301
+ assert_equal "6:\xC3 \x9F \xC3 \xB6 \xC3 \xB6 ," . unpack ( 'C*' ) , s . bytes
302
+
303
+ s << TNetStrings ::dump ( "µ" )
304
+ assert_equal "6:ßöö,2:µ," , s . force_encoding ( "UTF-8" )
305
+
306
+ s << TNetStrings ::dump ( "\u{1F607} " ) . force_encoding ( 'UTF-8' )
307
+ assert_equal "6:ßöö,2:µ,4:😇," , s . force_encoding ( "UTF-8" )
308
+ end
309
+
251
310
def test_dump_symbol
252
311
s = TNetStrings ::dump ( :foobarbaz )
253
312
assert_equal "9:foobarbaz," , s
0 commit comments