sereal 0.0.7 → 0.0.8

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 658547490d95c374a8fad16740ca8bdb463394cf
4
- data.tar.gz: ff7871ff2e838a756d0a62c7094302068355e89f
3
+ metadata.gz: 06153f3bc1df8650c81eff2d5ef44f260920830c
4
+ data.tar.gz: e6e3e806787c10d2511ff7ea63256f922a45b0f3
5
5
  SHA512:
6
- metadata.gz: af647c218413b546b956392a909e97dc54302a5c729ed2b0f45eeec8c2431b611c7403c343025c9913421a5ebcda477921d5452f080bd02b29c47f93438f4f2e
7
- data.tar.gz: fff160c78207616f73f61380d78384b148053a89bf2b31c2519bfda961fb2dbb261772517f87f0b977cf7c2a17172b8a99fa27c94c42519fc141855b90294f7f
6
+ metadata.gz: 278c31a6754bd905858874e88d3cd87ed88986dbec21e3d7a5544d8b3fd7fab2d011ac3f7e22aff808a412e5b900e8f8d12427e8c1b3d05823cba271075b7379
7
+ data.tar.gz: a10efcc28da1409da425e6e6c222712fdaa7d62bee525728d9ea9b1edfc2a34ea0b14cb358fd98540063b4af1623f5e3b5995d0f17c251f044e67243513bea21
data/bin/rsrl CHANGED
@@ -1,11 +1,11 @@
1
1
  #!/usr/bin/env ruby
2
2
  begin
3
- require './lib/sereal'
3
+ require File.join(File.dirname(__FILE__),'..','lib','sereal')
4
4
  rescue LoadError
5
5
  require 'sereal'
6
6
  end
7
7
 
8
- content = ARGF.read
8
+ content = ENV['Sereal_STREAM'] ? STDIN : ARGF.read
9
9
  compress = Sereal::RAW
10
10
 
11
11
  {'Sereal_SNAPPY' => Sereal::SNAPPY,'Sereal_SNAPPY_INCR' => Sereal::SNAPPY_INCR }.each do |k,v|
@@ -13,9 +13,11 @@ compress = Sereal::RAW
13
13
  compress = v
14
14
  end
15
15
  end
16
- if content[0..3] == '=srl'
16
+
17
+ if ENV['Sereal_STREAM'] || content[0..3] == '=srl'
17
18
  Sereal.decode(content) do |x|
18
19
  STDOUT.write(x)
20
+ puts
19
21
  end
20
22
  else
21
23
  STDOUT.write(Sereal.encode(eval(content), compress))
data/ext/sereal/buffer.h CHANGED
@@ -1,105 +1,181 @@
1
1
  #include "sereal.h"
