packsnap 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. data/.gitignore +17 -0
  2. data/ChangeLog +29 -0
  3. data/README.rdoc +26 -0
  4. data/Rakefile +150 -0
  5. data/doclib/msgpack.rb +54 -0
  6. data/doclib/packsnap/buffer.rb +177 -0
  7. data/doclib/packsnap/error.rb +14 -0
  8. data/doclib/packsnap/packer.rb +131 -0
  9. data/doclib/packsnap/unpacker.rb +130 -0
  10. data/ext/packsnap/buffer.cc +684 -0
  11. data/ext/packsnap/buffer.hh +439 -0
  12. data/ext/packsnap/buffer_class.cc +490 -0
  13. data/ext/packsnap/buffer_class.hh +32 -0
  14. data/ext/packsnap/compat.h +128 -0
  15. data/ext/packsnap/extconf.rb +94 -0
  16. data/ext/packsnap/packer.cc +137 -0
  17. data/ext/packsnap/packer.h +334 -0
  18. data/ext/packsnap/packer_class.cc +288 -0
  19. data/ext/packsnap/packer_class.hh +32 -0
  20. data/ext/packsnap/packsnap.h +4 -0
  21. data/ext/packsnap/rbinit.cc +52 -0
  22. data/ext/packsnap/rmem.cc +110 -0
  23. data/ext/packsnap/rmem.h +100 -0
  24. data/ext/packsnap/sysdep.h +112 -0
  25. data/ext/packsnap/sysdep_endian.h +50 -0
  26. data/ext/packsnap/sysdep_types.h +46 -0
  27. data/ext/packsnap/unpacker.cc +654 -0
  28. data/ext/packsnap/unpacker.hh +108 -0
  29. data/ext/packsnap/unpacker_class.cc +392 -0
  30. data/ext/packsnap/unpacker_class.hh +32 -0
  31. data/lib/packsnap.rb +12 -0
  32. data/lib/packsnap/version.rb +3 -0
  33. data/packsnap.gemspec +23 -0
  34. data/spec/buffer_io_spec.rb +228 -0
  35. data/spec/buffer_spec.rb +572 -0
  36. data/spec/cases.json +1 -0
  37. data/spec/cases.msg +0 -0
  38. data/spec/cases_compact.msg +0 -0
  39. data/spec/cases_spec.rb +39 -0
  40. data/spec/format_spec.rb +225 -0
  41. data/spec/packer_spec.rb +127 -0
  42. data/spec/random_compat.rb +24 -0
  43. data/spec/spec_helper.rb +21 -0
  44. data/spec/unpacker_spec.rb +128 -0
  45. metadata +183 -0
