oj 2.9.9 → 2.10.0

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: 0a5afd2bda72fb22d683e9a6ed9f3064b423e8fa
4
+ data.tar.gz: b15ae64080dedd08f70ae05fc9dcaff5212ae3c0
5
+ SHA512:
6
+ metadata.gz: bbb37aa63c547484e68159b90896357b02af944abefbf391f4cafedf67baddc213f8592f9907be7c59a267008d43c8a3166ccc066ab60f68704daa854c183e0a
7
+ data.tar.gz: 9a4833e9d76eb017c5cf7b34c7a28c48c8e7d673c18a4df6839100102099558329e2bbe5173cf02955ab98ddcd049187c692bc49c7a24326df2a72cbf065bba4
data/README.md CHANGED
@@ -12,7 +12,7 @@ gem 'oj'
12
12
 
13
13
  ## Documentation
14
14
 
15
- *Documentation*: http://www.ohler.com/oj
15
+ *Documentation*: http://www.ohler.com/oj, http://rubydoc.info/gems/oj
16
16
 
17
17
  ## Source
18
18
 
@@ -26,31 +26,18 @@ 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.9.9
29
+ ### Current Release 2.10.0
30
30
 
31
- - Missed a character map entry. / in ascii mode is now output as / and not \/
31
+ - Using an indent of less than zero will not place newline characters between
32
+ JSON elements when using the string or stream writer.
32
33
 
33
- - Fixed SC parser to not treat all IO that respond to fileno as a file. It not
34
- checks stat and asks if it is a file.
34
+ - new options callback method was added to the Simple Callback Parser. If
35
+ defined the prepare_key() method will be called when an JSON object ket is
36
+ first encountered. The return value is then used as the key in the key-value
37
+ pair.
35
38
 
36
- - Tightened object parsing of non-string hash keys so that just "^#x" is parsed
37
- as a hash pair and not "~#x".
38
-
39
- - Using echo to STDIN as an IO input works around the exception raised when
40
- asking the IO for it's position (IO.pos).
41
-
42
- - Simple Callback Parser now uses the new stream parser for handling files and
43
- IO so that larger files are handled more efficiently and streams are read as
44
- data arrives instead of on close.
45
-
46
- - Handles file FIFO pipes correctly now.
47
-
48
- ### Release 2.9.8
49
-
50
- - Changed escaping back to previous release and added a new escape mode.
51
-
52
- - Strict mode and compat mode no longer parse Infinity or NaN as a valid
53
- number. Both are valid in object mode still.
39
+ - Increased significants digits to 16 from 15. On occasion there may be
40
+ unexpected round off results. Tou avoid those use the bigdecimal options.
54
41
 
