msgpack 0.4.7 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +17 -0
- data/ChangeLog +47 -0
- data/README.rdoc +102 -0
- data/Rakefile +88 -0
- data/doclib/msgpack.rb +55 -0
- data/doclib/msgpack/buffer.rb +193 -0
- data/doclib/msgpack/core_ext.rb +101 -0
- data/doclib/msgpack/error.rb +14 -0
- data/doclib/msgpack/packer.rb +131 -0
- data/doclib/msgpack/unpacker.rb +130 -0
- data/ext/msgpack/buffer.c +679 -0
- data/ext/msgpack/buffer.h +442 -0
- data/ext/msgpack/buffer_class.c +507 -0
- data/ext/msgpack/buffer_class.h +32 -0
- data/ext/msgpack/compat.h +112 -0
- data/ext/msgpack/core_ext.c +129 -0
- data/ext/{pack.h → msgpack/core_ext.h} +7 -7
- data/ext/msgpack/extconf.rb +17 -0
- data/ext/msgpack/packer.c +137 -0
- data/ext/msgpack/packer.h +319 -0
- data/ext/msgpack/packer_class.c +285 -0
- data/ext/{unpack.h → msgpack/packer_class.h} +11 -7
- data/ext/msgpack/rbinit.c +33 -0
- data/ext/msgpack/rmem.c +110 -0
- data/ext/msgpack/rmem.h +100 -0
- data/ext/msgpack/sysdep.h +115 -0
- data/ext/msgpack/sysdep_endian.h +50 -0
- data/ext/msgpack/sysdep_types.h +46 -0
- data/ext/msgpack/unpacker.c +669 -0
- data/ext/msgpack/unpacker.h +112 -0
- data/ext/msgpack/unpacker_class.c +376 -0
- data/{msgpack/pack_define.h → ext/msgpack/unpacker_class.h} +12 -8
- data/lib/msgpack.rb +10 -0
- data/{ext → lib/msgpack}/version.rb +1 -1
- data/msgpack.gemspec +25 -0
- data/spec/buffer_io_spec.rb +237 -0
- data/spec/buffer_spec.rb +572 -0
- data/{test → spec}/cases.json +0 -0
- data/{test/cases.mpac → spec/cases.msg} +0 -0
- data/{test/cases_compact.mpac → spec/cases_compact.msg} +0 -0
- data/spec/cases_spec.rb +39 -0
- data/spec/format_spec.rb +225 -0
- data/spec/packer_spec.rb +127 -0
- data/spec/random_compat.rb +24 -0
- data/spec/spec_helper.rb +21 -0
- data/spec/unpacker_spec.rb +128 -0
- metadata +171 -34
- data/ext/compat.h +0 -99
- data/ext/extconf.rb +0 -7
- data/ext/pack.c +0 -314
- data/ext/rbinit.c +0 -66
- data/ext/unpack.c +0 -1001
- data/msgpack/pack_template.h +0 -771
- data/msgpack/sysdep.h +0 -195
- data/msgpack/unpack_define.h +0 -93
- data/msgpack/unpack_template.h +0 -413
- data/test/test_cases.rb +0 -46
- data/test/test_encoding.rb +0 -68
- data/test/test_helper.rb +0 -10
- data/test/test_pack_unpack.rb +0 -308
data/ext/rbinit.c
DELETED
@@ -1,66 +0,0 @@
|
|
1
|
-
/*
|
2
|
-
* MessagePack for Ruby
|
3
|
-
*
|
4
|
-
* Copyright (C) 2008-2010 FURUHASHI Sadayuki
|
5
|
-
*
|
6
|
-
* Licensed under the Apache License, Version 2.0 (the "License");
|
7
|
-
* you may not use this file except in compliance with the License.
|
8
|
-
* You may obtain a copy of the License at
|
9
|
-
*
|
10
|
-
* http://www.apache.org/licenses/LICENSE-2.0
|
11
|
-
*
|
12
|
-
* Unless required by applicable law or agreed to in writing, software
|
13
|
-
* distributed under the License is distributed on an "AS IS" BASIS,
|
14
|
-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15
|
-
* See the License for the specific language governing permissions and
|
16
|
-
* limitations under the License.
|
17
|
-
*/
|
18
|
-
#include "pack.h"
|
19
|
-
#include "unpack.h"
|
20
|
-
#include "compat.h"
|
21
|
-
|
22
|
-
static VALUE mMessagePack;
|
23
|
-
|
24
|
-
#ifdef COMPAT_HAVE_ENCODING
|
25
|
-
int s_enc_utf8;
|
26
|
-
int s_enc_ascii8bit;
|
27
|
-
int s_enc_usascii;
|
28
|
-
VALUE s_enc_utf8_value;
|
29
|
-
#endif
|
30
|
-
|
31
|
-
/**
|
32
|
-
* Document-module: MessagePack
|
33
|
-
*
|
34
|
-
* MessagePack is a binary-based efficient object serialization library.
|
35
|
-
* It enables to exchange structured objects between many languages like JSON.
|
36
|
-
* But unlike JSON, it is very fast and small.
|
37
|
-
*
|
38
|
-
* You can install MessagePack with rubygems.
|
39
|
-
*
|
40
|
-
* gem install msgpack
|
41
|
-
*
|
42
|
-
* Simple usage is as follows:
|
43
|
-
*
|
44
|
-
* require 'msgpack'
|
45
|
-
* msg = [1,2,3].to_msgpack #=> "\x93\x01\x02\x03"
|
46
|
-
* MessagePack.unpack(msg) #=> [1,2,3]
|
47
|
-
*
|
48
|
-
* Use Unpacker class for streaming deserialization.
|
49
|
-
*
|
50
|
-
*/
|
51
|
-
void Init_msgpack(void)
|
52
|
-
{
|
53
|
-
mMessagePack = rb_define_module("MessagePack");
|
54
|
-
|
55
|
-
rb_define_const(mMessagePack, "VERSION", rb_str_new2(MESSAGEPACK_VERSION));
|
56
|
-
|
57
|
-
#ifdef COMPAT_HAVE_ENCODING
|
58
|
-
s_enc_ascii8bit = rb_ascii8bit_encindex();
|
59
|
-
s_enc_utf8 = rb_utf8_encindex();
|
60
|
-
s_enc_usascii = rb_usascii_encindex();
|
61
|
-
s_enc_utf8_value = rb_enc_from_encoding(rb_utf8_encoding());
|
62
|
-
#endif
|
63
|
-
|
64
|
-
Init_msgpack_unpack(mMessagePack);
|
65
|
-
Init_msgpack_pack(mMessagePack);
|
66
|
-
}
|
data/ext/unpack.c
DELETED
@@ -1,1001 +0,0 @@
|
|
1
|
-
/*
|
2
|
-
* MessagePack for Ruby unpacking routine
|
3
|
-
*
|
4
|
-
* Copyright (C) 2008-2010 FURUHASHI Sadayuki
|
5
|
-
*
|
6
|
-
* Licensed under the Apache License, Version 2.0 (the "License");
|
7
|
-
* you may not use this file except in compliance with the License.
|
8
|
-
* You may obtain a copy of the License at
|
9
|
-
*
|
10
|
-
* http://www.apache.org/licenses/LICENSE-2.0
|
11
|
-
*
|
12
|
-
* Unless required by applicable law or agreed to in writing, software
|
13
|
-
* distributed under the License is distributed on an "AS IS" BASIS,
|
14
|
-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15
|
-
* See the License for the specific language governing permissions and
|
16
|
-
* limitations under the License.
|
17
|
-
*/
|
18
|
-
#include "ruby.h"
|
19
|
-
#include "compat.h"
|
20
|
-
|
21
|
-
#include "msgpack/unpack_define.h"
|
22
|
-
|
23
|
-
static ID s_sysread;
|
24
|
-
static ID s_readpartial;
|
25
|
-
|
26
|
-
struct unpack_buffer {
|
27
|
-
size_t used;
|
28
|
-
size_t free;
|
29
|
-
char* ptr;
|
30
|
-
};
|
31
|
-
|
32
|
-
typedef struct {
|
33
|
-
int finished;
|
34
|
-
VALUE source;
|
35
|
-
size_t offset;
|
36
|
-
struct unpack_buffer buffer;
|
37
|
-
VALUE stream;
|
38
|
-
VALUE streambuf;
|
39
|
-
ID stream_append_method;
|
40
|
-
size_t buffer_free_size;
|
41
|
-
} unpack_user;
|
42
|
-
|
43
|
-
|
44
|
-
#define msgpack_unpack_struct(name) \
|
45
|
-
struct template ## name
|
46
|
-
|
47
|
-
#define msgpack_unpack_func(ret, name) \
|
48
|
-
ret template ## name
|
49
|
-
|
50
|
-
#define msgpack_unpack_callback(name) \
|
51
|
-
template_callback ## name
|
52
|
-
|
53
|
-
#define msgpack_unpack_object VALUE
|
54
|
-
|
55
|
-
#define msgpack_unpack_user unpack_user
|
56
|
-
|
57
|
-
|
58
|
-
struct template_context;
|
59
|
-
typedef struct template_context msgpack_unpack_t;
|
60
|
-
|
61
|
-
static void template_init(msgpack_unpack_t* u);
|
62
|
-
|
63
|
-
static VALUE template_data(msgpack_unpack_t* u);
|
64
|
-
|
65
|
-
static int template_execute(msgpack_unpack_t* u,
|
66
|
-
const char* data, size_t len, size_t* off);
|
67
|
-
|
68
|
-
|
69
|
-
static inline VALUE template_callback_root(unpack_user* u)
|
70
|
-
{ return Qnil; }
|
71
|
-
|
72
|
-
static inline int template_callback_uint8(unpack_user* u, uint8_t d, VALUE* o)
|
73
|
-
{ *o = INT2FIX(d); return 0; }
|
74
|
-
|
75
|
-
static inline int template_callback_uint16(unpack_user* u, uint16_t d, VALUE* o)
|
76
|
-
{ *o = INT2FIX(d); return 0; }
|
77
|
-
|
78
|
-
static inline int template_callback_uint32(unpack_user* u, uint32_t d, VALUE* o)
|
79
|
-
{ *o = UINT2NUM(d); return 0; }
|
80
|
-
|
81
|
-
static inline int template_callback_uint64(unpack_user* u, uint64_t d, VALUE* o)
|
82
|
-
{ *o = rb_ull2inum(d); return 0; }
|
83
|
-
|
84
|
-
static inline int template_callback_int8(unpack_user* u, int8_t d, VALUE* o)
|
85
|
-
{ *o = INT2FIX((long)d); return 0; }
|
86
|
-
|
87
|
-
static inline int template_callback_int16(unpack_user* u, int16_t d, VALUE* o)
|
88
|
-
{ *o = INT2FIX((long)d); return 0; }
|
89
|
-
|
90
|
-
static inline int template_callback_int32(unpack_user* u, int32_t d, VALUE* o)
|
91
|
-
{ *o = INT2NUM((long)d); return 0; }
|
92
|
-
|
93
|
-
static inline int template_callback_int64(unpack_user* u, int64_t d, VALUE* o)
|
94
|
-
{ *o = rb_ll2inum(d); return 0; }
|
95
|
-
|
96
|
-
static inline int template_callback_float(unpack_user* u, float d, VALUE* o)
|
97
|
-
{ *o = rb_float_new(d); return 0; }
|
98
|
-
|
99
|
-
static inline int template_callback_double(unpack_user* u, double d, VALUE* o)
|
100
|
-
{ *o = rb_float_new(d); return 0; }
|
101
|
-
|
102
|
-
static inline int template_callback_nil(unpack_user* u, VALUE* o)
|
103
|
-
{ *o = Qnil; return 0; }
|
104
|
-
|
105
|
-
static inline int template_callback_true(unpack_user* u, VALUE* o)
|
106
|
-
{ *o = Qtrue; return 0; }
|
107
|
-
|
108
|
-
static inline int template_callback_false(unpack_user* u, VALUE* o)
|
109
|
-
{ *o = Qfalse; return 0;}
|
110
|
-
|
111
|
-
static inline int template_callback_array(unpack_user* u, unsigned int n, VALUE* o)
|
112
|
-
{ *o = rb_ary_new2(n); return 0; }
|
113
|
-
|
114
|
-
static inline int template_callback_array_item(unpack_user* u, VALUE* c, VALUE o)
|
115
|
-
{ rb_ary_push(*c, o); return 0; }
|
116
|
-
|
117
|
-
static inline int template_callback_map(unpack_user* u, unsigned int n, VALUE* o)
|
118
|
-
{ *o = rb_hash_new(); return 0; }
|
119
|
-
|
120
|
-
static inline int template_callback_map_item(unpack_user* u, VALUE* c, VALUE k, VALUE v)
|
121
|
-
{ rb_hash_aset(*c, k, v); return 0; }
|
122
|
-
|
123
|
-
#ifdef RSTRING_EMBED_LEN_MAX
|
124
|
-
#define COW_MIN_SIZE RSTRING_EMBED_LEN_MAX
|
125
|
-
#else
|
126
|
-
#define COW_MIN_SIZE ((sizeof(VALUE)*3)/sizeof(char)-1)
|
127
|
-
#endif
|
128
|
-
|
129
|
-
static inline int template_callback_raw(unpack_user* u, const char* b, const char* p, unsigned int l, VALUE* o)
|
130
|
-
{
|
131
|
-
if(u->source == Qnil || l <= COW_MIN_SIZE) {
|
132
|
-
*o = rb_str_new(p, l);
|
133
|
-
} else {
|
134
|
-
*o = rb_str_substr(u->source, p - b, l);
|
135
|
-
}
|
136
|
-
#ifdef COMPAT_HAVE_ENCODING
|
137
|
-
ENCODING_SET(*o, s_enc_utf8);
|
138
|
-
#endif
|
139
|
-
return 0;
|
140
|
-
}
|
141
|
-
|
142
|
-
|
143
|
-
#include "msgpack/unpack_template.h"
|
144
|
-
|
145
|
-
|
146
|
-
#define UNPACKER(from, name) \
|
147
|
-
msgpack_unpack_t *name = NULL; \
|
148
|
-
Data_Get_Struct(from, msgpack_unpack_t, name); \
|
149
|
-
if(name == NULL) { \
|
150
|
-
rb_raise(rb_eArgError, "NULL found for " # name " when shouldn't be."); \
|
151
|
-
}
|
152
|
-
|
153
|
-
#define CHECK_STRING_TYPE(value) \
|
154
|
-
value = rb_check_string_type(value); \
|
155
|
-
if( NIL_P(value) ) { \
|
156
|
-
rb_raise(rb_eTypeError, "instance of String needed"); \
|
157
|
-
}
|
158
|
-
|
159
|
-
|
160
|
-
static VALUE template_execute_rescue(VALUE nouse)
|
161
|
-
{
|
162
|
-
rb_gc_enable();
|
163
|
-
COMPAT_RERAISE;
|
164
|
-
}
|
165
|
-
|
166
|
-
static VALUE template_execute_do(VALUE argv)
|
167
|
-
{
|
168
|
-
VALUE* args = (VALUE*)argv;
|
169
|
-
|
170
|
-
msgpack_unpack_t* mp = (msgpack_unpack_t*)args[0];
|
171
|
-
char* dptr = (char*)args[1];
|
172
|
-
size_t dlen = (size_t)args[2];
|
173
|
-
size_t* from = (size_t*)args[3];
|
174
|
-
|
175
|
-
int ret = template_execute(mp, dptr, dlen, from);
|
176
|
-
|
177
|
-
return (VALUE)ret;
|
178
|
-
}
|
179
|
-
|
180
|
-
static int template_execute_wrap(msgpack_unpack_t* mp,
|
181
|
-
VALUE str, size_t dlen, size_t* from)
|
182
|
-
{
|
183
|
-
VALUE args[4] = {
|
184
|
-
(VALUE)mp,
|
185
|
-
(VALUE)RSTRING_PTR(str),
|
186
|
-
(VALUE)dlen,
|
187
|
-
(VALUE)from,
|
188
|
-
};
|
189
|
-
|
190
|
-
// FIXME execute実行中はmp->topが更新されないのでGC markが機能しない
|
191
|
-
rb_gc_disable();
|
192
|
-
|
193
|
-
mp->user.source = str;
|
194
|
-
|
195
|
-
int ret = (int)rb_rescue(template_execute_do, (VALUE)args,
|
196
|
-
template_execute_rescue, Qnil);
|
197
|
-
|
198
|
-
rb_gc_enable();
|
199
|
-
|
200
|
-
return ret;
|
201
|
-
}
|
202
|
-
|
203
|
-
static int template_execute_wrap_each(msgpack_unpack_t* mp,
|
204
|
-
const char* ptr, size_t dlen, size_t* from)
|
205
|
-
{
|
206
|
-
VALUE args[4] = {
|
207
|
-
(VALUE)mp,
|
208
|
-
(VALUE)ptr,
|
209
|
-
(VALUE)dlen,
|
210
|
-
(VALUE)from,
|
211
|
-
};
|
212
|
-
|
213
|
-
// FIXME execute実行中はmp->topが更新されないのでGC markが機能しない
|
214
|
-
rb_gc_disable();
|
215
|
-
|
216
|
-
mp->user.source = Qnil;
|
217
|
-
|
218
|
-
int ret = (int)rb_rescue(template_execute_do, (VALUE)args,
|
219
|
-
template_execute_rescue, Qnil);
|
220
|
-
|
221
|
-
rb_gc_enable();
|
222
|
-
|
223
|
-
return ret;
|
224
|
-
}
|
225
|
-
|
226
|
-
|
227
|
-
static VALUE cUnpacker;
|
228
|
-
|
229
|
-
|
230
|
-
/**
|
231
|
-
* Document-module: MessagePack::UnpackerError
|
232
|
-
*
|
233
|
-
*/
|
234
|
-
static VALUE eUnpackError;
|
235
|
-
|
236
|
-
|
237
|
-
#ifndef MSGPACK_UNPACKER_BUFFER_INIT_SIZE
|
238
|
-
#define MSGPACK_UNPACKER_BUFFER_INIT_SIZE (32*1024)
|
239
|
-
#endif
|
240
|
-
|
241
|
-
#ifndef MSGPACK_UNPACKER_BUFFER_RESERVE_SIZE
|
242
|
-
#define MSGPACK_UNPACKER_BUFFER_RESERVE_SIZE (8*1024)
|
243
|
-
#endif
|
244
|
-
|
245
|
-
/*
|
246
|
-
#ifndef MSGPACK_BUFFER_FREE_SIZE
|
247
|
-
#define MSGPACK_BUFFER_FREE_SIZE (1024*1024)
|
248
|
-
#endif
|
249
|
-
*/
|
250
|
-
#define MSGPACK_BUFFER_FREE_SIZE 0
|
251
|
-
|
252
|
-
static void MessagePack_Unpacker_free(void* data)
|
253
|
-
{
|
254
|
-
if(data) {
|
255
|
-
msgpack_unpack_t* mp = (msgpack_unpack_t*)data;
|
256
|
-
free(mp->user.buffer.ptr);
|
257
|
-
free(mp);
|
258
|
-
}
|
259
|
-
}
|
260
|
-
|
261
|
-
static void MessagePack_Unpacker_mark(msgpack_unpack_t *mp)
|
262
|
-
{
|
263
|
-
unsigned int i;
|
264
|
-
rb_gc_mark(mp->user.stream);
|
265
|
-
rb_gc_mark(mp->user.streambuf);
|
266
|
-
rb_gc_mark_maybe(template_data(mp));
|
267
|
-
for(i=0; i < mp->top; ++i) {
|
268
|
-
rb_gc_mark(mp->stack[i].obj);
|
269
|
-
rb_gc_mark_maybe(mp->stack[i].map_key);
|
270
|
-
}
|
271
|
-
}
|
272
|
-
|
273
|
-
static VALUE MessagePack_Unpacker_alloc(VALUE klass)
|
274
|
-
{
|
275
|
-
VALUE obj;
|
276
|
-
msgpack_unpack_t* mp = ALLOC_N(msgpack_unpack_t, 1);
|
277
|
-
|
278
|
-
// rb_gc_mark (not _maybe) is used for following member objects.
|
279
|
-
mp->user.stream = Qnil;
|
280
|
-
mp->user.streambuf = Qnil;
|
281
|
-
|
282
|
-
mp->user.finished = 0;
|
283
|
-
mp->user.offset = 0;
|
284
|
-
mp->user.buffer.used = 0;
|
285
|
-
mp->user.buffer.free = 0;
|
286
|
-
mp->user.buffer.ptr = NULL;
|
287
|
-
|
288
|
-
obj = Data_Wrap_Struct(klass, MessagePack_Unpacker_mark,
|
289
|
-
MessagePack_Unpacker_free, mp);
|
290
|
-
return obj;
|
291
|
-
}
|
292
|
-
|
293
|
-
static ID append_method_of(VALUE stream)
|
294
|
-
{
|
295
|
-
if(rb_respond_to(stream, s_sysread)) {
|
296
|
-
return s_sysread;
|
297
|
-
} else {
|
298
|
-
return s_readpartial;
|
299
|
-
}
|
300
|
-
}
|
301
|
-
|
302
|
-
/**
|
303
|
-
* Document-method: MessagePack::Unpacker#initialize
|
304
|
-
*
|
305
|
-
* call-seq:
|
306
|
-
* MessagePack::Unpacker.new(stream = nil)
|
307
|
-
*
|
308
|
-
* Creates instance of MessagePack::Unpacker.
|
309
|
-
*
|
310
|
-
* You can specify a _stream_ for input stream.
|
311
|
-
* It is required to implement *sysread* or *readpartial* method.
|
312
|
-
*
|
313
|
-
* With the input stream, buffers will be feeded into the deserializer automatically.
|
314
|
-
*
|
315
|
-
* Without the input stream, use *feed* method manually. Or you can manage the buffer manually
|
316
|
-
* with *execute*, *finished?*, *data* and *reset* methods.
|
317
|
-
*/
|
318
|
-
static VALUE MessagePack_Unpacker_initialize(int argc, VALUE *argv, VALUE self)
|
319
|
-
{
|
320
|
-
VALUE stream;
|
321
|
-
switch(argc) {
|
322
|
-
case 0:
|
323
|
-
stream = Qnil;
|
324
|
-
break;
|
325
|
-
case 1:
|
326
|
-
stream = argv[0];
|
327
|
-
break;
|
328
|
-
default:
|
329
|
-
rb_raise(rb_eArgError, "wrong number of arguments (%d for 0)", argc);
|
330
|
-
}
|
331
|
-
|
332
|
-
UNPACKER(self, mp);
|
333
|
-
template_init(mp);
|
334
|
-
mp->user.stream = stream;
|
335
|
-
mp->user.streambuf = rb_str_buf_new(MSGPACK_UNPACKER_BUFFER_RESERVE_SIZE);
|
336
|
-
mp->user.stream_append_method = append_method_of(stream);
|
337
|
-
mp->user.buffer_free_size = MSGPACK_BUFFER_FREE_SIZE;
|
338
|
-
|
339
|
-
return self;
|
340
|
-
}
|
341
|
-
|
342
|
-
|
343
|
-
/**
|
344
|
-
* Document-method: MessagePack::Unpacker#stream
|
345
|
-
*
|
346
|
-
* call-seq:
|
347
|
-
* unpacker.stream
|
348
|
-
*
|
349
|
-
* Gets the input stream.
|
350
|
-
*/
|
351
|
-
static VALUE MessagePack_Unpacker_stream_get(VALUE self)
|
352
|
-
{
|
353
|
-
UNPACKER(self, mp);
|
354
|
-
return mp->user.stream;
|
355
|
-
}
|
356
|
-
|
357
|
-
/**
|
358
|
-
* Document-method: MessagePack::Unpacker#stream=
|
359
|
-
*
|
360
|
-
* call-seq:
|
361
|
-
* unpacker.stream = stream
|
362
|
-
*
|
363
|
-
* Resets the input stream. You can set nil not to use input stream.
|
364
|
-
*/
|
365
|
-
static VALUE MessagePack_Unpacker_stream_set(VALUE self, VALUE val)
|
366
|
-
{
|
367
|
-
UNPACKER(self, mp);
|
368
|
-
mp->user.stream = val;
|
369
|
-
mp->user.stream_append_method = append_method_of(val);
|
370
|
-
return val;
|
371
|
-
}
|
372
|
-
|
373
|
-
|
374
|
-
static void reserve_buffer(msgpack_unpack_t* mp, size_t require)
|
375
|
-
{
|
376
|
-
struct unpack_buffer* buffer = &mp->user.buffer;
|
377
|
-
|
378
|
-
if(buffer->used == 0) {
|
379
|
-
if(require <= buffer->free) {
|
380
|
-
/* enough free space */
|
381
|
-
return;
|
382
|
-
}
|
383
|
-
/* no used buffer: realloc only */
|
384
|
-
size_t nsize = buffer->free == 0 ?
|
385
|
-
MSGPACK_UNPACKER_BUFFER_INIT_SIZE : buffer->free*2;
|
386
|
-
while(nsize < require) {
|
387
|
-
nsize *= 2;
|
388
|
-
}
|
389
|
-
char* tmp = REALLOC_N(buffer->ptr, char, nsize);
|
390
|
-
buffer->free = nsize;
|
391
|
-
buffer->ptr = tmp;
|
392
|
-
return;
|
393
|
-
}
|
394
|
-
|
395
|
-
if(buffer->used <= mp->user.offset) {
|
396
|
-
/* clear buffer and rewind offset */
|
397
|
-
buffer->free += buffer->used;
|
398
|
-
buffer->used = 0;
|
399
|
-
mp->user.offset = 0;
|
400
|
-
}
|
401
|
-
|
402
|
-
if(require <= buffer->free) {
|
403
|
-
/* enough free space */
|
404
|
-
return;
|
405
|
-
}
|
406
|
-
|
407
|
-
size_t nsize = (buffer->used + buffer->free) * 2;
|
408
|
-
|
409
|
-
if(mp->user.offset <= buffer->used / 2) {
|
410
|
-
/* parsed less than half: realloc only */
|
411
|
-
while(nsize < buffer->used + require) {
|
412
|
-
nsize *= 2;
|
413
|
-
}
|
414
|
-
char* tmp = REALLOC_N(buffer->ptr, char, nsize);
|
415
|
-
buffer->free = nsize - buffer->used;
|
416
|
-
buffer->ptr = tmp;
|
417
|
-
|
418
|
-
} else {
|
419
|
-
/* parsed more than half: realloc and move */
|
420
|
-
size_t not_parsed = buffer->used - mp->user.offset;
|
421
|
-
while(nsize < not_parsed + require) {
|
422
|
-
nsize *= 2;
|
423
|
-
}
|
424
|
-
char* tmp = REALLOC_N(buffer->ptr, char, nsize);
|
425
|
-
memcpy(tmp, tmp + mp->user.offset, not_parsed);
|
426
|
-
buffer->free = nsize - not_parsed;
|
427
|
-
buffer->used = not_parsed;
|
428
|
-
buffer->ptr = tmp;
|
429
|
-
mp->user.offset = 0;
|
430
|
-
}
|
431
|
-
}
|
432
|
-
|
433
|
-
static inline void try_free_buffer(msgpack_unpack_t* mp, size_t require)
|
434
|
-
{
|
435
|
-
if(mp->user.buffer_free_size == 0) {
|
436
|
-
return;
|
437
|
-
}
|
438
|
-
|
439
|
-
struct unpack_buffer* buffer = &mp->user.buffer;
|
440
|
-
size_t csize = buffer->used + buffer->free;
|
441
|
-
|
442
|
-
if(csize <= mp->user.buffer_free_size) {
|
443
|
-
return;
|
444
|
-
}
|
445
|
-
|
446
|
-
if(mp->user.offset <= buffer->used / 2) {
|
447
|
-
/* parsed less than half: do nothing */
|
448
|
-
|
449
|
-
} else if(mp->user.offset < buffer->used) {
|
450
|
-
/* parsed more than half but not all: realloc and move */
|
451
|
-
size_t nsize = MSGPACK_UNPACKER_BUFFER_INIT_SIZE;
|
452
|
-
size_t not_parsed = buffer->used - mp->user.offset;
|
453
|
-
while(nsize < not_parsed + require) {
|
454
|
-
nsize *= 2;
|
455
|
-
}
|
456
|
-
|
457
|
-
if(nsize >= csize) {
|
458
|
-
return;
|
459
|
-
}
|
460
|
-
|
461
|
-
char* tmp;
|
462
|
-
if(mp->user.offset == 0) {
|
463
|
-
tmp = ALLOC_N(char, nsize);
|
464
|
-
memcpy(tmp, buffer->ptr + mp->user.offset, not_parsed);
|
465
|
-
free(buffer->ptr);
|
466
|
-
} else {
|
467
|
-
tmp = REALLOC_N(buffer->ptr, char, nsize);
|
468
|
-
}
|
469
|
-
buffer->free = nsize - not_parsed;
|
470
|
-
buffer->used = not_parsed;
|
471
|
-
buffer->ptr = tmp;
|
472
|
-
mp->user.offset = 0;
|
473
|
-
|
474
|
-
} else {
|
475
|
-
/* all parsed: free all */
|
476
|
-
free(buffer->ptr);
|
477
|
-
buffer->free = 0;
|
478
|
-
buffer->used = 0;
|
479
|
-
buffer->ptr = NULL;
|
480
|
-
mp->user.offset = 0;
|
481
|
-
}
|
482
|
-
}
|
483
|
-
|
484
|
-
static void feed_buffer(msgpack_unpack_t* mp, const char* ptr, size_t len)
|
485
|
-
{
|
486
|
-
struct unpack_buffer* buffer = &mp->user.buffer;
|
487
|
-
|
488
|
-
reserve_buffer(mp, len);
|
489
|
-
|
490
|
-
memcpy(buffer->ptr + buffer->used, ptr, len);
|
491
|
-
buffer->used += len;
|
492
|
-
buffer->free -= len;
|
493
|
-
}
|
494
|
-
|
495
|
-
/**
|
496
|
-
* Document-method: MessagePack::Unpacker#feed
|
497
|
-
*
|
498
|
-
* call-seq:
|
499
|
-
* unpacker.feed(data)
|
500
|
-
*
|
501
|
-
* Fills the internal buffer with the specified buffer.
|
502
|
-
*/
|
503
|
-
static VALUE MessagePack_Unpacker_feed(VALUE self, VALUE data)
|
504
|
-
{
|
505
|
-
UNPACKER(self, mp);
|
506
|
-
StringValue(data);
|
507
|
-
feed_buffer(mp, RSTRING_PTR(data), RSTRING_LEN(data));
|
508
|
-
return Qnil;
|
509
|
-
}
|
510
|
-
|
511
|
-
/**
|
512
|
-
* Document-method: MessagePack::Unpacker#fill
|
513
|
-
*
|
514
|
-
* call-seq:
|
515
|
-
* unpacker.fill -> length of read data
|
516
|
-
*
|
517
|
-
* Fills the internal buffer using the input stream.
|
518
|
-
*
|
519
|
-
* If the input stream is not specified, it returns nil.
|
520
|
-
* You can set it on *initialize* or *stream=* methods.
|
521
|
-
*
|
522
|
-
* This methods raises exceptions that _stream.sysread_ or
|
523
|
-
* _stream.readpartial_ method raises.
|
524
|
-
*/
|
525
|
-
static VALUE MessagePack_Unpacker_fill(VALUE self)
|
526
|
-
{
|
527
|
-
UNPACKER(self, mp);
|
528
|
-
|
529
|
-
if(mp->user.stream == Qnil) {
|
530
|
-
return Qnil;
|
531
|
-
}
|
532
|
-
|
533
|
-
rb_funcall(mp->user.stream, mp->user.stream_append_method, 2,
|
534
|
-
LONG2FIX(MSGPACK_UNPACKER_BUFFER_RESERVE_SIZE),
|
535
|
-
mp->user.streambuf);
|
536
|
-
|
537
|
-
size_t len = RSTRING_LEN(mp->user.streambuf);
|
538
|
-
feed_buffer(mp, RSTRING_PTR(mp->user.streambuf), len);
|
539
|
-
|
540
|
-
return LONG2FIX(len);
|
541
|
-
}
|
542
|
-
|
543
|
-
|
544
|
-
/**
|
545
|
-
* Document-method: MessagePack::Unpacker#each
|
546
|
-
*
|
547
|
-
* call-seq:
|
548
|
-
* unpacker.each {|object| }
|
549
|
-
*
|
550
|
-
* Deserializes objects repeatedly. This calls *fill* method automatically.
|
551
|
-
*
|
552
|
-
* UnpackError is throw when parse error is occured.
|
553
|
-
* This method raises exceptions that *fill* method raises.
|
554
|
-
*/
|
555
|
-
static VALUE MessagePack_Unpacker_each(VALUE self)
|
556
|
-
{
|
557
|
-
UNPACKER(self, mp);
|
558
|
-
int ret;
|
559
|
-
|
560
|
-
#ifdef RETURN_ENUMERATOR
|
561
|
-
RETURN_ENUMERATOR(self, 0, 0);
|
562
|
-
#endif
|
563
|
-
|
564
|
-
while(1) {
|
565
|
-
if(mp->user.buffer.used <= mp->user.offset) {
|
566
|
-
do_fill:
|
567
|
-
{
|
568
|
-
VALUE len = MessagePack_Unpacker_fill(self);
|
569
|
-
if(len == Qnil || FIX2LONG(len) == 0) {
|
570
|
-
break;
|
571
|
-
}
|
572
|
-
}
|
573
|
-
}
|
574
|
-
|
575
|
-
ret = template_execute_wrap_each(mp,
|
576
|
-
mp->user.buffer.ptr, mp->user.buffer.used,
|
577
|
-
&mp->user.offset);
|
578
|
-
|
579
|
-
if(ret < 0) {
|
580
|
-
rb_raise(eUnpackError, "parse error.");
|
581
|
-
|
582
|
-
} else if(ret > 0) {
|
583
|
-
VALUE data = template_data(mp);
|
584
|
-
template_init(mp);
|
585
|
-
rb_yield(data);
|
586
|
-
|
587
|
-
} else {
|
588
|
-
goto do_fill;
|
589
|
-
}
|
590
|
-
}
|
591
|
-
|
592
|
-
try_free_buffer(mp, 0);
|
593
|
-
|
594
|
-
return Qnil;
|
595
|
-
}
|
596
|
-
|
597
|
-
static VALUE feed_each_impl(VALUE args)
|
598
|
-
{
|
599
|
-
VALUE self = ((VALUE*)args)[0];
|
600
|
-
VALUE data = ((VALUE*)args)[1];
|
601
|
-
size_t* pconsumed = (size_t*)((VALUE*)args)[2];
|
602
|
-
|
603
|
-
UNPACKER(self, mp);
|
604
|
-
int ret;
|
605
|
-
const char* ptr = RSTRING_PTR(data);
|
606
|
-
size_t len = RSTRING_LEN(data);
|
607
|
-
|
608
|
-
if(mp->user.buffer.used > 0) {
|
609
|
-
while(1) {
|
610
|
-
ret = template_execute_wrap_each(mp,
|
611
|
-
mp->user.buffer.ptr, mp->user.buffer.used,
|
612
|
-
&mp->user.offset);
|
613
|
-
|
614
|
-
if(ret < 0) {
|
615
|
-
rb_raise(eUnpackError, "parse error.");
|
616
|
-
|
617
|
-
} else if(ret > 0) {
|
618
|
-
VALUE data = template_data(mp);
|
619
|
-
template_init(mp);
|
620
|
-
rb_yield(data);
|
621
|
-
|
622
|
-
} else {
|
623
|
-
break;
|
624
|
-
}
|
625
|
-
}
|
626
|
-
}
|
627
|
-
|
628
|
-
if(len <= 0) {
|
629
|
-
return Qnil;
|
630
|
-
}
|
631
|
-
|
632
|
-
if(mp->user.buffer.used <= mp->user.offset) {
|
633
|
-
// wrap & execute & feed
|
634
|
-
while(1) {
|
635
|
-
ret = template_execute_wrap_each(mp,
|
636
|
-
ptr, len, pconsumed);
|
637
|
-
|
638
|
-
if(ret < 0) {
|
639
|
-
rb_raise(eUnpackError, "parse error.");
|
640
|
-
|
641
|
-
} else if(ret > 0) {
|
642
|
-
VALUE data = template_data(mp);
|
643
|
-
template_init(mp);
|
644
|
-
rb_yield(data);
|
645
|
-
|
646
|
-
} else {
|
647
|
-
break;
|
648
|
-
}
|
649
|
-
}
|
650
|
-
|
651
|
-
} else {
|
652
|
-
// feed & execute
|
653
|
-
feed_buffer(mp, ptr, len);
|
654
|
-
*pconsumed = len;
|
655
|
-
|
656
|
-
while(1) {
|
657
|
-
ret = template_execute_wrap_each(mp,
|
658
|
-
mp->user.buffer.ptr, mp->user.buffer.used,
|
659
|
-
&mp->user.offset);
|
660
|
-
|
661
|
-
if(ret < 0) {
|
662
|
-
rb_raise(eUnpackError, "parse error.");
|
663
|
-
|
664
|
-
} else if(ret > 0) {
|
665
|
-
VALUE data = template_data(mp);
|
666
|
-
template_init(mp);
|
667
|
-
rb_yield(data);
|
668
|
-
|
669
|
-
} else {
|
670
|
-
break;
|
671
|
-
}
|
672
|
-
}
|
673
|
-
}
|
674
|
-
|
675
|
-
return Qnil;
|
676
|
-
}
|
677
|
-
|
678
|
-
static VALUE feed_each_ensure(VALUE args) {
|
679
|
-
VALUE self = ((VALUE*)args)[0];
|
680
|
-
VALUE data = ((VALUE*)args)[1];
|
681
|
-
size_t* pconsumed = (size_t*)((VALUE*)args)[2];
|
682
|
-
|
683
|
-
const char* dptr = RSTRING_PTR(data) + *pconsumed;
|
684
|
-
size_t dlen = RSTRING_LEN(data) - *pconsumed;
|
685
|
-
|
686
|
-
if(dlen > 0) {
|
687
|
-
UNPACKER(self, mp);
|
688
|
-
try_free_buffer(mp, dlen);
|
689
|
-
feed_buffer(mp, dptr, dlen);
|
690
|
-
}
|
691
|
-
|
692
|
-
return Qnil;
|
693
|
-
}
|
694
|
-
|
695
|
-
/**
|
696
|
-
* Document-method: MessagePack::Unpacker#feed_each
|
697
|
-
*
|
698
|
-
* call-seq:
|
699
|
-
* unpacker.feed_each(data) {|object| }
|
700
|
-
*
|
701
|
-
* Same as feed(data) + each {|object| }, but tries to avoid copying of the buffer.
|
702
|
-
*/
|
703
|
-
static VALUE MessagePack_Unpacker_feed_each(VALUE self, VALUE data)
|
704
|
-
{
|
705
|
-
size_t consumed = 0;
|
706
|
-
StringValue(data);
|
707
|
-
|
708
|
-
VALUE args[3];
|
709
|
-
args[0] = self;
|
710
|
-
args[1] = data;
|
711
|
-
args[2] = (VALUE)&consumed;
|
712
|
-
|
713
|
-
return rb_ensure(feed_each_impl, (VALUE)args,
|
714
|
-
feed_each_ensure, (VALUE)args);
|
715
|
-
}
|
716
|
-
|
717
|
-
|
718
|
-
static inline VALUE MessagePack_unpack_impl(VALUE self, VALUE data, unsigned long dlen)
|
719
|
-
{
|
720
|
-
msgpack_unpack_t mp;
|
721
|
-
template_init(&mp);
|
722
|
-
|
723
|
-
mp.user.finished = 0;
|
724
|
-
|
725
|
-
size_t from = 0;
|
726
|
-
int ret = template_execute_wrap(&mp, data, dlen, &from);
|
727
|
-
|
728
|
-
if(ret < 0) {
|
729
|
-
rb_raise(eUnpackError, "parse error.");
|
730
|
-
|
731
|
-
} else if(ret == 0) {
|
732
|
-
rb_raise(eUnpackError, "insufficient bytes.");
|
733
|
-
|
734
|
-
} else {
|
735
|
-
if(from < dlen) {
|
736
|
-
rb_raise(eUnpackError, "extra bytes.");
|
737
|
-
}
|
738
|
-
return template_data(&mp);
|
739
|
-
}
|
740
|
-
}
|
741
|
-
|
742
|
-
/**
|
743
|
-
* Document-method: MessagePack::Unpacker.unpack_limit
|
744
|
-
*
|
745
|
-
* call-seq:
|
746
|
-
* MessagePack::Unpacker.unpack_limit(data, limit) -> object
|
747
|
-
*
|
748
|
-
* Deserializes one object over the specified buffer upto _limit_ bytes.
|
749
|
-
*
|
750
|
-
* UnpackError is throw when parse error is occured, the buffer is insufficient
|
751
|
-
* to deserialize one object or there are extra bytes.
|
752
|
-
*/
|
753
|
-
static VALUE MessagePack_unpack_limit(VALUE self, VALUE data, VALUE limit)
|
754
|
-
{
|
755
|
-
CHECK_STRING_TYPE(data);
|
756
|
-
return MessagePack_unpack_impl(self, data, NUM2ULONG(limit));
|
757
|
-
}
|
758
|
-
|
759
|
-
/**
|
760
|
-
* Document-method: MessagePack::Unpacker.unpack
|
761
|
-
*
|
762
|
-
* call-seq:
|
763
|
-
* MessagePack::Unpacker.unpack(data) -> object
|
764
|
-
*
|
765
|
-
* Deserializes one object over the specified buffer.
|
766
|
-
*
|
767
|
-
* UnpackError is throw when parse error is occured, the buffer is insufficient
|
768
|
-
* to deserialize one object or there are extra bytes.
|
769
|
-
*/
|
770
|
-
static VALUE MessagePack_unpack(VALUE self, VALUE data)
|
771
|
-
{
|
772
|
-
CHECK_STRING_TYPE(data);
|
773
|
-
return MessagePack_unpack_impl(self, data, RSTRING_LEN(data));
|
774
|
-
}
|
775
|
-
|
776
|
-
|
777
|
-
static VALUE MessagePack_Unpacker_execute_impl(VALUE self, VALUE data,
|
778
|
-
size_t from, size_t limit)
|
779
|
-
{
|
780
|
-
UNPACKER(self, mp);
|
781
|
-
|
782
|
-
if(from >= limit) {
|
783
|
-
rb_raise(eUnpackError, "offset is bigger than data buffer size.");
|
784
|
-
}
|
785
|
-
|
786
|
-
int ret = template_execute_wrap(mp, data, limit, &from);
|
787
|
-
|
788
|
-
if(ret < 0) {
|
789
|
-
rb_raise(eUnpackError, "parse error.");
|
790
|
-
} else if(ret > 0) {
|
791
|
-
mp->user.finished = 1;
|
792
|
-
return ULONG2NUM(from);
|
793
|
-
} else {
|
794
|
-
mp->user.finished = 0;
|
795
|
-
return ULONG2NUM(from);
|
796
|
-
}
|
797
|
-
}
|
798
|
-
|
799
|
-
/**
|
800
|
-
* Document-method: MessagePack::Unpacker#execute_limit
|
801
|
-
*
|
802
|
-
* call-seq:
|
803
|
-
* unpacker.execute_limit(data, offset, limit) -> next offset
|
804
|
-
*
|
805
|
-
* Deserializes one object over the specified buffer from _offset_ bytes upto _limit_ bytes.
|
806
|
-
*
|
807
|
-
* This method doesn't use the internal buffer.
|
808
|
-
*
|
809
|
-
* Call *reset* method before calling this method again.
|
810
|
-
*
|
811
|
-
* UnpackError is throw when parse error is occured.
|
812
|
-
*/
|
813
|
-
static VALUE MessagePack_Unpacker_execute_limit(VALUE self, VALUE data,
|
814
|
-
VALUE off, VALUE limit)
|
815
|
-
{
|
816
|
-
CHECK_STRING_TYPE(data);
|
817
|
-
return MessagePack_Unpacker_execute_impl(self, data,
|
818
|
-
(size_t)NUM2ULONG(off), (size_t)NUM2ULONG(limit));
|
819
|
-
}
|
820
|
-
|
821
|
-
/**
|
822
|
-
* Document-method: MessagePack::Unpacker#execute
|
823
|
-
*
|
824
|
-
* call-seq:
|
825
|
-
* unpacker.execute(data, offset) -> next offset
|
826
|
-
*
|
827
|
-
* Deserializes one object over the specified buffer from _offset_ bytes.
|
828
|
-
*
|
829
|
-
* This method doesn't use the internal buffer.
|
830
|
-
*
|
831
|
-
* Call *reset* method before calling this method again.
|
832
|
-
*
|
833
|
-
* This returns offset that was parsed to.
|
834
|
-
* Use *finished?* method to check an object is deserialized and call *data*
|
835
|
-
* method if it returns true.
|
836
|
-
*
|
837
|
-
* UnpackError is throw when parse error is occured.
|
838
|
-
*/
|
839
|
-
static VALUE MessagePack_Unpacker_execute(VALUE self, VALUE data, VALUE off)
|
840
|
-
{
|
841
|
-
CHECK_STRING_TYPE(data);
|
842
|
-
return MessagePack_Unpacker_execute_impl(self, data,
|
843
|
-
(size_t)NUM2ULONG(off), (size_t)RSTRING_LEN(data));
|
844
|
-
}
|
845
|
-
|
846
|
-
/**
|
847
|
-
* Document-method: MessagePack::Unpacker#finished?
|
848
|
-
*
|
849
|
-
* call-seq:
|
850
|
-
* unpacker.finished?
|
851
|
-
*
|
852
|
-
* Returns true if an object is ready to get with data method.
|
853
|
-
*
|
854
|
-
* Use this method with execute method.
|
855
|
-
*/
|
856
|
-
static VALUE MessagePack_Unpacker_finished_p(VALUE self)
|
857
|
-
{
|
858
|
-
UNPACKER(self, mp);
|
859
|
-
if(mp->user.finished) {
|
860
|
-
return Qtrue;
|
861
|
-
}
|
862
|
-
return Qfalse;
|
863
|
-
}
|
864
|
-
|
865
|
-
/**
|
866
|
-
* Document-method: MessagePack::Unpacker#data
|
867
|
-
*
|
868
|
-
* call-seq:
|
869
|
-
* unpacker.data
|
870
|
-
*
|
871
|
-
* Gets the object deserialized by execute method.
|
872
|
-
*
|
873
|
-
* Use this method with execute method.
|
874
|
-
*/
|
875
|
-
static VALUE MessagePack_Unpacker_data(VALUE self)
|
876
|
-
{
|
877
|
-
UNPACKER(self, mp);
|
878
|
-
return template_data(mp);
|
879
|
-
}
|
880
|
-
|
881
|
-
/**
|
882
|
-
* Document-method: MessagePack::Unpacker#reset
|
883
|
-
*
|
884
|
-
* call-seq:
|
885
|
-
* unpacker.reset
|
886
|
-
*
|
887
|
-
* Resets the internal state of the unpacker.
|
888
|
-
*/
|
889
|
-
static VALUE MessagePack_Unpacker_reset(VALUE self)
|
890
|
-
{
|
891
|
-
UNPACKER(self, mp);
|
892
|
-
template_init(mp);
|
893
|
-
mp->user.finished = 0;
|
894
|
-
try_free_buffer(mp, 0);
|
895
|
-
return self;
|
896
|
-
}
|
897
|
-
|
898
|
-
|
899
|
-
void Init_msgpack_unpack(VALUE mMessagePack)
|
900
|
-
{
|
901
|
-
s_sysread = rb_intern("sysread");
|
902
|
-
s_readpartial = rb_intern("readpartial");
|
903
|
-
|
904
|
-
eUnpackError = rb_define_class_under(mMessagePack, "UnpackError", rb_eStandardError);
|
905
|
-
cUnpacker = rb_define_class_under(mMessagePack, "Unpacker", rb_cObject);
|
906
|
-
rb_define_alloc_func(cUnpacker, MessagePack_Unpacker_alloc);
|
907
|
-
|
908
|
-
rb_define_method(cUnpacker, "initialize", MessagePack_Unpacker_initialize, -1);
|
909
|
-
|
910
|
-
/* Buffered API */
|
911
|
-
rb_define_method(cUnpacker, "feed", MessagePack_Unpacker_feed, 1);
|
912
|
-
rb_define_method(cUnpacker, "fill", MessagePack_Unpacker_fill, 0);
|
913
|
-
rb_define_method(cUnpacker, "each", MessagePack_Unpacker_each, 0);
|
914
|
-
rb_define_method(cUnpacker, "stream", MessagePack_Unpacker_stream_get, 0);
|
915
|
-
rb_define_method(cUnpacker, "stream=", MessagePack_Unpacker_stream_set, 1);
|
916
|
-
rb_define_method(cUnpacker, "feed_each", MessagePack_Unpacker_feed_each, 1);
|
917
|
-
|
918
|
-
/* Unbuffered API */
|
919
|
-
rb_define_method(cUnpacker, "execute", MessagePack_Unpacker_execute, 2);
|
920
|
-
rb_define_method(cUnpacker, "execute_limit", MessagePack_Unpacker_execute_limit, 3);
|
921
|
-
rb_define_method(cUnpacker, "finished?", MessagePack_Unpacker_finished_p, 0);
|
922
|
-
rb_define_method(cUnpacker, "data", MessagePack_Unpacker_data, 0);
|
923
|
-
rb_define_method(cUnpacker, "reset", MessagePack_Unpacker_reset, 0);
|
924
|
-
|
925
|
-
/**
|
926
|
-
* MessagePack module is defined in rbinit.c file.
|
927
|
-
* mMessagePack = rb_define_module("MessagePack");
|
928
|
-
*/
|
929
|
-
rb_define_module_function(mMessagePack, "unpack", MessagePack_unpack, 1);
|
930
|
-
rb_define_module_function(mMessagePack, "unpack_limit", MessagePack_unpack_limit, 2);
|
931
|
-
}
|
932
|
-
|
933
|
-
/**
|
934
|
-
* Document-module: MessagePack::Unpacker
|
935
|
-
*
|
936
|
-
* Deserializer class that includes Buffered API and Unbuffered API.
|
937
|
-
*
|
938
|
-
*
|
939
|
-
* Buffered API uses the internal buffer of the Unpacker.
|
940
|
-
* Following code uses Buffered API with an input stream:
|
941
|
-
*
|
942
|
-
* # create an unpacker with input stream.
|
943
|
-
* pac = MessagePack::Unpacker.new(STDIN)
|
944
|
-
*
|
945
|
-
* # deserialize object one after another.
|
946
|
-
* pac.each {|obj|
|
947
|
-
* # ...
|
948
|
-
* }
|
949
|
-
*
|
950
|
-
*
|
951
|
-
* Following code doesn't use the input stream and feeds buffer
|
952
|
-
* manually. This is useful to use special stream or with
|
953
|
-
* event-driven I/O library.
|
954
|
-
*
|
955
|
-
* # create an unpacker without input stream.
|
956
|
-
* pac = MessagePack::Unpacker.new()
|
957
|
-
*
|
958
|
-
* # feed buffer to the internal buffer.
|
959
|
-
* pac.feed(input_bytes)
|
960
|
-
*
|
961
|
-
* # deserialize object one after another.
|
962
|
-
* pac.each {|obj|
|
963
|
-
* # ...
|
964
|
-
* }
|
965
|
-
*
|
966
|
-
*
|
967
|
-
* You can manage the buffer manually with the combination of
|
968
|
-
* *execute*, *finished?*, *data* and *reset* method.
|
969
|
-
*
|
970
|
-
* # create an unpacker.
|
971
|
-
* pac = MessagePack::Unpacker.new()
|
972
|
-
*
|
973
|
-
* # manage buffer and offset manually.
|
974
|
-
* offset = 0
|
975
|
-
* buffer = ''
|
976
|
-
*
|
977
|
-
* # read some data into the buffer.
|
978
|
-
* buffer << [1,2,3].to_msgpack
|
979
|
-
* buffer << [4,5,6].to_msgpack
|
980
|
-
*
|
981
|
-
* while true
|
982
|
-
* offset = pac.execute(buffer, offset)
|
983
|
-
*
|
984
|
-
* if pac.finished?
|
985
|
-
* obj = pac.data
|
986
|
-
*
|
987
|
-
* buffer.slice!(0, offset)
|
988
|
-
* offset = 0
|
989
|
-
* pac.reset
|
990
|
-
*
|
991
|
-
* # do something with the object
|
992
|
-
* # ...
|
993
|
-
*
|
994
|
-
* # repeat execution if there are more data.
|
995
|
-
* next unless buffer.empty?
|
996
|
-
* end
|
997
|
-
*
|
998
|
-
* break
|
999
|
-
* end
|
1000
|
-
*/
|
1001
|
-
|