@@ -0,0 +1,108 @@
1
+ /*
2
+ * MessagePack for Ruby
3
+ *
4
+ * Copyright (C) 2008-2012 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
+ #ifndef MSGPACK_RUBY_UNPACKER_H__
19
+ #define MSGPACK_RUBY_UNPACKER_H__
20
+
21
+ #include "buffer.hh"
22
+
23
+ #ifndef MSGPACK_UNPACKER_STACK_CAPACITY
24
+ #define MSGPACK_UNPACKER_STACK_CAPACITY 128
25
+ #endif
26
+
27
+ struct msgpack_unpacker_t;
28
+ typedef struct msgpack_unpacker_t msgpack_unpacker_t;
29
+
30
+ enum stack_type_t {
31
+ STACK_TYPE_ARRAY,
32
+ STACK_TYPE_MAP_KEY,
33
+ STACK_TYPE_MAP_VALUE,
34
+ };
35
+
36
+ typedef struct {
37
+ size_t count;
38
+ enum stack_type_t type;
39
+ VALUE object;
40
+ VALUE key;
41
+ } msgpack_unpacker_stack_t;
42
+
43
+ struct msgpack_unpacker_t {
44
+ msgpack_buffer_t buffer;
45
+
46
+ unsigned int head_byte;
47
+
48
+ msgpack_unpacker_stack_t* stack;
49
+ size_t stack_depth;
50
+ size_t stack_capacity;
51
+
52
+ VALUE last_object;
53
+
54
+ VALUE reading_raw;
55
+ size_t reading_raw_remaining;
56
+
57
+ VALUE buffer_ref;
58
+ };
59
+
60
+ #define UNPACKER_BUFFER_(uk) (&(uk)->buffer)
61
+
62
+ enum msgpack_unpacker_object_type {
63
+ TYPE_NIL = 0,
64
+ TYPE_BOOLEAN,
65
+ TYPE_INTEGER,
66
+ TYPE_FLOAT,
67
+ TYPE_RAW,
68
+ TYPE_ARRAY,
69
+ TYPE_MAP,
70
+ };
71
+
72
+ void msgpack_unpacker_init(msgpack_unpacker_t* uk);
73
+
74
+ void msgpack_unpacker_destroy(msgpack_unpacker_t* uk);
75
+
76
+ void msgpack_unpacker_mark(msgpack_unpacker_t* uk);
77
+
78
+ void msgpack_unpacker_reset(msgpack_unpacker_t* uk);
79
+
80
+
81
+ /* error codes */
82
+ #define PRIMITIVE_CONTAINER_START 1
83
+ #define PRIMITIVE_OBJECT_COMPLETE 0
84
+ #define PRIMITIVE_EOF -1
85
+ #define PRIMITIVE_INVALID_BYTE -2
86
+ #define PRIMITIVE_STACK_TOO_DEEP -3
87
+ #define PRIMITIVE_UNEXPECTED_TYPE -4
88
+
89
+ int msgpack_unpacker_read(msgpack_unpacker_t* uk, size_t target_stack_depth);
90
+
91
+ int msgpack_unpacker_skip(msgpack_unpacker_t* uk, size_t target_stack_depth);
92
+
93
+ static inline VALUE msgpack_unpacker_get_last_object(msgpack_unpacker_t* uk)
94
+ {
95
+ return uk->last_object;
96
+ }
97
+
98
+
99
+ int msgpack_unpacker_peek_next_object_type(msgpack_unpacker_t* uk);
100
+
101
+ int msgpack_unpacker_skip_nil(msgpack_unpacker_t* uk);
102
+
103
+ int msgpack_unpacker_read_array_header(msgpack_unpacker_t* uk, uint32_t* result_size);
104
+
105
+ int msgpack_unpacker_read_map_header(msgpack_unpacker_t* uk, uint32_t* result_size);
106
+
107
+ #endif
108
+
@@ -0,0 +1,392 @@
1
+ /*
2
+ * MessagePack for Ruby
3
+ *
4
+ * Copyright (C) 2008-2012 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
+
19
+ #include "packsnap.h"
20
+ #include "snappy.h"
21
+ #include "unpacker.hh"
22
+ #include "unpacker_class.hh"
23
+ #include "buffer_class.hh"
24
+
25
+ VALUE cMessagePack_Unpacker;
26
+
27
+ static VALUE s_unpacker_value;
28
+ static msgpack_unpacker_t* s_unpacker;
29
+
30
+ static VALUE eUnpackError;
31
+ static VALUE eMalformedFormatError;
32
+ static VALUE eStackError;
33
+ static VALUE eTypeError;
34
+
35
+ #define UNPACKER(from, name) \
36
+ msgpack_unpacker_t *name = NULL; \
37
+ Data_Get_Struct(from, msgpack_unpacker_t, name); \
38
+ if(name == NULL) { \
39
+ rb_raise(rb_eArgError, "NULL found for " # name " when shouldn't be."); \
40
+ }
41
+
42
+ static void Unpacker_free(msgpack_unpacker_t* uk)
43
+ {
44
+ if(uk == NULL) {
45
+ return;
46
+ }
47
+ msgpack_unpacker_destroy(uk);
48
+ free(uk);
49
+ }
50
+
51
+ static VALUE Unpacker_alloc(VALUE klass)
52
+ {
53
+ msgpack_unpacker_t* uk = ALLOC_N(msgpack_unpacker_t, 1);
54
+ msgpack_unpacker_init(uk);
55
+
56
+ VALUE self = Data_Wrap_Struct(klass, msgpack_unpacker_mark, Unpacker_free, uk);
57
+
58
+ uk->buffer_ref = MessagePack_Buffer_wrap(UNPACKER_BUFFER_(uk), self);
59
+
60
+ return self;
61
+ }
62
+
63
+ static VALUE Unpacker_initialize(int argc, VALUE* argv, VALUE self)
64
+ {
65
+ VALUE io = Qnil;
66
+ VALUE options = Qnil;
67
+
68
+ if(argc == 0 || (argc == 1 && argv[0] == Qnil)) {
69
+ /* Qnil */
70
+
71
+ } else if(argc == 1) {
72
+ VALUE v = argv[0];
73
+ if(rb_type(v) == T_HASH) {
74
+ options = v;
75
+ } else {
76
+ io = v;
77
+ }
78
+
79
+ } else if(argc == 2) {
80
+ io = argv[0];
81
+ options = argv[1];
82
+ if(rb_type(options) != T_HASH) {
83
+ rb_raise(rb_eArgError, "expected Hash but found %s.", rb_obj_classname(io));
84
+ }
85
+
86
+ } else {
87
+ rb_raise(rb_eArgError, "wrong number of arguments (%d for 0..1)", argc);
88
+ }
89
+
90
+ UNPACKER(self, uk);
91
+ if(io != Qnil || options != Qnil) {
92
+ MessagePack_Buffer_initialize(UNPACKER_BUFFER_(uk), io, options);
93
+ }
94
+
95
+ // TODO options
96
+
97
+ return self;
98
+ }
99
+
100
+ static void raise_unpacker_error(int r)
101
+ {
102
+ switch(r) {
103
+ case PRIMITIVE_EOF:
104
+ rb_raise(rb_eEOFError, "end of buffer reached");
105
+ case PRIMITIVE_INVALID_BYTE:
106
+ rb_raise(eMalformedFormatError, "invalid byte");
107
+ case PRIMITIVE_STACK_TOO_DEEP:
108
+ rb_raise(eStackError, "stack level too deep");
109
+ case PRIMITIVE_UNEXPECTED_TYPE:
110
+ rb_raise(eTypeError, "unexpected type");
111
+ default:
112
+ rb_raise(eUnpackError, "logically unknown error %d", r);
113
+ }
114
+ }
115
+
116
+ static VALUE Unpacker_buffer(VALUE self)
117
+ {
118
+ UNPACKER(self, uk);
119
+ return uk->buffer_ref;
120
+ }
121
+
122
+ static VALUE Unpacker_read(VALUE self)
123
+ {
124
+ UNPACKER(self, uk);
125
+
126
+ int r = msgpack_unpacker_read(uk, 0);
127
+ if(r < 0) {
128
+ raise_unpacker_error(r);
129
+ }
130
+
131
+ return msgpack_unpacker_get_last_object(uk);
132
+ }
133
+
134
+ static VALUE Unpacker_skip(VALUE self)
135
+ {
136
+ UNPACKER(self, uk);
137
+
138
+ int r = msgpack_unpacker_skip(uk, 0);
139
+ if(r < 0) {
140
+ raise_unpacker_error(r);
141
+ }
142
+
143
+ return Qnil;
144
+ }
145
+
146
+ static VALUE Unpacker_skip_nil(VALUE self)
147
+ {
148
+ UNPACKER(self, uk);
149
+
150
+ int r = msgpack_unpacker_skip_nil(uk);
151
+ if(r < 0) {
152
+ raise_unpacker_error(r);
153
+ }
154
+
155
+ if(r) {
156
+ return Qtrue;
157
+ }
158
+ return Qfalse;
159
+ }
160
+
161
+ static VALUE Unpacker_read_array_header(VALUE self)
162
+ {
163
+ UNPACKER(self, uk);
164
+
165
+ uint32_t size;
166
+ int r = msgpack_unpacker_read_array_header(uk, &size);
167
+ if(r < 0) {
168
+ raise_unpacker_error(r);
169
+ }
170
+
171
+ return ULONG2NUM(size);
172
+ }
173
+
174
+ static VALUE Unpacker_read_map_header(VALUE self)
175
+ {
176
+ UNPACKER(self, uk);
177
+
178
+ uint32_t size;
179
+ int r = msgpack_unpacker_read_map_header(uk, &size);
180
+ if(r < 0) {
181
+ raise_unpacker_error((int)r);
182
+ }
183
+
184
+ return ULONG2NUM(size);
185
+ }
186
+
187
+ static VALUE Unpacker_peek_next_type(VALUE self)
188
+ {
189
+ UNPACKER(self, uk);
190
+
191
+ int r = msgpack_unpacker_peek_next_object_type(uk);
192
+ if(r < 0) {
193
+ raise_unpacker_error(r);
194
+ }
195
+
196
+ switch((enum msgpack_unpacker_object_type) r) {
197
+ case TYPE_NIL:
198
+ return rb_intern("nil");
199
+ case TYPE_BOOLEAN:
200
+ return rb_intern("boolean");
201
+ case TYPE_INTEGER:
202
+ return rb_intern("integer");
203
+ case TYPE_FLOAT:
204
+ return rb_intern("float");
205
+ case TYPE_RAW:
206
+ return rb_intern("raw");
207
+ case TYPE_ARRAY:
208
+ return rb_intern("array");
209
+ case TYPE_MAP:
210
+ return rb_intern("map");
211
+ default:
212
+ rb_raise(eUnpackError, "logically unknown type %d", r);
213
+ }
214
+ }
215
+
216
+ static VALUE Unpacker_feed(VALUE self, VALUE data)
217
+ {
218
+ UNPACKER(self, uk);
219
+
220
+ StringValue(data);
221
+
222
+ msgpack_buffer_append_string(UNPACKER_BUFFER_(uk), data);
223
+
224
+ return self;
225
+ }
226
+
227
+ static VALUE Unpacker_each_impl(VALUE self)
228
+ {
229
+ UNPACKER(self, uk);
230
+
231
+ while(true) {
232
+ int r = msgpack_unpacker_read(uk, 0);
233
+ if(r < 0) {
234
+ if(r == PRIMITIVE_EOF) {
235
+ return Qnil;
236
+ }
237
+ raise_unpacker_error(r);
238
+ }
239
+ rb_yield(msgpack_unpacker_get_last_object(uk));
240
+ }
241
+ }
242
+
243
+ static VALUE Unpacker_rescue_EOFError(VALUE self)
244
+ {
245
+ UNUSED(self);
246
+ return Qnil;
247
+ }
248
+
249
+ static VALUE Unpacker_each(VALUE self)
250
+ {
251
+ UNPACKER(self, uk);
252
+
253
+ #ifdef RETURN_ENUMERATOR
254
+ RETURN_ENUMERATOR(self, 0, 0);
255
+ #endif
256
+
257
+ if(msgpack_buffer_has_io(UNPACKER_BUFFER_(uk))) {
258
+ return Unpacker_each_impl(self);
259
+ } else {
260
+ /* rescue EOFError only if io is set */
261
+ return rb_rescue2((VALUE (*)(...))Unpacker_each_impl, self,
262
+ (VALUE (*)(...))Unpacker_rescue_EOFError, self,
263
+ rb_eEOFError, NULL);
264
+ }
265
+ }
266
+
267
+ static VALUE Unpacker_feed_each(VALUE self, VALUE data)
268
+ {
269
+ // TODO optimize
270
+ Unpacker_feed(self, data);
271
+ return Unpacker_each(self);
272
+ }
273
+
274
+ static VALUE
275
+ _unsnappify(VALUE src)
276
+ {
277
+ VALUE dst;
278
+ size_t output_length;
279
+
280
+ if (!snappy::GetUncompressedLength(RSTRING_PTR(src), RSTRING_LEN(src), &output_length)) {
281
+ rb_raise(rb_ePacksnap, "packsnap::GetUncompressedLength");
282
+ }
283
+
284
+ dst = rb_str_new(NULL, output_length);
285
+
286
+ if (!snappy::RawUncompress(RSTRING_PTR(src), RSTRING_LEN(src), RSTRING_PTR(dst))) {
287
+ rb_raise(rb_ePacksnap, "packsnap::RawUncompress");
288
+ }
289
+
290
+ return dst;
291
+ }
292
+
293
+ VALUE MessagePack_unpack(int argc, VALUE* argv)
294
+ {
295
+ VALUE src;
296
+
297
+ switch(argc) {
298
+ case 1:
299
+ src = argv[0];
300
+ break;
301
+ default:
302
+ rb_raise(rb_eArgError, "wrong number of arguments (%d for 1)", argc);
303
+ }
304
+
305
+ VALUE io = Qnil;
306
+ if(rb_type(src) != T_STRING) {
307
+ io = src;
308
+ src = Qnil;
309
+ }
310
+
311
+ if (src != Qnil) {
312
+ src = _unsnappify(src);
313
+ }
314
+
315
+ // TODO create an instance if io is set?; thread safety
316
+ //VALUE self = Unpacker_alloc(cMessagePack_Unpacker);
317
+ //UNPACKER(self, uk);
318
+ msgpack_unpacker_reset(s_unpacker);
319
+ msgpack_buffer_reset_io(UNPACKER_BUFFER_(s_unpacker));
320
+
321
+ if(io != Qnil) {
322
+ MessagePack_Buffer_initialize(UNPACKER_BUFFER_(s_unpacker), io, Qnil);
323
+ }
324
+
325
+ if(src != Qnil) {
326
+ // TODO prefer zero-copy?
327
+ msgpack_buffer_append_string(UNPACKER_BUFFER_(s_unpacker), src);
328
+ }
329
+
330
+ int r = msgpack_unpacker_read(s_unpacker, 0);
331
+ if(r < 0) {
332
+ raise_unpacker_error(r);
333
+ }
334
+
335
+ /* raise if extra bytes follow */
336
+ if(msgpack_buffer_top_readable_size(UNPACKER_BUFFER_(s_unpacker)) > 0) {
337
+ rb_raise(eMalformedFormatError, "extra bytes follow after a deserialized object");
338
+ }
339
+
340
+ return msgpack_unpacker_get_last_object(s_unpacker);
341
+ }
342
+
343
+ static VALUE MessagePack_load_module_method(int argc, VALUE* argv, VALUE mod)
344
+ {
345
+ UNUSED(mod);
346
+ return MessagePack_unpack(argc, argv);
347
+ }
348
+
349
+ static VALUE MessagePack_unpack_module_method(int argc, VALUE* argv, VALUE mod)
350
+ {
351
+ UNUSED(mod);
352
+ return MessagePack_unpack(argc, argv);
353
+ }
354
+
355
+ extern "C"
356
+ void MessagePack_Unpacker_module_init(VALUE mMessagePack)
357
+ {
358
+ cMessagePack_Unpacker = rb_define_class_under(mMessagePack, "Unpacker", rb_cObject);
359
+
360
+ eUnpackError = rb_define_class_under(mMessagePack, "UnpackError", rb_eStandardError);
361
+
362
+ eMalformedFormatError = rb_define_class_under(mMessagePack, "MalformedFormatError", eUnpackError);
363
+
364
+ eStackError = rb_define_class_under(mMessagePack, "StackError", eUnpackError);
365
+
366
+ eTypeError = rb_define_class_under(mMessagePack, "TypeError", rb_eStandardError);
367
+
368
+ rb_define_alloc_func(cMessagePack_Unpacker, Unpacker_alloc);
369
+
370
+ rb_define_method(cMessagePack_Unpacker, "initialize", (VALUE (*)(...))Unpacker_initialize, -1);
371
+ rb_define_method(cMessagePack_Unpacker, "buffer", (VALUE (*)(...))Unpacker_buffer, 0);
372
+ rb_define_method(cMessagePack_Unpacker, "read", (VALUE (*)(...))Unpacker_read, 0);
373
+ rb_define_alias(cMessagePack_Unpacker, "unpack", "read");
374
+ rb_define_method(cMessagePack_Unpacker, "skip", (VALUE (*)(...))Unpacker_skip, 0);
375
+ rb_define_method(cMessagePack_Unpacker, "skip_nil", (VALUE (*)(...))Unpacker_skip_nil, 0);
376
+ rb_define_method(cMessagePack_Unpacker, "read_array_header", (VALUE (*)(...))Unpacker_read_array_header, 0);
377
+ rb_define_method(cMessagePack_Unpacker, "read_map_header", (VALUE (*)(...))Unpacker_read_map_header, 0);
378
+ //rb_define_method(cMessagePack_Unpacker, "peek_next_type", Unpacker_peek_next_type, 0);
379
+ rb_define_method(cMessagePack_Unpacker, "feed", (VALUE (*)(...))Unpacker_feed, 1);
380
+ rb_define_method(cMessagePack_Unpacker, "each", (VALUE (*)(...))Unpacker_each, 0);
381
+ rb_define_method(cMessagePack_Unpacker, "feed_each", (VALUE (*)(...))Unpacker_feed_each, 1);
382
+
383
+ s_unpacker_value = Unpacker_alloc(cMessagePack_Unpacker);
384
+ rb_gc_register_address(&s_unpacker_value);
385
+ Data_Get_Struct(s_unpacker_value, msgpack_unpacker_t, s_unpacker);
386
+ msgpack_buffer_set_write_reference_threshold(UNPACKER_BUFFER_(s_unpacker), 0); /* always prefer reference */
387
+
388
+ /* MessagePack.unpack(x) */
389
+ rb_define_module_function(mMessagePack, "load", (VALUE (*)(...))MessagePack_load_module_method, -1);
390
+ rb_define_module_function(mMessagePack, "unpack", (VALUE (*)(...))MessagePack_unpack_module_method, -1);
391
+ }
392
+