vox-etf 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,162 @@
1
+ #include "erlpack/encoder.h"
2
+ #include "etf.hpp"
3
+
4
+ namespace etf
5
+ {
6
+ class encoder
7
+ {
8
+ public:
9
+ encoder()
10
+ {
11
+ erl_buff = (erlpack_buffer *)malloc(sizeof(erl_buff));
12
+ erl_buff->buf = (char *)malloc(sizeof(char) * 128);
13
+ erl_buff->length = 0;
14
+ erl_buff->allocated_size = 128;
15
+ erlpack_append_version(erl_buff);
16
+ }
17
+
18
+ ~encoder()
19
+ {
20
+ free(erl_buff->buf);
21
+ free(erl_buff);
22
+ }
23
+
24
+ void encode_object(VALUE input)
25
+ {
26
+ switch (TYPE(input))
27
+ {
28
+ case T_TRUE:
29
+ encode_true();
30
+ break;
31
+ case T_FALSE:
32
+ encode_false();
33
+ break;
34
+ case T_NIL:
35
+ encode_nil();
36
+ break;
37
+ case T_FLOAT:
38
+ encode_float(input);
39
+ break;
40
+ case T_BIGNUM:
41
+ encode_bignum(input);
42
+ break;
43
+ case T_FIXNUM:
44
+ encode_fixnum(input);
45
+ break;
46
+ case T_SYMBOL:
47
+ encode_symbol(input);
48
+ break;
49
+ case T_STRING:
50
+ encode_string(input);
51
+ break;
52
+ case T_ARRAY:
53
+ encode_array(input);
54
+ break;
55
+ case T_HASH:
56
+ encode_hash(input);
57
+ break;
58
+ default:
59
+ rb_raise(rb_eArgError, "Unsupported serialization type");
60
+ break;
61
+ }
62
+ }
63
+
64
+ VALUE
65
+ r_string(void)
66
+ {
67
+ return rb_str_new(erl_buff->buf, erl_buff->length);
68
+ }
69
+
70
+ private:
71
+ erlpack_buffer *erl_buff;
72
+
73
+ void encode_true()
74
+ {
75
+ erlpack_append_true(erl_buff);
76
+ }
77
+
78
+ void encode_false()
79
+ {
80
+ erlpack_append_false(erl_buff);
81
+ }
82
+
83
+ void encode_nil()
84
+ {
85
+ erlpack_append_nil(erl_buff);
86
+ }
87
+
88
+ void encode_fixnum(VALUE fixnum)
89
+ {
90
+ long l = FIX2LONG(fixnum);
91
+ if (l > 0 && l <= 0xFF)
92
+ erlpack_append_small_integer(erl_buff, (unsigned char)l);
93
+ else
94
+ erlpack_append_integer(erl_buff, l);
95
+ }
96
+
97
+ void encode_bignum(VALUE bignum)
98
+ {
99
+ size_t byte_count = rb_absint_size(bignum, NULL);
100
+ if (byte_count <= 0xFF)
101
+ {
102
+ // id byte | n byte | sign byte | data
103
+ uint8_t buff[3 + byte_count];
104
+ buff[0] = term::small_big;
105
+ buff[1] = byte_count;
106
+ buff[2] = FIX2LONG(bignum) >= 0 ? 0 : 1;
107
+ rb_integer_pack(bignum, buff + 3, byte_count, sizeof(uint8_t), 0, INTEGER_PACK_LITTLE_ENDIAN);
108
+ erlpack_buffer_write(erl_buff, (const char *)buff, 3 + byte_count);
109
+ }
110
+ else
111
+ {
112
+ // id byte | 4 byte n | sign byte | data
113
+ uint8_t buff[6 + byte_count];
114
+ buff[0] = term::large_big;
115
+ _erlpack_store32(buff + 1, byte_count);
116
+ buff[5] = RBIGNUM_SIGN(bignum) ? 0 : 1;
117
+ rb_integer_pack(bignum, buff + 6, byte_count, sizeof(uint8_t), 0, INTEGER_PACK_LITTLE_ENDIAN);
118
+ erlpack_buffer_write(erl_buff, (const char *)buff, 6 + byte_count);
119
+ }
120
+ }
121
+
122
+ void encode_float(VALUE rfloat)
123
+ {
124
+ erlpack_append_double(erl_buff, NUM2DBL(rfloat));
125
+ }
126
+
127
+ void encode_array(VALUE array)
128
+ {
129
+ erlpack_append_list_header(erl_buff, RARRAY_LEN(array));
130
+ uint32_t size = RARRAY_LEN(array);
131
+ for (uint32_t index = 0; index < size; index++)
132
+ {
133
+ encode_object(RARRAY_AREF(array, index));
134
+ }
135
+ }
136
+
137
+ void encode_symbol(VALUE symbol)
138
+ {
139
+ VALUE str = rb_sym2str(symbol);
140
+ erlpack_append_atom_utf8(erl_buff, RSTRING_PTR(str), RSTRING_LEN(str));
141
+ }
142
+
143
+ void encode_string(VALUE string)
144
+ {
145
+ erlpack_append_binary(erl_buff, RSTRING_PTR(string), RSTRING_LEN(string));
146
+ }
147
+
148
+ void encode_hash(VALUE hash)
149
+ {
150
+ uint32_t size = RHASH_SIZE(hash);
151
+ erlpack_append_map_header(erl_buff, size);
152
+ VALUE keys = rb_funcall(hash, rb_intern("keys"), 0);
153
+
154
+ for (uint32_t index = 0; index < size * 2; index += 2)
155
+ {
156
+ VALUE key = RARRAY_AREF(keys, index / 2);
157
+ encode_object(key);
158
+ encode_object(rb_hash_aref(hash, key));
159
+ }
160
+ }
161
+ };
162
+ } // namespace etf
@@ -0,0 +1,51 @@
1
+ /************************************************
2
+ * MIT License
3
+ *
4
+ * Copyright (c) 2017 Discord
5
+ *
6
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ * of this software and associated documentation files (the "Software"), to deal
8
+ * in the Software without restriction, including without limitation the rights
9
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ * copies of the Software, and to permit persons to whom the Software is
11
+ * furnished to do so, subject to the following conditions:
12
+ *
13
+ * The above copyright notice and this permission notice shall be included in all
14
+ * copies or substantial portions of the Software.
15
+ *
16
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ * SOFTWARE.
23
+ ************************************************/
24
+
25
+ #define FORMAT_VERSION 131
26
+ #define NEW_FLOAT_EXT 'F' // 70 [Float64:IEEE float]
27
+ #define BIT_BINARY_EXT 'M' // 77 [UInt32:Len, UInt8:Bits, Len:Data]
28
+ #define COMPRESSED 'P' // 80 [UInt4:UncompressedSize, N:ZlibCompressedData]
29
+ #define SMALL_INTEGER_EXT 'a' // 97 [UInt8:Int]
30
+ #define INTEGER_EXT 'b' // 98 [Int32:Int]
31
+ #define FLOAT_EXT 'c' // 99 [31:Float String] Float in string format (formatted "%.20e", sscanf "%lf"). Superseded by NEW_FLOAT_EXT
32
+ #define ATOM_EXT 'd' // 100 [UInt16:Len, Len:AtomName] max Len is 255
33
+ #define REFERENCE_EXT 'e' // 101 [atom:Node, UInt32:ID, UInt8:Creation]
34
+ #define PORT_EXT 'f' // 102 [atom:Node, UInt32:ID, UInt8:Creation]
35
+ #define PID_EXT 'g' // 103 [atom:Node, UInt32:ID, UInt32:Serial, UInt8:Creation]
36
+ #define SMALL_TUPLE_EXT 'h' // 104 [UInt8:Arity, N:Elements]
37
+ #define LARGE_TUPLE_EXT 'i' // 105 [UInt32:Arity, N:Elements]
38
+ #define NIL_EXT 'j' // 106 empty list
39
+ #define STRING_EXT 'k' // 107 [UInt16:Len, Len:Characters]
40
+ #define LIST_EXT 'l' // 108 [UInt32:Len, Elements, Tail]
41
+ #define BINARY_EXT 'm' // 109 [UInt32:Len, Len:Data]
42
+ #define SMALL_BIG_EXT 'n' // 110 [UInt8:n, UInt8:Sign, n:nums]
43
+ #define LARGE_BIG_EXT 'o' // 111 [UInt32:n, UInt8:Sign, n:nums]
44
+ #define NEW_FUN_EXT 'p' // 112 [UInt32:Size, UInt8:Arity, 16*Uint6-MD5:Uniq, UInt32:Index, UInt32:NumFree, atom:Module, int:OldIndex, int:OldUniq, pid:Pid, NunFree*ext:FreeVars]
45
+ #define EXPORT_EXT 'q' // 113 [atom:Module, atom:Function, smallint:Arity]
46
+ #define NEW_REFERENCE_EXT 'r' // 114 [UInt16:Len, atom:Node, UInt8:Creation, Len*UInt32:ID]
47
+ #define SMALL_ATOM_EXT 's' // 115 [UInt8:Len, Len:AtomName]
48
+ #define MAP_EXT 't' // 116 [UInt32:Airty, N:Pairs]
49
+ #define FUN_EXT 'u' // 117 [UInt4:NumFree, pid:Pid, atom:Module, int:Index, int:Uniq, NumFree*ext:FreeVars]
50
+ #define ATOM_UTF8_EXT 'v' // 118 [UInt16:Len, Len:AtomName] max Len is 255 characters (up to 4 bytes per)
51
+ #define SMALL_ATOM_UTF8_EXT 'w' // 119 [UInt8:Len, Len:AtomName]
@@ -0,0 +1,296 @@
1
+ /************************************************
2
+ * MIT License
3
+ *
4
+ * Copyright (c) 2017 Discord
5
+ *
6
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ * of this software and associated documentation files (the "Software"), to deal
8
+ * in the Software without restriction, including without limitation the rights
9
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ * copies of the Software, and to permit persons to whom the Software is
11
+ * furnished to do so, subject to the following conditions:
12
+ *
13
+ * The above copyright notice and this permission notice shall be included in all
14
+ * copies or substantial portions of the Software.
15
+ *
16
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ * SOFTWARE.
23
+ ************************************************/
24
+
25
+ #include <stddef.h>
26
+ #include <stdlib.h>
27
+ #include "sysdep.h"
28
+ #include "constants.h"
29
+ #include <limits.h>
30
+ #include <string.h>
31
+
32
+ #ifdef __cplusplus
33
+ extern "C"
34
+ {
35
+ #endif
36
+
37
+ typedef struct erlpack_buffer
38
+ {
39
+ char *buf;
40
+ size_t length;
41
+ size_t allocated_size;
42
+ } erlpack_buffer;
43
+
44
+ static inline int erlpack_buffer_write(erlpack_buffer *pk, const char *bytes,
45
+ size_t l)
46
+ {
47
+ char *buf = pk->buf;
48
+ size_t allocated_size = pk->allocated_size;
49
+ size_t length = pk->length;
50
+
51
+ if (length + l > allocated_size)
52
+ {
53
+ // Grow buffer 2x to avoid excessive re-allocations.
54
+ allocated_size = (length + l) * 2;
55
+ buf = (char *)realloc(buf, allocated_size);
56
+
57
+ if (!buf)
58
+ return -1;
59
+ }
60
+
61
+ memcpy(buf + length, bytes, l);
62
+ length += l;
63
+
64
+ pk->buf = buf;
65
+ pk->allocated_size = allocated_size;
66
+ pk->length = length;
67
+ return 0;
68
+ }
69
+
70
+ #define erlpack_append(pk, buf, len) \
71
+ return erlpack_buffer_write(pk, (const char *)buf, len)
72
+
73
+ static inline int erlpack_append_version(erlpack_buffer *b)
74
+ {
75
+ static unsigned char buf[1] = {FORMAT_VERSION};
76
+ erlpack_append(b, buf, 1);
77
+ }
78
+
79
+ static inline int erlpack_append_nil(erlpack_buffer *b)
80
+ {
81
+ static unsigned char buf[5] = {SMALL_ATOM_EXT, 3, 'n', 'i', 'l'};
82
+ erlpack_append(b, buf, 5);
83
+ }
84
+ static inline int erlpack_append_false(erlpack_buffer *b)
85
+ {
86
+ static unsigned char buf[7] = {SMALL_ATOM_EXT, 5, 'f', 'a', 'l', 's', 'e'};
87
+ erlpack_append(b, buf, 7);
88
+ }
89
+
90
+ static inline int erlpack_append_true(erlpack_buffer *b)
91
+ {
92
+ static unsigned char buf[6] = {SMALL_ATOM_EXT, 4, 't', 'r', 'u', 'e'};
93
+ erlpack_append(b, buf, 6);
94
+ }
95
+
96
+ static inline int erlpack_append_small_integer(erlpack_buffer *b,
97
+ unsigned char d)
98
+ {
99
+ unsigned char buf[2] = {SMALL_INTEGER_EXT, d};
100
+ erlpack_append(b, buf, 2);
101
+ }
102
+
103
+ static inline int erlpack_append_integer(erlpack_buffer *b, int32_t d)
104
+ {
105
+ unsigned char buf[5];
106
+ buf[0] = INTEGER_EXT;
107
+ _erlpack_store32(buf + 1, d);
108
+ erlpack_append(b, buf, 5);
109
+ }
110
+
111
+ static inline int erlpack_append_unsigned_long_long(erlpack_buffer *b,
112
+ unsigned long long d)
113
+ {
114
+ unsigned char buf[1 + 2 + sizeof(unsigned long long)];
115
+ buf[0] = SMALL_BIG_EXT;
116
+
117
+ unsigned char bytes_enc = 0;
118
+ while (d > 0)
119
+ {
120
+ buf[3 + bytes_enc] = d & 0xFF;
121
+ d >>= 8;
122
+ bytes_enc++;
123
+ }
124
+ buf[1] = bytes_enc;
125
+ buf[2] = 0;
126
+
127
+ erlpack_append(b, buf, 1 + 2 + bytes_enc);
128
+ }
129
+
130
+ static inline int erlpack_append_long_long(erlpack_buffer *b, long long d)
131
+ {
132
+ unsigned char buf[1 + 2 + sizeof(unsigned long long)];
133
+ buf[0] = SMALL_BIG_EXT;
134
+ buf[2] = d < 0 ? 1 : 0;
135
+ unsigned long long ull = d < 0 ? -d : d;
136
+ unsigned char bytes_enc = 0;
137
+ while (ull > 0)
138
+ {
139
+ buf[3 + bytes_enc] = ull & 0xFF;
140
+ ull >>= 8;
141
+ bytes_enc++;
142
+ }
143
+ buf[1] = bytes_enc;
144
+ erlpack_append(b, buf, 1 + 2 + bytes_enc);
145
+ }
146
+
147
+ typedef union
148
+ {
149
+ uint64_t ui64;
150
+ double df;
151
+ } typePunner;
152
+
153
+ static inline int erlpack_append_double(erlpack_buffer *b, double f)
154
+ {
155
+ unsigned char buf[1 + 8] = {0};
156
+ buf[0] = NEW_FLOAT_EXT;
157
+ typePunner p;
158
+ p.df = f;
159
+ _erlpack_store64(buf + 1, p.ui64);
160
+ erlpack_append(b, buf, 1 + 8);
161
+ }
162
+
163
+ static inline int erlpack_append_atom(erlpack_buffer *b, const char *bytes, size_t size)
164
+ {
165
+ if (size < 255)
166
+ {
167
+ unsigned char buf[2] = {SMALL_ATOM_EXT, (unsigned char)size};
168
+ int ret = erlpack_buffer_write(b, (const char *)buf, 2);
169
+ if (ret < 0)
170
+ return ret;
171
+
172
+ erlpack_append(b, bytes, size);
173
+ }
174
+ else
175
+ {
176
+ unsigned char buf[3];
177
+ buf[0] = ATOM_EXT;
178
+
179
+ if (size > 0xFFFF)
180
+ {
181
+ return 1;
182
+ }
183
+
184
+ _erlpack_store16(buf + 1, size);
185
+
186
+ int ret = erlpack_buffer_write(b, (const char *)buf, 3);
187
+ if (ret < 0)
188
+ return ret;
189
+
190
+ erlpack_append(b, bytes, size);
191
+ }
192
+ }
193
+
194
+ static inline int erlpack_append_atom_utf8(erlpack_buffer *b, const char *bytes, size_t size)
195
+ {
196
+ if (size < 255)
197
+ {
198
+ unsigned char buf[2] = {SMALL_ATOM_UTF8_EXT, (unsigned char)size};
199
+ int ret = erlpack_buffer_write(b, (const char *)buf, 2);
200
+ if (ret < 0)
201
+ return ret;
202
+
203
+ erlpack_append(b, bytes, size);
204
+ }
205
+ else
206
+ {
207
+ unsigned char buf[3];
208
+ buf[0] = ATOM_UTF8_EXT;
209
+
210
+ if (size > 0xFFFF)
211
+ {
212
+ return 1;
213
+ }
214
+
215
+ _erlpack_store16(buf + 1, size);
216
+
217
+ int ret = erlpack_buffer_write(b, (const char *)buf, 3);
218
+ if (ret < 0)
219
+ return ret;
220
+
221
+ erlpack_append(b, bytes, size);
222
+ }
223
+ }
224
+
225
+ static inline int erlpack_append_binary(erlpack_buffer *b, const char *bytes, size_t size)
226
+ {
227
+ unsigned char buf[5];
228
+ buf[0] = BINARY_EXT;
229
+
230
+ _erlpack_store32(buf + 1, size);
231
+
232
+ int ret = erlpack_buffer_write(b, (const char *)buf, 5);
233
+ if (ret < 0)
234
+ return ret;
235
+
236
+ erlpack_append(b, bytes, size);
237
+ }
238
+
239
+ static inline int erlpack_append_string(erlpack_buffer *b, const char *bytes, size_t size)
240
+ {
241
+ unsigned char buf[3];
242
+ buf[0] = STRING_EXT;
243
+
244
+ _erlpack_store16(buf + 1, size);
245
+
246
+ int ret = erlpack_buffer_write(b, (const char *)buf, 3);
247
+ if (ret < 0)
248
+ return ret;
249
+
250
+ erlpack_append(b, bytes, size);
251
+ }
252
+
253
+ static inline int erlpack_append_tuple_header(erlpack_buffer *b, size_t size)
254
+ {
255
+ if (size < 256)
256
+ {
257
+ unsigned char buf[2];
258
+ buf[0] = SMALL_TUPLE_EXT;
259
+ buf[1] = (unsigned char)size;
260
+ erlpack_append(b, buf, 2);
261
+ }
262
+ else
263
+ {
264
+ unsigned char buf[5];
265
+ buf[0] = LARGE_TUPLE_EXT;
266
+ _erlpack_store32(buf + 1, size);
267
+ erlpack_append(b, buf, 5);
268
+ }
269
+ }
270
+
271
+ static inline int erlpack_append_nil_ext(erlpack_buffer *b)
272
+ {
273
+ static unsigned char buf[1] = {NIL_EXT};
274
+ erlpack_append(b, buf, 1);
275
+ }
276
+
277
+ static inline int erlpack_append_list_header(erlpack_buffer *b, size_t size)
278
+ {
279
+ unsigned char buf[5];
280
+ buf[0] = LIST_EXT;
281
+ _erlpack_store32(buf + 1, size);
282
+ erlpack_append(b, buf, 5);
283
+ }
284
+
285
+ static inline int erlpack_append_map_header(erlpack_buffer *b, size_t size)
286
+ {
287
+ unsigned char buf[5];
288
+ buf[0] = MAP_EXT;
289
+ _erlpack_store32(buf + 1, size);
290
+ erlpack_append(b, buf, 5);
291
+ }
292
+
293
+ #ifdef __cplusplus
294
+ }
295
+
296
+ #endif