mochilo 1.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.
@@ -0,0 +1,119 @@
1
+ /*
2
+ * Copyright (c) 2012, GitHub, Inc
3
+ *
4
+ * Permission to use, copy, modify, and distribute this software for any
5
+ * purpose with or without fee is hereby granted, provided that the above
6
+ * copyright notice and this permission notice appear in all copies.
7
+ *
8
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15
+ */
16
+ #include <stdio.h>
17
+ #include "mochilo.h"
18
+
19
+ #define CSTR2SYM(s) (ID2SYM(rb_intern((s))))
20
+
21
+ static VALUE rb_mMochilo;
22
+ static VALUE rb_eMochiloError;
23
+ VALUE rb_eMochiloPackError;
24
+ VALUE rb_eMochiloUnpackError;
25
+
26
+ extern void mochilo_pack_one(mochilo_buf *buf, VALUE rb_object, int trusted);
27
+
28
+ static VALUE rb_mochilo__unpack(VALUE rb_buffer, int trusted)
29
+ {
30
+ VALUE rb_result;
31
+ int error = -1;
32
+ mochilo_src source;
33
+
34
+ Check_Type(rb_buffer, T_STRING);
35
+
36
+ source.ptr = RSTRING_PTR(rb_buffer);
37
+ source.end = source.ptr + RSTRING_LEN(rb_buffer);
38
+ source.trusted = trusted;
39
+
40
+ error = mochilo_unpack_one((mo_value)&rb_result, &source);
41
+ if (error < 0)
42
+ rb_raise(rb_eMochiloUnpackError, "unpack failed (%d)", error);
43
+
44
+ return rb_result;
45
+ }
46
+
47
+ /* Document-method: unpack
48
+ *
49
+ * call-seq:
50
+ * Mochilo.unpack(banana_pack_str) -> Object
51
+ *
52
+ * Unpacks a BananaPack stream into a Ruby object.
53
+ */
54
+ static VALUE rb_mochilo_unpack(VALUE self, VALUE rb_buffer)
55
+ {
56
+ return rb_mochilo__unpack(rb_buffer, 0);
57
+ }
58
+
59
+ /* Document-method: unpack_unsafe
60
+ *
61
+ * call-seq:
62
+ * Mochilo.unpack_unsafe(banana_pack_str) -> Object
63
+ *
64
+ * Unpacks a BananaPack stream into a Ruby object, in unsafe mode.
65
+ * Only use this function if +banana_pack_str+ is trusted; otherwise
66
+ * symbol DoS attacks are possible.
67
+ */
68
+ static VALUE rb_mochilo_unpack_unsafe(VALUE self, VALUE rb_buffer)
69
+ {
70
+ return rb_mochilo__unpack(rb_buffer, 1);
71
+ }
72
+
73
+ /* Document-method: pack
74
+ *
75
+ * call-seq:
76
+ * Mochilo.pack(obj) -> String
77
+ *
78
+ * Packs a Ruby object into BananaPack format.
79
+ */
80
+ static VALUE rb_mochilo_pack(VALUE self, VALUE rb_obj)
81
+ {
82
+ mochilo_buf buf;
83
+
84
+ mochilo_buf_init(&buf);
85
+ mochilo_pack_one(&buf, rb_obj, 0);
86
+ return mochilo_buf_flush(&buf);
87
+ }
88
+
89
+ /* Document-method: pack
90
+ *
91
+ * call-seq:
92
+ * Mochilo.pack_unsafe(obj) -> String
93
+ *
94
+ * Packs a Ruby object into BananaPack format, in unsafe mode.
95
+ * This enables the Symbol type durring serialization and will
96
+ * have to be deserialized in unsafe mode as well.
97
+ */
98
+ static VALUE rb_mochilo_pack_unsafe(VALUE self, VALUE rb_obj)
99
+ {
100
+ mochilo_buf buf;
101
+
102
+ mochilo_buf_init(&buf);
103
+ mochilo_pack_one(&buf, rb_obj, 1);
104
+ return mochilo_buf_flush(&buf);
105
+ }
106
+
107
+ void Init_mochilo()
108
+ {
109
+ rb_mMochilo = rb_define_module("Mochilo");
110
+ rb_define_method(rb_mMochilo, "unpack", rb_mochilo_unpack, 1);
111
+ rb_define_method(rb_mMochilo, "unpack_unsafe", rb_mochilo_unpack_unsafe, 1);
112
+ rb_define_method(rb_mMochilo, "pack", rb_mochilo_pack, 1);
113
+ rb_define_method(rb_mMochilo, "pack_unsafe", rb_mochilo_pack_unsafe, 1);
114
+
115
+ rb_eMochiloError = rb_define_class_under(rb_mMochilo, "Error", rb_eStandardError);
116
+ rb_eMochiloPackError = rb_define_class_under(rb_mMochilo, "PackError", rb_eMochiloError);
117
+ rb_eMochiloUnpackError = rb_define_class_under(rb_mMochilo, "UnpackError", rb_eMochiloError);
118
+ }
119
+
@@ -0,0 +1,91 @@
1
+
2
+ MOAPI mo_value moapi_bytes_new(const char *src, size_t len)
3
+ {
4
+ return (mo_value)rb_str_new(src, len);
5
+ }
6
+
7
+ MOAPI mo_value moapi_sym_new(const char *src, size_t len)
8
+ {
9
+ char *symbol;
10
+
11
+ if (len > 0xFF)
12
+ rb_raise(rb_eArgError, "Symbol too long to encode in BananaPack");
13
+
14
+ symbol = alloca(len + 1);
15
+ memcpy(symbol, src, len);
16
+ symbol[len] = '\0';
17
+
18
+ return (mo_value)ID2SYM(rb_intern(symbol));
19
+ }
20
+
21
+ #ifdef HAVE_RUBY_ENCODING_H
22
+ MOAPI mo_value moapi_str_new(const char *src, size_t len, enum msgpack_enc_t encoding)
23
+ {
24
+ int index = 0;
25
+ VALUE str;
26
+
27
+ if (encoding < sizeof(mochilo_enc_lookup)/sizeof(mochilo_enc_lookup[0]))
28
+ index = rb_enc_find_index(mochilo_enc_lookup[encoding]);
29
+
30
+ str = rb_str_new(src, len);
31
+ rb_enc_set_index(str, index);
32
+
33
+ return (mo_value)str;
34
+ }
35
+ #endif
36
+
37
+ MOAPI mo_value moapi_array_new(size_t array_size)
38
+ {
39
+ return (mo_value)rb_ary_new2(array_size);
40
+ }
41
+
42
+ MOAPI void moapi_array_append(mo_value array, mo_value element)
43
+ {
44
+ rb_ary_push((VALUE)array, (VALUE)element);
45
+ }
46
+
47
+ MOAPI mo_value moapi_hash_new(void)
48
+ {
49
+ return (mo_value)rb_hash_new();
50
+ }
51
+
52
+ MOAPI void moapi_hash_set(mo_value hash, mo_value key, mo_value val)
53
+ {
54
+ rb_hash_aset((VALUE)hash, (VALUE)key, (VALUE)val);
55
+ }
56
+
57
+ MOAPI mo_value moapi_uint64_new(uint64_t value)
58
+ {
59
+ return (mo_value)rb_ull2inum((long long)value);
60
+ }
61
+
62
+ MOAPI mo_value moapi_int64_new(int64_t value)
63
+ {
64
+ return (mo_value)rb_ll2inum(value);
65
+ }
66
+
67
+ MOAPI mo_value moapi_atom_new(enum msgpack_t type)
68
+ {
69
+ switch (type) {
70
+ case MSGPACK_T_NIL: return (mo_value)Qnil;
71
+ case MSGPACK_T_TRUE: return (mo_value)Qtrue;
72
+ case MSGPACK_T_FALSE: return (mo_value)Qfalse;
73
+ default: return NULL;
74
+ }
75
+ }
76
+
77
+ MOAPI mo_value moapi_double_new(double d)
78
+ {
79
+ return (mo_value)rb_float_new(d);
80
+ }
81
+
82
+
83
+ #define moapi_uint8_new(n) (mo_value)INT2FIX((int)n)
84
+ #define moapi_uint16_new(n) (mo_value)INT2FIX((int)n)
85
+ #define moapi_uint32_new(n) (mo_value)ULONG2NUM((unsigned long)n)
86
+
87
+ #define moapi_int8_new(n) (mo_value)INT2FIX((int)n)
88
+ #define moapi_int16_new(n) (mo_value)INT2FIX((int)n)
89
+ #define moapi_int32_new(n) (mo_value)LONG2FIX((long)n)
90
+
91
+ #define moapi_float_new moapi_double_new
@@ -0,0 +1,331 @@
1
+ #include <stdint.h>
2
+ #include <stdlib.h>
3
+ #include <stdio.h>
4
+ #include <string.h>
5
+
6
+ #include "mochilo.h"
7
+
8
+ extern VALUE rb_eMochiloPackError;
9
+
10
+ void mochilo_pack_one(mochilo_buf *buf, VALUE rb_object, int trusted);
11
+
12
+ void mochilo_pack_fixnum(mochilo_buf *buf, VALUE rb_fixnum)
13
+ {
14
+ long fixnum = NUM2LONG(rb_fixnum);
15
+
16
+ if (fixnum < -0x20L) {
17
+ if (fixnum < -0x8000L) {
18
+ if (sizeof(long) > 4 && fixnum < -0x80000000L) {
19
+ mochilo_buf_putc(buf, MSGPACK_T_INT64);
20
+ mochilo_buf_put64be(buf, &fixnum);
21
+ } else {
22
+ int32_t fixnum32 = (int32_t)fixnum;
23
+ mochilo_buf_putc(buf, MSGPACK_T_INT32);
24
+ mochilo_buf_put32be(buf, &fixnum32);
25
+ }
26
+ } else {
27
+ if (fixnum < -0x80L) {
28
+ int16_t fixnum16 = (int16_t)fixnum;
29
+ mochilo_buf_putc(buf, MSGPACK_T_INT16);
30
+ mochilo_buf_put16be(buf, &fixnum16);
31
+ } else {
32
+ mochilo_buf_putc(buf, MSGPACK_T_INT8);
33
+ mochilo_buf_putc(buf, (int8_t)fixnum);
34
+ }
35
+ }
36
+ } else if (fixnum <= 0x7fL) {
37
+ mochilo_buf_putc(buf, (uint8_t)fixnum);
38
+ } else {
39
+ if (fixnum <= 0xffffL) {
40
+ if (fixnum <= 0xffL) {
41
+ mochilo_buf_putc(buf, MSGPACK_T_UINT8);
42
+ mochilo_buf_putc(buf, (uint8_t)fixnum);
43
+ } else {
44
+ uint16_t fixnum16 = (uint16_t)fixnum;
45
+ mochilo_buf_putc(buf, MSGPACK_T_UINT16);
46
+ mochilo_buf_put16be(buf, &fixnum16);
47
+ }
48
+ } else {
49
+ if (fixnum <= 0xffffffffL) {
50
+ uint32_t fixnum32 = (uint32_t)fixnum;
51
+ mochilo_buf_putc(buf, MSGPACK_T_UINT32);
52
+ mochilo_buf_put32be(buf, &fixnum32);
53
+ } else if (sizeof(long) > 4) {
54
+ mochilo_buf_putc(buf, MSGPACK_T_UINT64);
55
+ mochilo_buf_put64be(buf, &fixnum);
56
+ }
57
+ }
58
+ }
59
+ }
60
+
61
+ void mochilo_pack_bignum(mochilo_buf *buf, VALUE rb_bignum)
62
+ {
63
+ if (RBIGNUM_POSITIVE_P(rb_bignum)) {
64
+ uint64_t bignum = rb_big2ull(rb_bignum);
65
+
66
+ mochilo_buf_putc(buf, MSGPACK_T_UINT64);
67
+ mochilo_buf_put64be(buf, &bignum);
68
+ } else {
69
+ int64_t bignum = rb_big2ll(rb_bignum);
70
+
71
+ mochilo_buf_putc(buf, MSGPACK_T_INT64);
72
+ mochilo_buf_put64be(buf, &bignum);
73
+ }
74
+ }
75
+
76
+ struct mochilo_hash_pack {
77
+ mochilo_buf *buf;
78
+ int trusted;
79
+ };
80
+
81
+ static int hash_callback(VALUE key, VALUE val, VALUE opaque)
82
+ {
83
+ struct mochilo_hash_pack *hash_pack = (struct mochilo_hash_pack*)opaque;
84
+ mochilo_pack_one(hash_pack->buf, key, hash_pack->trusted);
85
+ mochilo_pack_one(hash_pack->buf, val, hash_pack->trusted);
86
+ return 0;
87
+ }
88
+
89
+ void mochilo_pack_double(mochilo_buf *buf, VALUE rb_double)
90
+ {
91
+ double d = RFLOAT_VALUE(rb_double);
92
+ mochilo_buf_putc(buf, MSGPACK_T_DOUBLE);
93
+ mochilo_buf_put64be(buf, &d);
94
+ }
95
+
96
+ void mochilo_pack_hash(mochilo_buf *buf, VALUE rb_hash, int trusted)
97
+ {
98
+ struct mochilo_hash_pack hash_pack;
99
+ long size = RHASH_SIZE(rb_hash);
100
+
101
+ hash_pack.buf = buf;
102
+ hash_pack.trusted = trusted;
103
+
104
+ if (size < 0x10) {
105
+ uint8_t lead = 0x80 | size;
106
+ mochilo_buf_putc(buf, lead);
107
+ }
108
+
109
+ else if (size < 0x10000) {
110
+ uint16_t lead = size;
111
+ mochilo_buf_putc(buf, MSGPACK_T_MAP16);
112
+ mochilo_buf_put16be(buf, &lead);
113
+ }
114
+
115
+ else {
116
+ mochilo_buf_putc(buf, MSGPACK_T_MAP32);
117
+ mochilo_buf_put32be(buf, &size);
118
+ }
119
+
120
+ rb_hash_foreach(rb_hash, &hash_callback, (VALUE)&hash_pack);
121
+ }
122
+
123
+ void mochilo_pack_bytes(mochilo_buf *buf, VALUE rb_bytes)
124
+ {
125
+ long size = RSTRING_LEN(rb_bytes);
126
+
127
+ if (size < 0x20) {
128
+ uint8_t lead = 0xA0 | size;
129
+ mochilo_buf_putc(buf, lead);
130
+ }
131
+
132
+ else if (size < 0x10000) {
133
+ uint16_t lead = size;
134
+ mochilo_buf_putc(buf, MSGPACK_T_RAW16);
135
+ mochilo_buf_put16be(buf, &lead);
136
+ }
137
+
138
+ else {
139
+ mochilo_buf_putc(buf, MSGPACK_T_RAW32);
140
+ mochilo_buf_put32be(buf, &size);
141
+ }
142
+
143
+ mochilo_buf_put(buf, RSTRING_PTR(rb_bytes), size);
144
+ }
145
+
146
+ void mochilo_pack_symbol(mochilo_buf *buf, VALUE rb_symbol)
147
+ {
148
+ long size;
149
+ const char *name;
150
+
151
+ name = rb_id2name(SYM2ID(rb_symbol));
152
+ size = strlen(name);
153
+
154
+ if (size < 0x100) {
155
+ uint8_t lead = size;
156
+ mochilo_buf_putc(buf, MSGPACK_T_SYM);
157
+ mochilo_buf_putc(buf, lead);
158
+ } else {
159
+ rb_raise(rb_eMochiloPackError,
160
+ "Symbol too long: must be under %d bytes, %ld given", 0x100, size);
161
+ }
162
+
163
+ mochilo_buf_put(buf, name, size);
164
+ }
165
+
166
+ #ifdef HAVE_RUBY_ENCODING_H
167
+ void mochilo_pack_str(mochilo_buf *buf, VALUE rb_str)
168
+ {
169
+ long size = RSTRING_LEN(rb_str);
170
+ rb_encoding *encoding;
171
+
172
+ const struct mochilo_enc_map *enc2id;
173
+ const char *enc_name;
174
+
175
+ if (size < 0x10000) {
176
+ uint16_t lead = size;
177
+ mochilo_buf_putc(buf, MSGPACK_T_STR16);
178
+ mochilo_buf_put16be(buf, &lead);
179
+ }
180
+
181
+ else {
182
+ mochilo_buf_putc(buf, MSGPACK_T_STR32);
183
+ mochilo_buf_put32be(buf, &size);
184
+ }
185
+
186
+ encoding = rb_enc_get(rb_str);
187
+ enc_name = rb_enc_name(encoding);
188
+ enc2id = mochilo_encoding_to_id(enc_name, (unsigned int)strlen(enc_name));
189
+
190
+ mochilo_buf_putc(buf, enc2id ? enc2id->id : 0);
191
+ mochilo_buf_put(buf, RSTRING_PTR(rb_str), size);
192
+ }
193
+ #endif
194
+
195
+ void mochilo_pack_array(mochilo_buf *buf, VALUE rb_array, int trusted)
196
+ {
197
+ long i, size = RARRAY_LEN(rb_array);
198
+
199
+ if (size < 0x10) {
200
+ uint8_t lead = 0x90 | size;
201
+ mochilo_buf_putc(buf, lead);
202
+ }
203
+
204
+ else if (size < 0x10000) {
205
+ uint16_t lead = size;
206
+ mochilo_buf_putc(buf, MSGPACK_T_ARRAY16);
207
+ mochilo_buf_put16be(buf, &lead);
208
+ }
209
+
210
+ else {
211
+ mochilo_buf_putc(buf, MSGPACK_T_ARRAY32);
212
+ mochilo_buf_put32be(buf, &size);
213
+ }
214
+
215
+ for (i = 0; i < size; i++) {
216
+ mochilo_pack_one(buf, rb_ary_entry(rb_array, i), trusted);
217
+ }
218
+ }
219
+
220
+ void mochilo_pack_one(mochilo_buf *buf, VALUE rb_object, int trusted)
221
+ {
222
+ #ifndef RUBINIUS
223
+ if (rb_object == Qnil) {
224
+ mochilo_buf_putc(buf, MSGPACK_T_NIL);
225
+ }
226
+ else if (rb_object == Qtrue) {
227
+ mochilo_buf_putc(buf, MSGPACK_T_TRUE);
228
+ }
229
+ else if (rb_object == Qfalse) {
230
+ mochilo_buf_putc(buf, MSGPACK_T_FALSE);
231
+ }
232
+ else if (FIXNUM_P(rb_object)) {
233
+ mochilo_pack_fixnum(buf, rb_object);
234
+ }
235
+ else if (SYMBOL_P(rb_object)) {
236
+ if (trusted)
237
+ mochilo_pack_symbol(buf, rb_object);
238
+ else
239
+ mochilo_pack_str(buf, rb_obj_as_string(rb_object));
240
+ }
241
+ else {
242
+ switch (BUILTIN_TYPE(rb_object)) {
243
+ case T_STRING:
244
+ #ifdef HAVE_RUBY_ENCODING_H
245
+ if (ENCODING_GET(rb_object) != 0)
246
+ mochilo_pack_str(buf, rb_object);
247
+ else
248
+ #endif
249
+ mochilo_pack_bytes(buf, rb_object);
250
+ return;
251
+
252
+ case T_HASH:
253
+ mochilo_pack_hash(buf, rb_object, trusted);
254
+ return;
255
+
256
+ case T_ARRAY:
257
+ mochilo_pack_array(buf, rb_object, trusted);
258
+ return;
259
+
260
+ case T_FLOAT:
261
+ mochilo_pack_double(buf, rb_object);
262
+ return;
263
+
264
+ case T_BIGNUM:
265
+ mochilo_pack_bignum(buf, rb_object);
266
+ return;
267
+
268
+ default:
269
+ rb_raise(rb_eMochiloPackError,
270
+ "Unsupported object type: %s", rb_obj_classname(rb_object));
271
+ return;
272
+ }
273
+ }
274
+ #else // RUBINIUS
275
+ switch (rb_type(rb_object)) {
276
+ case T_NIL:
277
+ mochilo_buf_putc(buf, MSGPACK_T_NIL);
278
+ return;
279
+
280
+ case T_FALSE:
281
+ mochilo_buf_putc(buf, MSGPACK_T_FALSE);
282
+ return;
283
+
284
+ case T_TRUE:
285
+ mochilo_buf_putc(buf, MSGPACK_T_TRUE);
286
+ return;
287
+
288
+ case T_FIXNUM:
289
+ mochilo_pack_fixnum(buf, rb_object);
290
+ return;
291
+
292
+ case T_BIGNUM:
293
+ mochilo_pack_bignum(buf, rb_object);
294
+ return;
295
+
296
+ case T_SYMBOL:
297
+ if (trusted)
298
+ mochilo_pack_symbol(buf, rb_object);
299
+ else
300
+ mochilo_pack_str(buf, rb_obj_as_string(rb_object));
301
+ return;
302
+
303
+ case T_STRING:
304
+ #ifdef HAVE_RUBY_ENCODING_H
305
+ if (ENCODING_GET(rb_object) != 0)
306
+ mochilo_pack_str(buf, rb_object);
307
+ else
308
+ #endif
309
+ mochilo_pack_bytes(buf, rb_object);
310
+ return;
311
+
312
+ case T_HASH:
313
+ mochilo_pack_hash(buf, rb_object, trusted);
314
+ return;
315
+
316
+ case T_ARRAY:
317
+ mochilo_pack_array(buf, rb_object, trusted);
318
+ return;
319
+
320
+ case T_FLOAT:
321
+ mochilo_pack_double(buf, rb_object);
322
+ return;
323
+
324
+ default:
325
+ rb_raise(rb_eMochiloPackError,
326
+ "Unsupported object type: %s", rb_obj_classname(rb_object));
327
+ return;
328
+ }
329
+ #endif
330
+ }
331
+