2
- static inline void *realloc_or_raise(void *p, u32 n) {
3
- u8 *buf = realloc(p,n);
4
- if (!buf)
5
- rb_raise(rb_eNoMemError,"memory allocation failure for %d bytes",n);
6
- return buf;
7
- }
8
- static inline void *alloc_or_raise(u32 s) {
9
- return realloc_or_raise(NULL,s);
2
+ #include <errno.h>
3
+ static void s_dump(sereal_t *s);
4
+
5
+ static inline void s_free_data_if_not_mine(sereal_t *s) {
6
+ if (!(s->flags & FLAG_NOT_MINE)) {
7
+ if (s->data)
8
+ free(s->data);
9
+ s->data = NULL;
10
+ }
10
11
  }
11
12
 
12
- static inline sereal_t * s_create(void) {
13
- sereal_t *s = alloc_or_raise(sizeof(*s));
14
- ZERO(s,sizeof(*s));
15
- return s;
13
+ static inline void s_reset_tracker(sereal_t *s) {
14
+ if (s->tracked != Qnil)
15
+ rb_gc_unregister_address(&s->tracked);
16
+ s->tracked = Qnil;
16
17
  }
17
18
 
18
19
  static inline void s_destroy(sereal_t *s) {
19
- if (s->tracked != Qnil)
20
- rb_gc_unregister_address(&s->tracked);
21
- if (s->data && (s->flags & FLAG_NOT_MINE) == 0)
22
- free(s->data);
20
+ if (!s)
21
+ return;
22
+
23
+ s_reset_tracker(s);
24
+ s_free_data_if_not_mine(s);
25
+ free(s);
26
+ }
27
+
28
+ static inline void *s_realloc_or_raise(sereal_t *s, void *p, u32 n) {
29
+ u8 *buf = realloc(p,n);
30
+ if (!buf)
31
+ s_raise(s,rb_eNoMemError,"memory allocation failure for %d bytes",n);
32
+ return buf;
33
+ }
34
+ static inline void *s_alloc_or_raise(sereal_t *s,u32 n) {
35
+ return s_realloc_or_raise(s,NULL,n);
36
+ }
23
37
 
24
- free(s);
38
+ static inline sereal_t * s_create(void) {
39
+ sereal_t *s = s_alloc_or_raise(NULL,sizeof(*s));
40
+ ZERO(s,sizeof(*s));
41
+ s->tracked = Qnil;
42
+ return s;
25
43
  }
26
44
 
27
45
  static inline void s_alloc(sereal_t *s, u32 len) {
28
- if (s->rsize > s->size + len)
29
- return;
46
+ if (s->rsize > s->size + len)
47
+ return;
30
48
 
31
- u32 size = s->size + len + 512; // every time allocate 512b more, so we wont alloc for a while
32
- u8 *buf = realloc_or_raise(s->data,size);
33
- s->data = buf;
34
- s->rsize = size;
49
+ u32 size = s->size + len + 512; // every time allocate 512b more, so we wont alloc for a while
50
+ u8 *buf = s_realloc_or_raise(s,s->data,size);
51
+ s->data = buf;
52
+ s->rsize = size;
35
53
  }
36
54
 
37
55
  static inline void s_append(sereal_t *s, void *suffix, u32 s_len) {
38
- s_alloc(s,s_len);
39
- COPY(suffix,(s->data + s->size), s_len);
40
- s->size += s_len;
41
- s->pos += s_len;
56
+ s_alloc(s,s_len);
57
+ COPY(suffix,(s->data + s->size), s_len);
58
+ s->size += s_len;
59
+ s->pos += s_len;
42
60
  }
43
61
 
44
62
  static inline void s_append_u8(sereal_t *s,u8 b) {
45
- s_append(s,&b,sizeof(b));
63
+ s_append(s,&b,sizeof(b));
46
64
  }
47
65
 
48
66
  static inline void s_append_u32(sereal_t *s,u32 b) {
49
- s_append(s,&b,sizeof(b));
67
+ s_append(s,&b,sizeof(b));
68
+ }
69
+
70
+ static inline int s_read_stream(sereal_t *s, u32 end) {
71
+ u32 pos = s->pos;
72
+ while (s->size < end) {
73
+ u32 req = end - s->size;
74
+ u32 left = s->buffer.size - s->buffer.pos;
75
+ if (left == 0) {
76
+ int rc = read(s->fd,s->buffer.data,BUFSIZ);
77
+ if (rc <= 0)
78
+ return -1;
79
+ s->buffer.size = rc;
80
+ s->buffer.pos = 0;
81
+ left = rc;
82
+ }
83
+ left = left > req ? req : left;
84
+ s_append(s,s->buffer.data + s->buffer.pos,left);
85
+ s->buffer.pos += left;
86
+ };
87
+ s->pos = pos;
88
+ return 1;
50
89
  }
51
90
 
52
91
  static inline void *s_get_p_at_pos(sereal_t *s, u32 pos,u32 req) {
53
- if (pos + req > s->size)
54
- rb_raise(rb_eRangeError,"position is out of bounds (%d + %d > %d)",pos,req,s->size);
55
- return &s->data[pos];
92
+ // returning s->data[pos], so we just make size count from 0
93
+ if (pos + req >= s->size) {
94
+ if (s->flags & FLAG_STREAM) {
95
+ if (s_read_stream(s,pos + req + 1) < 0) {
96
+ s_raise(s,rb_eRangeError,"stream request for %d bytes failed (err: %s)",
97
+ req,strerror(errno));
98
+ }
99
+ } else {
100
+ u32 size = s->size;
101
+ s_raise(s,rb_eRangeError,"position is out of bounds (%d + %d > %d)",pos,req,size);
102
+ }
103
+ }
104
+ return &s->data[pos];
56
105
  }
57
106
 
58
107
  static inline void *s_get_p_at_pos_bang(sereal_t *s, u32 pos,u32 req) {
59
- void *p = s_get_p_at_pos(s,pos,req);
60
- s->pos += req;
61
- return p;
108
+ void *p = s_get_p_at_pos(s,pos,req);
109
+ s->pos += req;
110
+ return p;
62
111
  }
63
112
 
113
+ static inline void *s_end_p(sereal_t *s) {
114
+ return s_get_p_at_pos(s,s->size - 1,0);
115
+ }
116
+ static inline void *s_get_p_req_inclusive(sereal_t *s, int req) {
117
+ return s_get_p_at_pos(s,s->pos,req > 0 ? req - 1 : 0);
118
+ }
119
+ static inline void *s_get_p_req(sereal_t *s, int req) {
120
+ return s_get_p_at_pos(s,s->pos,req);
121
+ }
64
122
  static inline void *s_get_p(sereal_t *s) {
65
- return s_get_p_at_pos(s,s->pos,0);
123
+ return s_get_p_at_pos(s,s->pos,0);
66
124
  }
67
125
 
68
126
  static inline u8 s_get_u8(sereal_t *s) {
69
- return *((u8 *) s_get_p(s));
127
+ return *((u8 *) s_get_p(s));
70
128
  }
71
129
 
72
130
  static inline u8 s_get_u8_bang(sereal_t *s) {
73
- u8 r = s_get_u8(s);
74
- s->pos++;
75
- return r;
131
+ u8 r = s_get_u8(s);
132
+ s->pos++;
133
+ return r;
76
134
  }
77
135
 
78
136
  static inline u32 s_get_u32_bang(sereal_t *s) {
79
- u32 *r = (u32 *) s_get_p_at_pos(s,s->pos,sizeof(u32) - 1); /* current position + 3 bytes */
80
- s->pos += sizeof(u32);
81
- return *r;
137
+ u32 *r = (u32 *) s_get_p_at_pos(s,s->pos,sizeof(u32) - 1); /* current position + 3 bytes */
138
+ s->pos += sizeof(*r);
139
+ return *r;
140
+ }
141
+
142
+ static inline float s_get_float_bang(sereal_t *s) {
143
+ float *f = (float *) s_get_p_at_pos(s,s->pos,sizeof(*f) - 1);
144
+ s->pos += sizeof(*f);
145
+ return *f;
146
+ }
147
+
148
+ static inline double s_get_double_bang(sereal_t *s) {
149
+ double *d = (double *) s_get_p_at_pos(s,s->pos,sizeof(*d) - 1);
150
+ s->pos += sizeof(*d);
151
+ return *d;
152
+ }
153
+
154
+ static inline long double s_get_long_double_bang(sereal_t *s) {
155
+ long double *d = (long double *) s_get_p_at_pos(s,s->pos,sizeof(*d) - 1);
156
+ s->pos += sizeof(*d);
157
+ return *d;
82
158
  }
83
159
 
84
160
  static inline u32 s_shift_position_bang(sereal_t *s, u32 len) {
85
- s->pos += len;
86
- return len;
161
+ s->pos += len;
162
+ return len;
87
163
  }
88
164
 
89
165
  static void b_dump(u8 *p, u32 len, u32 pos) {
90
- int i;
91
-
92
- fprintf(stderr,"\n-----------\n");
93
- for (i = 0; i < len; i++) {
94
- if (i == pos)
95
- fprintf(stderr," [%c %d] ",p[i],p[i]);
96
- else
97
- fprintf(stderr," (%c %d) ",p[i],p[i]);
98
- }
99
- fprintf(stderr,"\n-----------\n");
166
+ int i;
167
+
168
+ fprintf(stderr,"\n-----------\n");
169
+ for (i = 0; i < len; i++) {
170
+ if (i == pos)
171
+ fprintf(stderr," [%c %d] ",p[i],p[i]);
172
+ else
173
+ fprintf(stderr," (%c %d) ",p[i],p[i]);
174
+ }
175
+ fprintf(stderr,"\n-----------\n");
100
176
  }
101
177
 
102
178
  static void s_dump(sereal_t *s) {
103
- b_dump(s->data,s->size,s->pos);
179
+ E("[ pos: %d, size: %d, rsize: %d ]\n",s->pos,s->size,s->rsize);
180
+ b_dump(s->data,s->size,s->pos);
104
181
  }
105
-
data/ext/sereal/decode.c CHANGED
@@ -4,295 +4,332 @@
4
4
  #include "snappy/csnappy_decompress.c"
5
5
 
6
6
  static VALUE s_default_reader(sereal_t *s, u8 tag) {
7
- // s_dump(s);
8
- s_raise(s,rb_eTypeError,"unsupported tag %d [ 0x%x ]",tag,tag);
9
- return Qnil;
7
+ s_raise(s,rb_eTypeError,"unsupported tag %d [ 0x%x ]",tag,tag);
8
+ return Qnil;
10
9
  }
11
10
 
12
11
  /* VARINT */
13
12
  static u64 s_get_varint_bang(sereal_t *s) {
14
- u64 uv = 0;
15
- unsigned int lshift = 0;
16
- while (s_get_u8(s) & 0x80) {
17
- uv |= ((u64)(s_get_u8_bang(s) & 0x7F) << lshift);
18
- lshift += 7;
19
- if (lshift > (sizeof(uv) * 8))
20
- s_raise(s,rb_eTypeError, "varint too big");
21
- }
22
- uv |= ((u64)(s_get_u8_bang(s)) << lshift);
23
- return uv;
13
+ u64 uv = 0;
14
+ unsigned int lshift = 0;
15
+ while (s_get_u8(s) & 0x80) {
16
+ uv |= ((u64)(s_get_u8_bang(s) & 0x7F) << lshift);
17
+ lshift += 7;
18
+ if (lshift > (sizeof(uv) * 8))
19
+ s_raise(s,rb_eTypeError, "varint too big");
20
+ }
21
+ uv |= ((u64)(s_get_u8_bang(s)) << lshift);
22
+ return uv;
24
23
  }
25
24
 
26
25
  /* ZIGZAG */
27
26
  static VALUE s_read_zigzag(sereal_t *s, u8 tag) {
28
- signed long long z = 0;
29
- u64 v = s_get_varint_bang(s);
30
- if (v & 1) {
31
- z = ((long) v >> 1);
32
- } else {
33
- z = (long) v >> 1;
34
- }
35
- return LL2NUM(z);
27
+ signed long long z = 0;
28
+ u64 v = s_get_varint_bang(s);
29
+ if (v & 1) {
30
+ z = ((long) v >> 1);
31
+ } else {
32
+ z = (long) v >> 1;
33
+ }
34
+ return LL2NUM(z);
36
35
  }
37
36
 
38
37
  /* VARINT */
39
38
  static VALUE s_read_varint(sereal_t *s, u8 tag) {
40
- return ULL2NUM(s_get_varint_bang(s));
39
+ return ULL2NUM(s_get_varint_bang(s));
41
40
  }
42
41
 
43
42
  /* FLOAT */
44
43
  static VALUE s_read_float(sereal_t *s, u8 tag) {
45
- float *f = (float *) s_get_p_at_pos_bang(s,s->pos,sizeof(*f));
46
- return DBL2NUM((double) *f);
44
+ return DBL2NUM(s_get_float_bang(s));
47
45
  }
48
46
 
49
47
  /* DOUBLE */
50
48
  static VALUE s_read_double(sereal_t *s, u8 tag) {
51
- double *d = (double *) s_get_p_at_pos_bang(s,s->pos,sizeof(*d));
52
- return DBL2NUM(*d);
49
+ return DBL2NUM(s_get_double_bang(s));
53
50
  }
54
51
 
55
52
  /* LONG DOUBLE */
56
53
  static VALUE s_read_long_double(sereal_t *s, u8 tag) {
57
- long double *d = (long double *) s_get_p_at_pos_bang(s,s->pos,sizeof(*d));
58
- return DBL2NUM((double) *d);
54
+ return DBL2NUM((double) s_get_long_double(s));
59
55
  }
60
56
 
61
57
  /* POS */
62
58
  static VALUE s_read_small_positive_int(sereal_t *s, u8 tag) {
63
- return INT2FIX(tag);
59
+ return INT2FIX(tag);
64
60
  }
65
61
 
66
62
  /* NEG */
67
63
  static VALUE s_read_small_negative_int(sereal_t *s, u8 tag) {
68
- return INT2FIX(tag - 32);
64
+ return INT2FIX(tag - 32);
69
65
  }
70
66
 
71
67
  /* ARRAY */
72
68
  static inline VALUE s_read_array_with_len(sereal_t *s, u32 len) {
73
- VALUE arr[len];
74
- register u32 i;
75
- for (i = 0; i < len; i++)
76
- arr[i] = sereal_to_rb_object(s);
77
- return rb_ary_new4(len,arr);
69
+ VALUE arr[len];
70
+ register u32 i;
71
+ for (i = 0; i < len; i++)
72
+ arr[i] = sereal_to_rb_object(s);
73
+ return rb_ary_new4(len,arr);
78
74
  }
79
75
 
80
76
  /* ARRAY */
81
77
  static VALUE s_read_array(sereal_t *s,u8 tag) {
82
- return s_read_array_with_len(s,s_get_varint_bang(s));
78
+ return s_read_array_with_len(s,s_get_varint_bang(s));
83
79
  }
84
80
 
85
81
  /* ARRAY */
86
82
  static VALUE s_read_arrayref(sereal_t *s, u8 tag) {
87
- return s_read_array_with_len(s,tag & SRL_MASK_ARRAYREF_COUNT);
83
+ return s_read_array_with_len(s,tag & SRL_MASK_ARRAYREF_COUNT);
88
84
  }
89
85
 
90
86
  /* HASH */
91
87
  static inline VALUE s_read_hash_with_len(sereal_t *s, u32 len) {
92
- VALUE hash = rb_hash_new();
93
- register u32 i;
94
- for (i = 0; i < len; i++) {
95
- VALUE key = sereal_to_rb_object(s);
96
- VALUE value = sereal_to_rb_object(s);
97
- rb_hash_aset(hash,key,value);
98
- }
99
- return hash;
88
+ VALUE hash = rb_hash_new();
89
+ register u32 i;
90
+ for (i = 0; i < len; i++) {
91
+ VALUE key = sereal_to_rb_object(s);
92
+ VALUE value = sereal_to_rb_object(s);
93
+ rb_hash_aset(hash,key,value);
94
+ }
95
+ return hash;
100
96
  }
101
97
 
102
98
  /* HASH */
103
99
  static VALUE s_read_hash(sereal_t *s, u8 tag) {
104
- return s_read_hash_with_len(s,s_get_varint_bang(s));
100
+ return s_read_hash_with_len(s,s_get_varint_bang(s));
105
101
  }
106
102
 
107
103
  /* HASH */
108
104
  static VALUE s_read_hashref(sereal_t *s, u8 tag) {
109
- return s_read_hash_with_len(s,tag & SRL_MASK_HASHREF_COUNT);
105
+ return s_read_hash_with_len(s,tag & SRL_MASK_HASHREF_COUNT);
110
106
  }
111
107
 
112
108
  static VALUE s_read_rb_string_bang(sereal_t *s,u8 t) {
113
- u32 len = 0;
114
- VALUE string;
115
- #define RETURN_STRING(fx_l,fx_gen) \
116
- do { \
117
- len = fx_l; \
118
- string = fx_gen; \
119
- s_shift_position_bang(s,len); \
120
- return string; \
121
- } while(0);
122
-
123
- if (t == SRL_HDR_STR_UTF8) {
124
- RETURN_STRING(s_get_varint_bang(s),
125
- rb_enc_str_new(s_get_p(s),len,
126
- rb_utf8_encoding()));
127
- } else if (t == SRL_HDR_BINARY || t == SRL_HDR_SYM) {
128
- RETURN_STRING(s_get_varint_bang(s),
129
- rb_str_new(s_get_p(s),len));
130
- } else if (IS_SHORT_BINARY(t)) {
131
- RETURN_STRING((t & SRL_MASK_SHORT_BINARY_LEN),
132
- rb_str_new(s_get_p(s), len));
133
- }
109
+ u32 len = 0;
110
+ VALUE string;
111
+ // len - 1: we also use the current byte, similar to u32,float.. casts
112
+ #define RETURN_STRING(fx_l,fx_gen) \
113
+ do { \
114
+ len = fx_l; \
115
+ u8 *ptr = len == 0 ? 0 : s_get_p_req_inclusive(s,len); \
116
+ string = fx_gen; \
117
+ s_shift_position_bang(s,len); \
118
+ return string; \
119
+ } while(0);
120
+
121
+ if (t == SRL_HDR_STR_UTF8) {
122
+ RETURN_STRING(s_get_varint_bang(s),
123
+ rb_enc_str_new(ptr,len,
124
+ rb_utf8_encoding()));
125
+ } else if (t == SRL_HDR_BINARY || t == SRL_HDR_SYM) {
126
+ RETURN_STRING(s_get_varint_bang(s),
127
+ rb_str_new(ptr,len));
128
+ } else if (IS_SHORT_BINARY(t)) {
129
+ RETURN_STRING((t & SRL_MASK_SHORT_BINARY_LEN),
130
+ rb_str_new(ptr, len));
131
+ }
134
132
  #undef RETURN_STRING
135
- s_raise(s,rb_eTypeError, "undefined string type %d",t);
133
+ s_raise(s,rb_eTypeError, "undefined string type %d",t);
136
134
  }
137
135
 
138
136
  static VALUE s_read_next_rb_string_bang(sereal_t *s) {
139
- return s_read_rb_string_bang(s,s_get_u8_bang(s));
137
+ return s_read_rb_string_bang(s,s_get_u8_bang(s));
140
138
  }
141
139
 
142
140
  static VALUE s_read_regexp(sereal_t *s, u8 tag) {
143
- VALUE pattern = s_read_next_rb_string_bang(s);
144
- VALUE modifiers = s_read_next_rb_string_bang(s);
145
-
146
- u32 flags = 0;
147
- if (strchr(RSTRING_PTR(modifiers),'i'))
148
- flags |= IGNORECASE;
149
-
150
- if (strchr(RSTRING_PTR(modifiers),'m'))
151
- flags |= MULTILINE;
152
-
153
- if (strchr(RSTRING_PTR(modifiers),'x'))
154
- flags |= EXTENDED;
155
- #ifdef RUBINIUS
156
- return rb_reg_new(RSTRING_PTR(pattern),RSTRING_LEN(pattern),flags);
157
- #else
158
- return rb_reg_new_str(pattern,flags);
159
- #endif
141
+ VALUE pattern = s_read_next_rb_string_bang(s);
142
+ VALUE modifiers = s_read_next_rb_string_bang(s);
143
+
144
+ u32 flags = 0;
145
+ if (strchr(RSTRING_PTR(modifiers),'i'))
146
+ flags |= IGNORECASE;
147
+
148
+ if (strchr(RSTRING_PTR(modifiers),'m'))
149
+ flags |= MULTILINE;
150
+
151
+ if (strchr(RSTRING_PTR(modifiers),'x'))
152
+ flags |= EXTENDED;
153
+
154
+ #ifdef RUBINIUS
155
+ return rb_reg_new(RSTRING_PTR(pattern),RSTRING_LEN(pattern),flags);
156
+ #else
157
+ return rb_reg_new_str(pattern,flags);
158
+ #endif
160
159
  }
161
160
 
162
161
  static VALUE s_read_nil(sereal_t *s, u8 tag) {
163
- return Qnil;
162
+ return Qnil;
164
163
  }
165
164
 
166
165
  static VALUE s_read_true(sereal_t *s, u8 tag) {
167
- return Qtrue;
166
+ return Qtrue;
168
167
  }
169
168
 
170
169
  static VALUE s_read_false(sereal_t *s, u8 tag) {
171
- return Qfalse;
170
+ return Qfalse;
172
171
  }
173
172
 
174
173
  static VALUE s_read_pad(sereal_t *s, u8 tag) {
175
- /* just skip this byte and go forward */
176
- return sereal_to_rb_object(s);
174
+ /* just skip this byte and go forward */
175
+ return sereal_to_rb_object(s);
177
176
  }
178
177
 
179
178
  static VALUE s_read_extend(sereal_t *s, u8 tag) {
180
- s_raise(s,rb_eArgError,"extend tags are not supported");
179
+ s_raise(s,rb_eArgError,"extend tags are not supported");
181
180
  }
182
181
 
183
182
  static VALUE s_read_ref(sereal_t *s, u8 tag) {
184
- u64 off = s_get_varint_bang(s);
185
- if (s->tracked == Qnil)
186
- s_raise(s,rb_eArgError,"there are no references stored");
187
- return rb_hash_aref(s->tracked,INT2FIX(off + s->hdr_end));
183
+ u64 off = s_get_varint_bang(s);
184
+ if (s->tracked == Qnil)
185
+ s_raise(s,rb_eArgError,"there are no references stored");
186
+ return rb_hash_aref(s->tracked,INT2FIX(off + s->hdr_end));
188
187
  }
189
188
 
190
189
  static VALUE s_read_copy(sereal_t *s, u8 tag) {
191
- VALUE ref = s_red_ref(s,tag);
192
- return rb_obj_dup(ref);
190
+ VALUE ref = s_red_ref(s,tag);
191
+ return rb_obj_dup(ref);
193
192
  }
194
193
 
195
194
  VALUE sereal_to_rb_object(sereal_t *s) {
196
- u8 t, tracked;
197
- S_RECURSE_INC(s);
198
- u32 pos;
199
- while (s->pos < s->size) {
200
- t = s_get_u8_bang(s);
201
- tracked = (t & SRL_HDR_TRACK_FLAG ? 1 : 0);
202
- t &= ~SRL_HDR_TRACK_FLAG;
203
- pos = s->pos;
204
-
205
- S_RECURSE_DEC(s);
206
-
207
- VALUE decoded = (*READERS[t])(s,t);
208
- if (tracked) {
209
- if (s->tracked == Qnil) {
210
- s->tracked = rb_hash_new();
211
- rb_gc_register_address(&s->tracked);
212
- }
213
- rb_hash_aset(s->tracked,INT2FIX(pos),decoded);
214
- }
215
- return decoded;
195
+ u8 t, tracked;
196
+ S_RECURSE_INC(s);
197
+ u32 pos;
198
+ while (s->pos < s->size || (s->flags & FLAG_STREAM)) {
199
+ t = s_get_u8_bang(s);
200
+ tracked = (t & SRL_HDR_TRACK_FLAG ? 1 : 0);
201
+ t &= ~SRL_HDR_TRACK_FLAG;
202
+ pos = s->pos;
203
+
204
+ S_RECURSE_DEC(s);
205
+
206
+ VALUE decoded = (*READERS[t])(s,t);
207
+ if (tracked) {
208
+ if (s->tracked == Qnil) {
209
+ s->tracked = rb_hash_new();
210
+ rb_gc_register_address(&s->tracked);
211
+ }
212
+ rb_hash_aset(s->tracked,INT2FIX(pos),decoded);
216
213
  }
217
- s_raise(s,rb_eArgError,"bad packet, or broken decoder");
218
- return Qnil;
214
+ return decoded;
215
+ }
216
+ s_raise(s,rb_eArgError,"bad packet, or broken decoder");
217
+ return Qnil;
219
218
  }
220
219
 
221
220
  VALUE method_sereal_decode(VALUE self, VALUE args) {
222
- u32 argc = RARRAY_LEN(args);
223
- if (argc < 1)
224
- rb_raise(rb_eArgError,"need at least 1 argument (object)");
225
- VALUE payload = rb_ary_shift(args);
226
- if (TYPE(payload) != T_STRING)
227
- rb_raise(rb_eTypeError,"can not decode objects of type %s",rb_obj_classname(payload));
228
- u8 have_block = rb_block_given_p();
229
- sereal_t *s = s_create();
230
- u64 offset = 0;
221
+ u32 argc = RARRAY_LEN(args);
222
+ if (argc < 1)
223
+ rb_raise(rb_eArgError,"need at least 1 argument (object)");
224
+ VALUE payload = rb_ary_shift(args);
225
+ u8 have_block = rb_block_given_p();
226
+ sereal_t *s = s_create();
227
+ u64 offset = 0;
228
+ if (TYPE(payload) == T_FILE) {
229
+ if (!have_block)
230
+ s_raise(s,rb_eTypeError,"block is required when reading from a stream")
231
+
232
+ rb_io_t *fptr;
233
+ GetOpenFile(payload, fptr);
234
+ s->flags |= FLAG_STREAM;
235
+ s->fd = fptr->fd;
236
+ } else if (TYPE(payload) != T_STRING) {
237
+ rb_raise(rb_eTypeError,"can not decode objects of type %s",rb_obj_classname(payload));
238
+ }
239
+
231
240
  again:
232
- if (offset >= RSTRING_LEN(payload)) {
233
- free(s);
241
+ s->pos = 0;
242
+ s_reset_tracker(s);
243
+
244
+ if (s->flags & FLAG_STREAM) {
245
+ s->size = 0;
246
+ s->rsize = 0;
247
+ if (s_read_stream(s,__MIN_SIZE) < 0) {
248
+ s_destroy(s);
234
249
  return Qnil;
235
250
  }
251
+
252
+ } else {
253
+ u32 size = RSTRING_LEN(payload) - offset;
254
+ if (offset > RSTRING_LEN(payload) || (offset > 0 && size < __MIN_SIZE)) {
255
+ s_destroy(s);
256
+ return Qnil;
257
+ }
258
+ if (size < __MIN_SIZE)
259
+ s_raise(s,rb_eTypeError,"size(%d) is less then min packet size %d, offset: %d",size,__MIN_SIZE,offset);
260
+
236
261
  s->flags |= FLAG_NOT_MINE;
237
262
  s->data = RSTRING_PTR(payload) + offset;
238
- s->size = RSTRING_LEN(payload) - offset;
239
- s->pos = 0;
240
- s->tracked = Qnil;
241
- if (s->size < 6 || s_get_u32_bang(s) != SRL_MAGIC_STRING_LILIPUTIAN)
242
- s_raise(s,rb_eTypeError,"invalid header");
243
-
244
- u8 version = s_get_u8_bang(s);
245
- u8 suffix = s_get_varint_bang(s);
246
- u8 is_compressed;
247
-
248
- if ((version & SRL_PROTOCOL_ENCODING_MASK) == SRL_PROTOCOL_ENCODING_SNAPPY)
249
- is_compressed = __SNAPPY;
250
- else if ((version & SRL_PROTOCOL_ENCODING_MASK) == SRL_PROTOCOL_ENCODING_SNAPPY_INCR)
251
- is_compressed = __SNAPPY_INCR;
252
- else
253
- is_compressed = __RAW;
254
- if (is_compressed) {
255
- u32 uncompressed_len;
256
- u32 compressed_len;
257
-
258
- if (is_compressed == __SNAPPY_INCR) {
259
- compressed_len = s_get_varint_bang(s);
260
- } else {
261
- compressed_len = s->size - s->pos;
262
- }
263
-
264
- int snappy_header_len = csnappy_get_uncompressed_length(s_get_p(s),
265
- compressed_len,
266
- &uncompressed_len);
267
- if (snappy_header_len == CSNAPPY_E_HEADER_BAD)
268
- rb_raise(rb_eTypeError,"invalid snappy header");
269
- u8 *uncompressed = alloc_or_raise(uncompressed_len);
270
- int done = csnappy_decompress(s_get_p(s),
271
- compressed_len,
272
- uncompressed,
273
- uncompressed_len) == CSNAPPY_E_OK ? 1 : 0;
274
- if (!done)
275
- s_raise(s,rb_eTypeError, "decompression failed error: %d type: %d, unompressed size: %d compressed size: %d",done,is_compressed,uncompressed_len,compressed_len);
276
-
277
- offset += s->pos + compressed_len;
278
- s->data = uncompressed;
279
- s->size = uncompressed_len;
280
- s->pos = 0;
281
- s->flags &= ~FLAG_NOT_MINE;
263
+ s->size = size;
264
+ }
265
+
266
+ u32 magic = s_get_u32_bang(s);
267
+ if (magic != SRL_MAGIC_STRING_LILIPUTIAN)
268
+ s_raise(s,rb_eTypeError,"invalid header: %d (%x)",magic,magic);
269
+
270
+ u8 version = s_get_u8_bang(s);
271
+ u8 suffix = s_get_varint_bang(s);
272
+ u8 is_compressed;
273
+
274
+ if ((version & SRL_PROTOCOL_ENCODING_MASK) == SRL_PROTOCOL_ENCODING_SNAPPY)
275
+ is_compressed = __SNAPPY;
276
+ else if ((version & SRL_PROTOCOL_ENCODING_MASK) == SRL_PROTOCOL_ENCODING_SNAPPY_INCR)
277
+ is_compressed = __SNAPPY_INCR;
278
+ else
279
+ is_compressed = __RAW;
280
+
281
+ if (is_compressed) {
282
+ u32 uncompressed_len;
283
+ u32 compressed_len;
284
+
285
+ if (is_compressed == __SNAPPY_INCR) {
286
+ compressed_len = s_get_varint_bang(s);
287
+ } else {
288
+ if (s->flags & FLAG_STREAM)
289
+ s_raise(s,rb_eTypeError,"parsing non incremental compressed objects, from stream of data, is not supported");
290
+
291
+ compressed_len = s->size - s->pos;
282
292
  }
283
- s->hdr_end = s->pos;
284
- VALUE result = sereal_to_rb_object(s);
285
- if (is_compressed && have_block) {
286
- free(s->data);
287
- s->data = NULL;
288
- rb_yield(result);
289
- goto again;
293
+
294
+ if (s->flags & FLAG_STREAM)
295
+ s_get_p_req_inclusive(s,compressed_len);
296
+
297
+ int snappy_header_len = csnappy_get_uncompressed_length(s_get_p_req_inclusive(s,compressed_len),
298
+ compressed_len,
299
+ &uncompressed_len);
300
+ if (snappy_header_len == CSNAPPY_E_HEADER_BAD)
301
+ s_raise(s,rb_eTypeError,"invalid snappy header");
302
+
303
+ u8 *uncompressed = s_alloc_or_raise(s,uncompressed_len);
304
+ int done = csnappy_decompress(s_get_p_req_inclusive(s,compressed_len),
305
+ compressed_len,
306
+ uncompressed,
307
+ uncompressed_len) == CSNAPPY_E_OK ? 1 : 0;
308
+ if (!done)
309
+ s_raise(s,rb_eTypeError, "decompression failed error: %d type: %d, unompressed size: %d compressed size: %d",
310
+ done,is_compressed,uncompressed_len,compressed_len);
311
+
312
+ s_free_data_if_not_mine(s);
313
+ s->data = uncompressed;
314
+ s->size = uncompressed_len;
315
+ offset += s->pos + compressed_len;
316
+ s->pos = 0;
317
+ s->flags &= ~FLAG_NOT_MINE;
318
+ }
319
+ s->hdr_end = s->pos;
320
+ VALUE result = sereal_to_rb_object(s);
321
+ if (!is_compressed)
322
+ offset += s->pos;
323
+ if (have_block) {
324
+ rb_yield(result);
325
+ s_free_data_if_not_mine(s);
326
+ goto again;
327
+ } else {
328
+ if (s->pos < s->size) {
329
+ s_raise(s,rb_eTypeError,"there is still some data left in the buffer, use block read, otherwise we are losing it");
290
330
  }
291
331
  s_destroy(s);
292
- if (have_block) {
293
- rb_yield(result);
294
- return Qnil;
295
- }
296
332
  return result;
333
+ }
297
334
  }
298
335