oj 2.12.1 → 2.12.2

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of oj might be problematic. Click here for more details.

@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 2a621ea1cf610e5b78949d860fc54f2c6fe43e0c
4
+ data.tar.gz: 11cd52b0f0747e95007d678b291560b6271b9235
5
+ SHA512:
6
+ metadata.gz: 76bdb63802a6f728259dd9cb7351d64f38862cf8a522bdb56c208cdc5803cb52a4625493c4c0d7d103d5e6a7a2522bfd847a1942ccb56ce2a59a3b22ae9d969e
7
+ data.tar.gz: 5a215c6a81a876ee0f1a777ff90f1d55b1ad5eb809da6b431eb21b79f7bcaab7a552febdcc090f12e17aa0acf0ea885c78d70940b13e298d8524db1c227c0500
data/README.md CHANGED
@@ -26,9 +26,11 @@ Follow [@peterohler on Twitter](http://twitter.com/#!/peterohler) for announceme
26
26
 
27
27
  [![Build Status](https://secure.travis-ci.org/ohler55/oj.png?branch=master)](http://travis-ci.org/ohler55/oj)
28
28
 
29
- ## Current Release 2.12.1
29
+ ## Current Release 2.12.2
30
30
 
31
- - Changed the unix_zone encoded format to be the utc epoch.
31
+ - Fixed Oj::Doc bug that causes a crash on local name lookups.
32
+
33
+ - Fixed Oj::Doc unicode parsing.
32
34
 
33
35
  [Older release notes](http://www.ohler.com/dev/oj_misc/release_notes.html).
34
36
 
@@ -80,6 +82,11 @@ Rails 3.2 and 4.0. As of the Oj 2.6.0 release the default behavior is to not use
80
82
  the `to_json()` method unless the `:use_to_json` option is set. This provides
81
83
  another work around to the rails older and newer behavior.
82
84
 
85
+ The latest ActiveRecord is able to work with Oj by simply using the line:
86
+ ```
87
+ serialize :my_attr, Oj
88
+ ```
89
+
83
90
  In version Rails 4.1, multi_json has been removed, and this patch is unnecessary and will no longer work.
84
91
  Instead, use the `oj_mimic_json` [gem](https://github.com/ohler55/oj_mimic_json) along with `oj` in your `Gemfile` to have Oj mimic the JSON gem and be used in its place by `ActiveSupport` JSON handling:
85
92
  ```
@@ -2228,7 +2228,7 @@ dump_leaf_hash(Leaf leaf, int depth, Out out) {
2228
2228
 
2229
2229
  static void
2230
2230
  dump_leaf(Leaf leaf, int depth, Out out) {
2231
- switch (leaf->type) {
2231
+ switch (leaf->rtype) {
2232
2232
  case T_NIL:
2233
2233
  dump_nil(out);
2234
2234
  break;
@@ -2254,7 +2254,7 @@ dump_leaf(Leaf leaf, int depth, Out out) {
2254
2254
  dump_leaf_hash(leaf, depth, out);
2255
2255
  break;
2256
2256
  default:
2257
- rb_raise(rb_eTypeError, "Unexpected type %02x.\n", leaf->type);
2257
+ rb_raise(rb_eTypeError, "Unexpected type %02x.\n", leaf->rtype);
2258
2258
  break;
2259
2259
  }
2260
2260
  }
@@ -170,7 +170,7 @@ ulong_fill(char *s, size_t num) {
170
170
  inline static void
171
171
  leaf_init(Leaf leaf, int type) {
172
172
  leaf->next = 0;
173
- leaf->type = type;
173
+ leaf->rtype = type;
174
174
  leaf->parent_type = T_NONE;
175
175
  switch (type) {
176
176
  case T_ARRAY:
@@ -206,6 +206,8 @@ leaf_new(Doc doc, int type) {
206
206
  if (0 == doc->batches || BATCH_SIZE == doc->batches->next_avail) {
207
207
  Batch b = ALLOC(struct _Batch);
208
208
 
209
+ // Initializes all leaves with a NO_VAL value_type
210
+ memset(b, 0, sizeof(struct _Batch));
209
211
  b->next = doc->batches;
210
212
  doc->batches = b;
211
213
  b->next_avail = 0;
@@ -232,7 +234,7 @@ leaf_append_element(Leaf parent, Leaf element) {
232
234
  static VALUE
233
235
  leaf_value(Doc doc, Leaf leaf) {
234
236
  if (RUBY_VAL != leaf->value_type) {
235
- switch (leaf->type) {
237
+ switch (leaf->rtype) {
236
238
  case T_NIL:
237
239
  leaf->value = Qnil;
238
240
  break;
@@ -260,7 +262,7 @@ leaf_value(Doc doc, Leaf leaf) {
260
262
  return leaf_hash_value(doc, leaf);
261
263
  break;
262
264
  default:
263
- rb_raise(rb_const_get_at(Oj, rb_intern("Error")), "Unexpected type %02x.", leaf->type);
265
+ rb_raise(rb_const_get_at(Oj, rb_intern("Error")), "Unexpected type %02x.", leaf->rtype);
264
266
  break;
265
267
  }
266
268
  }
@@ -348,79 +350,11 @@ leaf_fixnum_value(Leaf leaf) {
348
350
  leaf->value_type = RUBY_VAL;
349
351
  }
350
352
 
351
- #ifdef JRUBY_RUBY
352
- static void
353
- leaf_float_value(Leaf leaf) {
354
- char *s = leaf->str;
355
- int64_t n = 0;
356
- long a = 0;
357
- long div = 1;
358
- long e = 0;
359
- int neg = 0;
360
- int eneg = 0;
361
- int big = 0;
362
-
363
- if ('-' == *s) {
364
- s++;
365
- neg = 1;
366
- } else if ('+' == *s) {
367
- s++;
368
- }
369
- for (; '0' <= *s && *s <= '9'; s++) {
370
- n = n * 10 + (*s - '0');
371
- if (NUM_MAX <= n) {
372
- big = 1;
373
- }
374
- }
375
- if (big) {
376
- char c = *s;
377
-
378
- *s = '\0';
379
- leaf->value = rb_cstr_to_inum(leaf->str, 10, 0);
380
- *s = c;
381
- } else {
382
- double d;
383
-
384
- if ('.' == *s) {
385
- s++;
386
- for (; '0' <= *s && *s <= '9'; s++) {
387
- a = a * 10 + (*s - '0');
388
- div *= 10;
389
- }
390
- }
391
- if ('e' == *s || 'E' == *s) {
392
- s++;
393
- if ('-' == *s) {
394
- s++;
395
- eneg = 1;
396
- } else if ('+' == *s) {
397
- s++;
398
- }
399
- for (; '0' <= *s && *s <= '9'; s++) {
400
- e = e * 10 + (*s - '0');
401
- }
402
- }
403
- d = (double)n + (double)a / (double)div;
404
- if (neg) {
405
- d = -d;
406
- }
407
- if (0 != e) {
408
- if (eneg) {
409
- e = -e;
410
- }
411
- d *= pow(10.0, e);
412
- }
413
- leaf->value = rb_float_new(d);
414
- }
415
- leaf->value_type = RUBY_VAL;
416
- }
417
- #else
418
353
  static void
419
354
  leaf_float_value(Leaf leaf) {
420
355
  leaf->value = rb_float_new(rb_cstr_to_dbl(leaf->str, 1));
421
356
  leaf->value_type = RUBY_VAL;
422
357
  }
423
- #endif
424
358
 
425
359
  static VALUE
426
360
  leaf_array_value(Doc doc, Leaf leaf) {
@@ -675,33 +609,59 @@ read_nil(ParseInfo pi) {
675
609
  return leaf;
676
610
  }
677
611
 
678
- static char
679
- read_hex(ParseInfo pi, char *h) {
680
- uint8_t b = 0;
612
+ static uint32_t
613
+ read_4hex(ParseInfo pi, const char *h) {
614
+ uint32_t b = 0;
615
+ int i;
616
+
617
+ for (i = 0; i < 4; i++, h++) {
618
+ b = b << 4;
619
+ if ('0' <= *h && *h <= '9') {
620
+ b += *h - '0';
621
+ } else if ('A' <= *h && *h <= 'F') {
622
+ b += *h - 'A' + 10;
623
+ } else if ('a' <= *h && *h <= 'f') {
624
+ b += *h - 'a' + 10;
625
+ } else {
626
+ raise_error("invalid hex character", pi->str, pi->s);
627
+ }
628
+ }
629
+ return b;
630
+ }
681
631
 
682
- if ('0' <= *h && *h <= '9') {
683
- b = *h - '0';
684
- } else if ('A' <= *h && *h <= 'F') {
685
- b = *h - 'A' + 10;
686
- } else if ('a' <= *h && *h <= 'f') {
687
- b = *h - 'a' + 10;
688
- } else {
689
- pi->s = h;
690
- raise_error("invalid hex character", pi->str, pi->s);
691
- }
692
- h++;
693
- b = b << 4;
694
- if ('0' <= *h && *h <= '9') {
695
- b += *h - '0';
696
- } else if ('A' <= *h && *h <= 'F') {
697
- b += *h - 'A' + 10;
698
- } else if ('a' <= *h && *h <= 'f') {
699
- b += *h - 'a' + 10;
632
+ static char*
633
+ unicode_to_chars(ParseInfo pi, char *t, uint32_t code) {
634
+ if (0x0000007F >= code) {
635
+ *t++ = (char)code;
636
+ } else if (0x000007FF >= code) {
637
+ *t++ = 0xC0 | (code >> 6);
638
+ *t++ = 0x80 | (0x3F & code);
639
+ } else if (0x0000FFFF >= code) {
640
+ *t++ = 0xE0 | (code >> 12);
641
+ *t++ = 0x80 | ((code >> 6) & 0x3F);
642
+ *t++ = 0x80 | (0x3F & code);
643
+ } else if (0x001FFFFF >= code) {
644
+ *t++ = 0xF0 | (code >> 18);
645
+ *t++ = 0x80 | ((code >> 12) & 0x3F);
646
+ *t++ = 0x80 | ((code >> 6) & 0x3F);
647
+ *t++ = 0x80 | (0x3F & code);
648
+ } else if (0x03FFFFFF >= code) {
649
+ *t++ = 0xF8 | (code >> 24);
650
+ *t++ = 0x80 | ((code >> 18) & 0x3F);
651
+ *t++ = 0x80 | ((code >> 12) & 0x3F);
652
+ *t++ = 0x80 | ((code >> 6) & 0x3F);
653
+ *t++ = 0x80 | (0x3F & code);
654
+ } else if (0x7FFFFFFF >= code) {
655
+ *t++ = 0xFC | (code >> 30);
656
+ *t++ = 0x80 | ((code >> 24) & 0x3F);
657
+ *t++ = 0x80 | ((code >> 18) & 0x3F);
658
+ *t++ = 0x80 | ((code >> 12) & 0x3F);
659
+ *t++ = 0x80 | ((code >> 6) & 0x3F);
660
+ *t++ = 0x80 | (0x3F & code);
700
661
  } else {
701
- pi->s = h;
702
- raise_error("invalid hex character", pi->str, pi->s);
662
+ raise_error("invalid Unicode character", pi->str, pi->s);
703
663
  }
704
- return (char)b;
664
+ return t;
705
665
  }
706
666
 
707
667
  /* Assume the value starts immediately and goes until the quote character is
@@ -731,16 +691,31 @@ read_quoted_value(ParseInfo pi) {
731
691
  case '"': *t = '"'; break;
732
692
  case '/': *t = '/'; break;
733
693
  case '\\': *t = '\\'; break;
734
- case 'u':
694
+ case 'u': {
695
+ uint32_t code;
696
+
735
697
  h++;
736
- *t = read_hex(pi, h);
737
- h += 2;
738
- if ('\0' != *t) {
739
- t++;
698
+ code = read_4hex(pi, h);
699
+ h += 3;
700
+ if (0x0000D800 <= code && code <= 0x0000DFFF) {
701
+ uint32_t c1 = (code - 0x0000D800) & 0x000003FF;
702
+ uint32_t c2;
703
+
704
+ h++;
705
+ if ('\\' != *h || 'u' != *(h + 1)) {
706
+ pi->s = h;
707
+ raise_error("invalid escaped character", pi->str, pi->s);
708
+ }
709
+ h += 2;
710
+ c2 = read_4hex(pi, h);
711
+ h += 3;
712
+ c2 = (c2 - 0x0000DC00) & 0x000003FF;
713
+ code = ((c1 << 10) | c2) + 0x00010000;
740
714
  }
741
- *t = read_hex(pi, h);
742
- h++;
715
+ t = unicode_to_chars(pi, t, code);
716
+ t--;
743
717
  break;
718
+ }
744
719
  default:
745
720
  pi->s = h;
746
721
  raise_error("invalid escaped character", pi->str, pi->s);
@@ -759,15 +734,10 @@ read_quoted_value(ParseInfo pi) {
759
734
  // doc support functions
760
735
  inline static void
761
736
  doc_init(Doc doc) {
737
+ memset(doc, 0, sizeof(struct _Doc));
762
738
  doc->where = doc->where_path;
763
- *doc->where = 0;
764
- doc->data = 0;
765
739
  doc->self = Qundef;
766
- doc->size = 0;
767
- doc->json = 0;
768
740
  doc->batches = &doc->batch0;
769
- doc->batch0.next = 0;
770
- doc->batch0.next_avail = 0;
771
741
  }
772
742
 
773
743
  static void
@@ -885,7 +855,7 @@ get_doc_leaf(Doc doc, const char *path) {
885
855
  if (MAX_STACK <= cnt) {
886
856
  rb_raise(rb_const_get_at(Oj, rb_intern("DepthError")), "Path too deep. Limit is %d levels.", MAX_STACK);
887
857
  }
888
- memcpy(stack, doc->where_path, sizeof(Leaf) * cnt);
858
+ memcpy(stack, doc->where_path, sizeof(Leaf) * (cnt + 1));
889
859
  lp = stack + cnt;
890
860
  }
891
861
  return get_leaf(stack, lp, path);
@@ -914,7 +884,7 @@ get_leaf(Leaf *stack, Leaf *lp, const char *path) {
914
884
  } else if (COL_VAL == leaf->value_type && 0 != leaf->elements) {
915
885
  Leaf first = leaf->elements->next;
916
886
  Leaf e = first;
917
- int type = leaf->type;
887
+ int type = leaf->rtype;
918
888
 
919
889
  leaf = 0;
920
890
  if (T_ARRAY == type) {
@@ -1021,7 +991,7 @@ move_step(Doc doc, const char *path, int loc) {
1021
991
  Leaf first = leaf->elements->next;
1022
992
  Leaf e = first;
1023
993
 
1024
- if (T_ARRAY == leaf->type) {
994
+ if (T_ARRAY == leaf->rtype) {
1025
995
  int cnt = 0;
1026
996
 
1027
997
  for (; '0' <= *path && *path <= '9'; path++) {
@@ -1046,7 +1016,7 @@ move_step(Doc doc, const char *path, int loc) {
1046
1016
  cnt--;
1047
1017
  e = e->next;
1048
1018
  } while (e != first);
1049
- } else if (T_HASH == leaf->type) {
1019
+ } else if (T_HASH == leaf->rtype) {
1050
1020
  const char *key = path;
1051
1021
  const char *slash = strchr(path, '/');
1052
1022
  int klen;
@@ -1302,7 +1272,7 @@ doc_type(int argc, VALUE *argv, VALUE self) {
1302
1272
  path = StringValuePtr(*argv);
1303
1273
  }
1304
1274
  if (0 != (leaf = get_doc_leaf(doc, path))) {
1305
- switch (leaf->type) {
1275
+ switch (leaf->rtype) {
1306
1276
  case T_NIL: type = rb_cNilClass; break;
1307
1277
  case T_TRUE: type = rb_cTrueClass; break;
1308
1278
  case T_FALSE: type = rb_cFalseClass; break;
@@ -1375,7 +1345,7 @@ doc_each_leaf(int argc, VALUE *argv, VALUE self) {
1375
1345
 
1376
1346
  wlen = doc->where - doc->where_path;
1377
1347
  if (0 < wlen) {
1378
- memcpy(save_path, doc->where_path, sizeof(Leaf) * wlen);
1348
+ memcpy(save_path, doc->where_path, sizeof(Leaf) * (wlen + 1));
1379
1349
  }
1380
1350
  if (1 <= argc) {
1381
1351
  Check_Type(*argv, T_STRING);
@@ -1386,14 +1356,14 @@ doc_each_leaf(int argc, VALUE *argv, VALUE self) {
1386
1356
  }
1387
1357
  if (0 != move_step(doc, path, 1)) {
1388
1358
  if (0 < wlen) {
1389
- memcpy(doc->where_path, save_path, sizeof(Leaf) * wlen);
1359
+ memcpy(doc->where_path, save_path, sizeof(Leaf) * (wlen + 1));
1390
1360
  }
1391
1361
  return Qnil;
1392
1362
  }
1393
1363
  }
1394
1364
  each_leaf(doc, self);
1395
1365
  if (0 < wlen) {
1396
- memcpy(doc->where_path, save_path, sizeof(Leaf) * wlen);
1366
+ memcpy(doc->where_path, save_path, sizeof(Leaf) * (wlen + 1));
1397
1367
  }
1398
1368
  }
1399
1369
  return Qnil;
@@ -1451,7 +1421,7 @@ doc_each_child(int argc, VALUE *argv, VALUE self) {
1451
1421
 
1452
1422
  wlen = doc->where - doc->where_path;
1453
1423
  if (0 < wlen) {
1454
- memcpy(save_path, doc->where_path, sizeof(Leaf) * wlen);
1424
+ memcpy(save_path, doc->where_path, sizeof(Leaf) * (wlen + 1));
1455
1425
  }
1456
1426
  if (1 <= argc) {
1457
1427
  Check_Type(*argv, T_STRING);
@@ -1462,7 +1432,7 @@ doc_each_child(int argc, VALUE *argv, VALUE self) {
1462
1432
  }
1463
1433
  if (0 != move_step(doc, path, 1)) {
1464
1434
  if (0 < wlen) {
1465
- memcpy(doc->where_path, save_path, sizeof(Leaf) * wlen);
1435
+ memcpy(doc->where_path, save_path, sizeof(Leaf) * (wlen + 1));
1466
1436
  }
1467
1437
  return Qnil;
1468
1438
  }
@@ -1479,7 +1449,7 @@ doc_each_child(int argc, VALUE *argv, VALUE self) {
1479
1449
  } while (e != first);
1480
1450
  }
1481
1451
  if (0 < wlen) {
1482
- memcpy(doc->where_path, save_path, sizeof(Leaf) * wlen);
1452
+ memcpy(doc->where_path, save_path, sizeof(Leaf) * (wlen + 1));
1483
1453
  }
1484
1454
  }
1485
1455
  return Qnil;
@@ -179,9 +179,10 @@ typedef struct _StreamWriter {
179
179
  } *StreamWriter;
180
180
 
181
181
  enum {
182
- STR_VAL = 0x00,
183
- COL_VAL = 0x01,
184
- RUBY_VAL = 0x02
182
+ NO_VAL = 0x00,
183
+ STR_VAL = 0x01,
184
+ COL_VAL = 0x02,
185
+ RUBY_VAL = 0x03
185
186
  };
186
187
 
187
188
  typedef struct _Leaf {
@@ -191,11 +192,11 @@ typedef struct _Leaf {
191
192
  size_t index; // array index, 0 is not set
192
193
  };
193
194
  union {
194
- char *str; // pointer to location in json string
195
+ char *str; // pointer to location in json string or allocated
195
196
  struct _Leaf *elements; // array and hash elements
196
197
  VALUE value;
197
198
  };
198
- uint8_t type;
199
+ uint8_t rtype;
199
200
  uint8_t parent_type;
200
201
  uint8_t value_type;
201
202
  } *Leaf;
@@ -1,5 +1,5 @@
1
1
 
2
2
  module Oj
3
3
  # Current version of the module.
4
- VERSION = '2.12.1'
4
+ VERSION = '2.12.2'
5
5
  end
@@ -1,3 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
1
3
  #!/usr/bin/env ruby
2
4
  # encoding: UTF-8
3
5
 
@@ -5,60 +7,47 @@ $: << File.dirname(__FILE__)
5
7
 
6
8
  require 'helper'
7
9
 
8
- require 'oj'
9
- require 'securerandom'
10
-
11
10
  class Handler
12
- def hash_start() {} end
13
- def hash_set(h,k,v) h.store(k,v) end
14
- def array_start() [] end
15
- def array_append(a,v) a << v end
16
- def error(message, line, column)
17
- raise Exception.new(message, line, column)
11
+ def initialize
12
+ @state = []
13
+ end
14
+
15
+ def hash_start
16
+ @state << {}
17
+ @state.last
18
+ end
19
+
20
+ def hash_end
21
+ @state.pop
22
+ end
23
+
24
+ def hash_set(h,k,v)
25
+ h.store(k,v)
18
26
  end
19
- end
20
27
 
21
- json = Oj.dump({"this"=>"object"})
22
-
23
- if true
24
- name = "/tmp/#{SecureRandom.uuid}"
25
- `mkfifo #{name}`
26
- if fork
27
- open(name, 'r+') do |read_io|
28
- p "start reading #{read_io.stat.ftype}"
29
- Oj.sc_parse(Handler.new, read_io) {|v| p v}
30
- p "stop reading"
31
- end
32
- else
33
- open(name, 'w+') do |write_io|
34
- p "start writing #{write_io.stat.ftype} autoclose: #{write_io.autoclose?}"
35
- write_io.write json
36
- write_io.write json
37
- p "stop writing"
38
- end
39
- sleep(1) # make it obvious that there are two threads
40
- open(name, 'w+') do |write_io|
41
- p "start writing #{write_io.stat.ftype}"
42
- write_io.write json
43
- write_io.write json
44
- p "stop writing"
45
- end
28
+ def array_start
29
+ @state << []
30
+ @state.last
46
31
  end
47
- else
48
- IO.pipe do |read_io, write_io|
49
- if fork
50
- write_io.close
51
- p "start reading #{read_io.stat.ftype}"
52
- Oj.sc_parse(Handler.new, read_io) {|v| p v}
53
- p "stop reading"
54
- read_io.close
55
- else
56
- read_io.close
57
- p "start writing #{write_io.stat.ftype}"
58
- write_io.write json
59
- write_io.write json
60
- p "stop writing"
61
- write_io.close
62
- end
32
+
33
+
34
+ def array_end
35
+ @state.pop
36
+ end
37
+
38
+ def array_append(a,v)
39
+ a << v
40
+ end
41
+
42
+ def add_value(v)
43
+ p v
63
44
  end
45
+
46
+ def error(message, line, column); p "ERROR: #{message}" end
64
47
  end
48
+
49
+ $handler = Handler.new
50
+
51
+ IO.popen("cat tst") { |p| puts Oj.sc_parse($handler, p) }
52
+
53
+ #File.open('tst', 'r') { |file| Oj.sc_parse($handler, file) }