sereal 0.0.7 → 0.0.8

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.
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