55
42
  [Older release notes](http://www.ohler.com/dev/oj_misc/release_notes.html).
56
43
 
@@ -38,10 +38,14 @@
38
38
  #include "encode.h"
39
39
 
40
40
  static void
41
- hash_set_cstr(ParseInfo pi, const char *key, size_t klen, const char *str, size_t len, const char *orig) {
42
- Val parent = stack_peek(&pi->stack);
41
+ hash_set_cstr(ParseInfo pi, Val kval, const char *str, size_t len, const char *orig) {
42
+ const char *key = kval->key;
43
+ int klen = kval->klen;
44
+ Val parent = stack_peek(&pi->stack);
45
+ volatile VALUE rkey = kval->key_val;
43
46
 
44
- if (0 != pi->options.create_id &&
47
+ if (Qundef == rkey &&
48
+ 0 != pi->options.create_id &&
45
49
  *pi->options.create_id == *key &&
46
50
  pi->options.create_id_len == klen &&
47
51
  0 == strncmp(pi->options.create_id, key, klen)) {
@@ -49,12 +53,14 @@ hash_set_cstr(ParseInfo pi, const char *key, size_t klen, const char *str, size_
49
53
  parent->clen = len;
50
54
  } else {
51
55
  volatile VALUE rstr = rb_str_new(str, len);
52
- volatile VALUE rkey = rb_str_new(key, klen);
53
56
 
54
- rstr = oj_encode(rstr);
55
- rkey = oj_encode(rkey);
56
- if (Yes == pi->options.sym_key) {
57
- rkey = rb_str_intern(rkey);
57
+ if (Qundef == rkey) {
58
+ rkey = rb_str_new(key, klen);
59
+ rstr = oj_encode(rstr);
60
+ rkey = oj_encode(rkey);
61
+ if (Yes == pi->options.sym_key) {
62
+ rkey = rb_str_intern(rkey);
63
+ }
58
64
  }
59
65
  rb_hash_aset(parent->val, rkey, rstr);
60
66
  }
@@ -468,7 +468,7 @@ dump_float(VALUE obj, Out out) {
468
468
  } else if (d == (double)(long long int)d) {
469
469
  cnt = sprintf(buf, "%.1f", d); // used sprintf due to bug in snprintf
470
470
  } else {
471
- cnt = sprintf(buf, "%0.15g", d); // used sprintf due to bug in snprintf
471
+ cnt = sprintf(buf, "%0.16g", d); // used sprintf due to bug in snprintf
472
472
  }
473
473
  if (out->end - out->cur <= (long)cnt) {
474
474
  grow(out, cnt);
@@ -2340,7 +2340,7 @@ oj_str_writer_pop(StrWriter sw) {
2340
2340
  *sw->out.cur++ = ']';
2341
2341
  break;
2342
2342
  }
2343
- if (0 == sw->depth) {
2343
+ if (0 == sw->depth && 0 <= sw->out.indent) {
2344
2344
  *sw->out.cur++ = '\n';
2345
2345
  }
2346
2346
  }
@@ -53,15 +53,15 @@ read_long(const char *str, size_t len) {
53
53
  }
54
54
 
55
55
  static VALUE
56
- hash_key(ParseInfo pi, const char *key, size_t klen, char k1) {
56
+ calc_hash_key(ParseInfo pi, Val kval, char k1) {
57
57
  VALUE rkey;
58
58
 
59
59
  if (':' == k1) {
60
- rkey = rb_str_new(key + 1, klen - 1);
60
+ rkey = rb_str_new(kval->key + 1, kval->klen - 1);
61
61
  rkey = oj_encode(rkey);
62
62
  rkey = rb_funcall(rkey, oj_to_sym_id, 0);
63
63
  } else {
64
- rkey = rb_str_new(key, klen);
64
+ rkey = rb_str_new(kval->key, kval->klen);
65
65
  rkey = oj_encode(rkey);
66
66
  if (Yes == pi->options.sym_key) {
67
67
  rkey = rb_str_intern(rkey);
@@ -94,7 +94,10 @@ str_to_value(ParseInfo pi, const char *str, size_t len, const char *orig) {
94
94
  }
95
95
 
96
96
  static int
97
- hat_cstr(ParseInfo pi, Val parent, const char *key, size_t klen, const char *str, size_t len) {
97
+ hat_cstr(ParseInfo pi, Val parent, Val kval, const char *str, size_t len) {
98
+ const char *key = kval->key;
99
+ int klen = kval->klen;
100
+
98
101
  if (2 == klen) {
99
102
  switch (key[1]) {
100
103
  case 'o': // object
@@ -139,9 +142,9 @@ hat_cstr(ParseInfo pi, Val parent, const char *key, size_t klen, const char *str
139
142
  }
140
143
 
141
144
  static int
142
- hat_num(ParseInfo pi, Val parent, const char *key, size_t klen, NumInfo ni) {
143
- if (2 == klen) {
144
- switch (key[1]) {
145
+ hat_num(ParseInfo pi, Val parent, Val kval, NumInfo ni) {
146
+ if (2 == kval->klen) {
147
+ switch (kval->key[1]) {
145
148
  case 't': // time as a float
146
149
  {
147
150
  int64_t nsec = ni->num * 1000000000LL / ni->div;
@@ -256,9 +259,11 @@ copy_ivars(VALUE target, VALUE src) {
256
259
  }
257
260
 
258
261
  static void
259
- set_obj_ivar(Val parent, const char *key, size_t klen, VALUE value) {
260
- ID var_id;
261
- ID *slot;
262
+ set_obj_ivar(Val parent, Val kval, VALUE value) {
263
+ const char *key = kval->key;
264
+ int klen = kval->klen;
265
+ ID var_id;
266
+ ID *slot;
262
267
 
263
268
  if ('~' == *key && Qtrue == rb_obj_is_kind_of(parent->val, rb_eException)) {
264
269
  if (5 == klen && 0 == strncmp("~mesg", key, klen)) {
@@ -315,36 +320,38 @@ set_obj_ivar(Val parent, const char *key, size_t klen, VALUE value) {
315
320
  }
316
321
 
317
322
  static void
318
- hash_set_cstr(ParseInfo pi, const char *key, size_t klen, const char *str, size_t len, const char *orig) {
319
- Val parent = stack_peek(&pi->stack);
323
+ hash_set_cstr(ParseInfo pi, Val kval, const char *str, size_t len, const char *orig) {
324
+ const char *key = kval->key;
325
+ int klen = kval->klen;
326
+ Val parent = stack_peek(&pi->stack);
320
327
 
321
328
  WHICH_TYPE:
322
329
  switch (rb_type(parent->val)) {
323
330
  case T_NIL:
324
331
  parent->odd_args = 0; // make sure it is 0 in case not odd
325
- if ('^' != *key || !hat_cstr(pi, parent, key, klen, str, len)) {
332
+ if ('^' != *key || !hat_cstr(pi, parent, kval, str, len)) {
326
333
  parent->val = rb_hash_new();
327
334
  goto WHICH_TYPE;
328
335
  }
329
336
  break;
330
337
  case T_HASH:
331
- rb_hash_aset(parent->val, hash_key(pi, key, klen, parent->k1), str_to_value(pi, str, len, orig));
338
+ rb_hash_aset(parent->val, calc_hash_key(pi, kval, parent->k1), str_to_value(pi, str, len, orig));
332
339
  break;
333
340
  case T_STRING:
334
341
  if (4 == klen && 's' == *key && 'e' == key[1] && 'l' == key[2] && 'f' == key[3]) {
335
342
  rb_funcall(parent->val, oj_replace_id, 1, str_to_value(pi, str, len, orig));
336
343
  } else {
337
- set_obj_ivar(parent, key, klen, str_to_value(pi, str, len, orig));
344
+ set_obj_ivar(parent, kval, str_to_value(pi, str, len, orig));
338
345
  }
339
346
  break;
340
347
  case T_OBJECT:
341
- set_obj_ivar(parent, key, klen, str_to_value(pi, str, len, orig));
348
+ set_obj_ivar(parent, kval, str_to_value(pi, str, len, orig));
342
349
  break;
343
350
  case T_CLASS:
344
351
  if (0 == parent->odd_args) {
345
352
  oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "%s is not an odd class", rb_class2name(rb_obj_class(parent->val)));
346
353
  return;
347
- } else if (0 != oj_odd_set_arg(parent->odd_args, key, klen, str_to_value(pi, str, len, orig))) {
354
+ } else if (0 != oj_odd_set_arg(parent->odd_args, kval->key, kval->klen, str_to_value(pi, str, len, orig))) {
348
355
  char buf[256];
349
356
 
350
357
  if (sizeof(buf) - 1 <= klen) {
@@ -362,27 +369,29 @@ hash_set_cstr(ParseInfo pi, const char *key, size_t klen, const char *str, size_
362
369
  }
363
370
 
364
371
  static void
365
- hash_set_num(ParseInfo pi, const char *key, size_t klen, NumInfo ni) {
366
- Val parent = stack_peek(&pi->stack);
372
+ hash_set_num(ParseInfo pi, Val kval, NumInfo ni) {
373
+ const char *key = kval->key;
374
+ int klen = kval->klen;
375
+ Val parent = stack_peek(&pi->stack);
367
376
 
368
377
  WHICH_TYPE:
369
378
  switch (rb_type(parent->val)) {
370
379
  case T_NIL:
371
380
  parent->odd_args = 0; // make sure it is 0 in case not odd
372
- if ('^' != *key || !hat_num(pi, parent, key, klen, ni)) {
381
+ if ('^' != *key || !hat_num(pi, parent, kval, ni)) {
373
382
  parent->val = rb_hash_new();
374
383
  goto WHICH_TYPE;
375
384
  }
376
385
  break;
377
386
  case T_HASH:
378
- rb_hash_aset(parent->val, hash_key(pi, key, klen, parent->k1), oj_num_as_value(ni));
387
+ rb_hash_aset(parent->val, calc_hash_key(pi, kval, parent->k1), oj_num_as_value(ni));
379
388
  break;
380
389
  case T_OBJECT:
381
390
  if (2 == klen && '^' == *key && 'i' == key[1] &&
382
391
  !ni->infinity && !ni->neg && 1 == ni->div && 0 == ni->exp && 0 != pi->circ_array) { // fixnum
383
392
  oj_circ_array_set(pi->circ_array, parent->val, ni->i);
384
393
  } else {
385
- set_obj_ivar(parent, key, klen, oj_num_as_value(ni));
394
+ set_obj_ivar(parent, kval, oj_num_as_value(ni));
386
395
  }
387
396
  break;
388
397
  case T_CLASS:
@@ -407,8 +416,10 @@ hash_set_num(ParseInfo pi, const char *key, size_t klen, NumInfo ni) {
407
416
  }
408
417
 
409
418
  static void
410
- hash_set_value(ParseInfo pi, const char *key, size_t klen, VALUE value) {
411
- Val parent = stack_peek(&pi->stack);
419
+ hash_set_value(ParseInfo pi, Val kval, VALUE value) {
420
+ const char *key = kval->key;
421
+ int klen = kval->klen;
422
+ Val parent = stack_peek(&pi->stack);
412
423
 
413
424
  WHICH_TYPE:
414
425
  switch (rb_type(parent->val)) {
@@ -424,7 +435,7 @@ hash_set_value(ParseInfo pi, const char *key, size_t klen, VALUE value) {
424
435
  if (4 == klen && 's' == *key && 'e' == key[1] && 'l' == key[2] && 'f' == key[3]) {
425
436
  rb_funcall(parent->val, oj_replace_id, 1, value);
426
437
  } else {
427
- set_obj_ivar(parent, key, klen, value);
438
+ set_obj_ivar(parent, kval, value);
428
439
  }
429
440
  } else {
430
441
  if (3 <= klen && '^' == *key && '#' == key[1] && T_ARRAY == rb_type(value)) {
@@ -437,7 +448,7 @@ hash_set_value(ParseInfo pi, const char *key, size_t klen, VALUE value) {
437
448
  }
438
449
  rb_hash_aset(parent->val, *a, a[1]);
439
450
  } else {
440
- rb_hash_aset(parent->val, hash_key(pi, key, klen, parent->k1), value);
451
+ rb_hash_aset(parent->val, calc_hash_key(pi, kval, parent->k1), value);
441
452
  }
442
453
  }
443
454
  break;
@@ -445,12 +456,12 @@ hash_set_value(ParseInfo pi, const char *key, size_t klen, VALUE value) {
445
456
  if (4 == klen && 's' == *key && 'e' == key[1] && 'l' == key[2] && 'f' == key[3]) {
446
457
  rb_funcall(parent->val, oj_replace_id, 1, value);
447
458
  } else {
448
- set_obj_ivar(parent, key, klen, value);
459
+ set_obj_ivar(parent, kval, value);
449
460
  }
450
461
  break;
451
462
  case T_STRING: // for subclassed strings
452
463
  case T_OBJECT:
453
- set_obj_ivar(parent, key, klen, value);
464
+ set_obj_ivar(parent, kval, value);
454
465
  break;
455
466
  case T_CLASS:
456
467
  if (0 == parent->odd_args) {
@@ -62,6 +62,7 @@ ID oj_file_id;
62
62
  ID oj_fileno_id;
63
63
  ID oj_ftype_id;
64
64
  ID oj_hash_end_id;
65
+ ID oj_hash_key_id;
65
66
  ID oj_hash_set_id;
66
67
  ID oj_hash_start_id;
67
68
  ID oj_iconv_id;
@@ -180,7 +181,7 @@ static VALUE define_mimic_json(int argc, VALUE *argv, VALUE self);
180
181
  /* call-seq: default_options() => Hash
181
182
  *
182
183
  * Returns the default load and dump options as a Hash. The options are
183
- * - indent: [Fixnum] number of spaces to indent each element in an JSON document
184
+ * - indent: [Fixnum] number of spaces to indent each element in an JSON document, zero is no newline between JSON elements, negative indicates no newline between top level JSON elements in a stream
184
185
  * - circular: [true|false|nil] support circular references while dumping
185
186
  * - auto_define: [true|false|nil] automatically define classes if they do not exist
186
187
  * - symbol_keys: [true|false|nil] use symbols instead of strings for hash keys
@@ -1959,6 +1960,7 @@ void Init_oj() {
1959
1960
  oj_fileno_id = rb_intern("fileno");
1960
1961
  oj_ftype_id = rb_intern("ftype");
1961
1962
  oj_hash_end_id = rb_intern("hash_end");
1963
+ oj_hash_key_id = rb_intern("hash_key");
1962
1964
  oj_hash_set_id = rb_intern("hash_set");
1963
1965
  oj_hash_start_id = rb_intern("hash_start");
1964
1966
  oj_iconv_id = rb_intern("iconv");
@@ -259,6 +259,7 @@ extern ID oj_file_id;
259
259
  extern ID oj_fileno_id;
260
260
  extern ID oj_ftype_id;
261
261
  extern ID oj_hash_end_id;
262
+ extern ID oj_hash_key_id;
262
263
  extern ID oj_hash_set_id;
263
264
  extern ID oj_hash_start_id;
264
265
  extern ID oj_iconv_id;
@@ -48,7 +48,7 @@
48
48
  #define NUM_MAX (FIXNUM_MAX >> 8)
49
49
  #endif
50
50
  #define EXP_MAX 1023
51
- #define DEC_MAX 14
51
+ #define DEC_MAX 15
52
52
 
53
53
  static void
54
54
  next_non_white(ParseInfo pi) {
@@ -110,8 +110,8 @@ add_value(ParseInfo pi, VALUE rval) {
110
110
  parent->next = NEXT_ARRAY_COMMA;
111
111
  break;
112
112
  case NEXT_HASH_VALUE:
113
- pi->hash_set_value(pi, parent->key, parent->klen, rval);
114
- if (0 != parent->key && (parent->key < pi->json || pi->cur < parent->key)) {
113
+ pi->hash_set_value(pi, parent, rval);
114
+ if (0 != parent->key && 0 < parent->klen && (parent->key < pi->json || pi->cur < parent->key)) {
115
115
  xfree((char*)parent->key);
116
116
  parent->key = 0;
117
117
  }
@@ -295,15 +295,19 @@ read_escaped_str(ParseInfo pi, const char *start) {
295
295
  break;
296
296
  case NEXT_HASH_NEW:
297
297
  case NEXT_HASH_KEY:
298
- // key will not be between pi->json and pi->cur.
299
- parent->key = strdup(buf.head);
300
- parent->klen = buf_len(&buf);
298
+ if (Qundef == (parent->key_val = pi->hash_key(pi, buf.head, buf_len(&buf)))) {
299
+ parent->key = strdup(buf.head);
300
+ parent->klen = buf_len(&buf);
301
+ } else {
302
+ parent->key = "";
303
+ parent->klen = 0;
304
+ }
301
305
  parent->k1 = *start;
302
306
  parent->next = NEXT_HASH_COLON;
303
307
  break;
304
308
  case NEXT_HASH_VALUE:
305
- pi->hash_set_cstr(pi, parent->key, parent->klen, buf.head, buf_len(&buf), start);
306
- if (0 != parent->key && (parent->key < pi->json || pi->cur < parent->key)) {
309
+ pi->hash_set_cstr(pi, parent, buf.head, buf_len(&buf), start);
310
+ if (0 != parent->key && 0 < parent->klen && (parent->key < pi->json || pi->cur < parent->key)) {
307
311
  xfree((char*)parent->key);
308
312
  parent->key = 0;
309
313
  }
@@ -350,14 +354,19 @@ read_str(ParseInfo pi) {
350
354
  break;
351
355
  case NEXT_HASH_NEW:
352
356
  case NEXT_HASH_KEY:
353
- parent->key = str;
354
- parent->klen = pi->cur - str;
357
+ if (Qundef == (parent->key_val = pi->hash_key(pi, str, pi->cur - str))) {
358
+ parent->key = str;
359
+ parent->klen = pi->cur - str;
360
+ } else {
361
+ parent->key = "";
362
+ parent->klen = 0;
363
+ }
355
364
  parent->k1 = *str;
356
365
  parent->next = NEXT_HASH_COLON;
357
366
  break;
358
367
  case NEXT_HASH_VALUE:
359
- pi->hash_set_cstr(pi, parent->key, parent->klen, str, pi->cur - str, str);
360
- if (0 != parent->key && (parent->key < pi->json || pi->cur < parent->key)) {
368
+ pi->hash_set_cstr(pi, parent, str, pi->cur - str, str);
369
+ if (0 != parent->key && 0 < parent->klen && (parent->key < pi->json || pi->cur < parent->key)) {
361
370
  xfree((char*)parent->key);
362
371
  parent->key = 0;
363
372
  }
@@ -487,8 +496,8 @@ read_num(ParseInfo pi) {
487
496
  parent->next = NEXT_ARRAY_COMMA;
488
497
  break;
489
498
  case NEXT_HASH_VALUE:
490
- pi->hash_set_num(pi, parent->key, parent->klen, &ni);
491
- if (0 != parent->key && (parent->key < pi->json || pi->cur < parent->key)) {
499
+ pi->hash_set_num(pi, parent, &ni);
500
+ if (0 != parent->key && 0 < parent->klen && (parent->key < pi->json || pi->cur < parent->key)) {
492
501
  xfree((char*)parent->key);
493
502
  parent->key = 0;
494
503
  }
@@ -702,13 +711,13 @@ oj_num_as_value(NumInfo ni) {
702
711
  rnum = rb_funcall(rnum, rb_intern("to_f"), 0);
703
712
  }
704
713
  } else {
705
- double d = (double)ni->i + (double)ni->num / (double)ni->div;
714
+ double d = (double)ni->i + (double)ni->num * (1.0L / ni->div);
706
715
 
707
716
  if (ni->neg) {
708
717
  d = -d;
709
718
  }
710
719
  if (0 != ni->exp) {
711
- d *= pow(10.0, ni->exp);
720
+ d *= pow(10.0L, ni->exp);
712
721
  }
713
722
  rnum = rb_float_new(d);
714
723
  }
@@ -72,9 +72,10 @@ typedef struct _ParseInfo {
72
72
  VALUE proc;
73
73
  VALUE (*start_hash)(struct _ParseInfo *pi);
74
74
  void (*end_hash)(struct _ParseInfo *pi);
75
- void (*hash_set_cstr)(struct _ParseInfo *pi, const char *key, size_t klen, const char *str, size_t len, const char *orig);
76
- void (*hash_set_num)(struct _ParseInfo *pi, const char *key, size_t klen, NumInfo ni);
77
- void (*hash_set_value)(struct _ParseInfo *pi, const char *key, size_t klen, VALUE value);
75
+ VALUE (*hash_key)(struct _ParseInfo *pi, const char *key, size_t klen);
76
+ void (*hash_set_cstr)(struct _ParseInfo *pi, Val kval, const char *str, size_t len, const char *orig);
77
+ void (*hash_set_num)(struct _ParseInfo *pi, Val kval, NumInfo ni);
78
+ void (*hash_set_value)(struct _ParseInfo *pi, Val kval, VALUE value);
78
79
 
79
80
  VALUE (*start_array)(struct _ParseInfo *pi);
80
81
  void (*end_array)(struct _ParseInfo *pi);
@@ -60,16 +60,21 @@ static void
60
60
  noop_add_num(ParseInfo pi, NumInfo ni) {
61
61
  }
62
62
 
63
+ static VALUE
64
+ noop_hash_key(struct _ParseInfo *pi, const char *key, size_t klen) {
65
+ return Qundef;
66
+ }
67
+
63
68
  static void
64
- noop_hash_set_cstr(ParseInfo pi, const char *key, size_t klen, const char *str, size_t len, const char *orig) {
69
+ noop_hash_set_cstr(ParseInfo pi, Val kval, const char *str, size_t len, const char *orig) {
65
70
  }
66
71
 
67
72
  static void
68
- noop_hash_set_num(ParseInfo pi, const char *key, size_t klen, NumInfo ni) {
73
+ noop_hash_set_num(ParseInfo pi, Val kval, NumInfo ni) {
69
74
  }
70
75
 
71
76
  static void
72
- noop_hash_set_value(ParseInfo pi, const char *key, size_t klen, VALUE value) {
77
+ noop_hash_set_value(ParseInfo pi, Val kval, VALUE value) {
73
78
  }
74
79
 
75
80
  static void
@@ -123,32 +128,40 @@ end_array(ParseInfo pi) {
123
128
  }
124
129
 
125
130
  static VALUE
126
- hash_key(ParseInfo pi, const char *key, size_t klen) {
127
- volatile VALUE rkey = rb_str_new(key, klen);
128
-
129
- rkey = oj_encode(rkey);
130
- if (Yes == pi->options.sym_key) {
131
- rkey = rb_str_intern(rkey);
131
+ calc_hash_key(ParseInfo pi, Val kval) {
132
+ volatile VALUE rkey = kval->key_val;
133
+
134
+ if (Qundef == rkey) {
135
+ rkey = rb_str_new(kval->key, kval->klen);
136
+ rkey = oj_encode(rkey);
137
+ if (Yes == pi->options.sym_key) {
138
+ rkey = rb_str_intern(rkey);
139
+ }
132
140
  }
133
141
  return rkey;
134
142
  }
135
143
 
144
+ static VALUE
145
+ hash_key(struct _ParseInfo *pi, const char *key, size_t klen) {
146
+ return rb_funcall(pi->handler, oj_hash_key_id, 1, rb_str_new(key, klen));
147
+ }
148
+
136
149
  static void
137
- hash_set_cstr(ParseInfo pi, const char *key, size_t klen, const char *str, size_t len, const char *orig) {
150
+ hash_set_cstr(ParseInfo pi, Val kval, const char *str, size_t len, const char *orig) {
138
151
  volatile VALUE rstr = rb_str_new(str, len);
139
152
 
140
153
  rstr = oj_encode(rstr);
141
- rb_funcall(pi->handler, oj_hash_set_id, 3, stack_peek(&pi->stack)->val, hash_key(pi, key, klen), rstr);
154
+ rb_funcall(pi->handler, oj_hash_set_id, 3, stack_peek(&pi->stack)->val, calc_hash_key(pi, kval), rstr);
142
155
  }
143
156
 
144
157
  static void
145
- hash_set_num(ParseInfo pi, const char *key, size_t klen, NumInfo ni) {
146
- rb_funcall(pi->handler, oj_hash_set_id, 3, stack_peek(&pi->stack)->val, hash_key(pi, key, klen), oj_num_as_value(ni));
158
+ hash_set_num(ParseInfo pi, Val kval, NumInfo ni) {
159
+ rb_funcall(pi->handler, oj_hash_set_id, 3, stack_peek(&pi->stack)->val, calc_hash_key(pi, kval), oj_num_as_value(ni));
147
160
  }
148
161
 
149
162
  static void
150
- hash_set_value(ParseInfo pi, const char *key, size_t klen, VALUE value) {
151
- rb_funcall(pi->handler, oj_hash_set_id, 3, stack_peek(&pi->stack)->val, hash_key(pi, key, klen), value);
163
+ hash_set_value(ParseInfo pi, Val kval, VALUE value) {
164
+ rb_funcall(pi->handler, oj_hash_set_id, 3, stack_peek(&pi->stack)->val, calc_hash_key(pi, kval), value);
152
165
  }
153
166
 
154
167
  static void
@@ -187,6 +200,7 @@ oj_sc_parse(int argc, VALUE *argv, VALUE self) {
187
200
 
188
201
  pi.start_hash = rb_respond_to(pi.handler, oj_hash_start_id) ? start_hash : noop_start;
189
202
  pi.end_hash = rb_respond_to(pi.handler, oj_hash_end_id) ? end_hash : noop_end;
203
+ pi.hash_key = rb_respond_to(pi.handler, oj_hash_key_id) ? hash_key : noop_hash_key;
190
204
  pi.start_array = rb_respond_to(pi.handler, oj_array_start_id) ? start_array : noop_start;
191
205
  pi.end_array = rb_respond_to(pi.handler, oj_array_end_id) ? end_array : noop_end;
192
206
  if (rb_respond_to(pi.handler, oj_hash_set_id)) {