oj 3.7.7 → 3.7.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
  SHA256:
3
- metadata.gz: 389ece68dade91713fa132445f6b5d7cefdef5b6e7787a8b66f530c13173271c
4
- data.tar.gz: 49d899629ebbb41cb5b545400262f1644b93140c62b57f7f8c7ef98200ad2bb9
3
+ metadata.gz: 5008cd86952b184d31350d5e84256ca433e3dafe672c04400cd8d74bbc6190f4
4
+ data.tar.gz: 620b94ba6107477d17eda4d2f3558f1aa98d3c6635bdbb16443ba2b5868aeb57
5
5
  SHA512:
6
- metadata.gz: 15c6bd0b3324687ef248e2f67270bab76b1c70da8e92b54dc474082ae717d601142a745a7e365b3ffdf82c1b6fbb12d72cdb7db3cdefb34a50b3eaf28c941786
7
- data.tar.gz: 28fa1bb71e89c195ccb840d6c4b639ffc5c2244eba48aa69aab07cc76757b954ddffbe83801eb6624745ab21c73e5493c4858cbcbfa630f6a3df2a5a2d3899b8
6
+ metadata.gz: c1641f5af216aab8948c70c5c0e75f6f9fc6db9de5eca5cafad65b7fc6b877cded31bbf9f5b0fdb438217bfeae7c04cb880ec1b560771e0b341a0f1292f3c1e3
7
+ data.tar.gz: 1e3a1f8ee9b47fb8004cc53992ae68e5cceb055a53daecc73771ebccf3d3edcefeaac70e58f740279482e49eca89f32d38866a3412d67efdb9738f4e80c8c2e2
@@ -3,6 +3,7 @@
3
3
  * All rights reserved.
4
4
  */
5
5
 
6
+ #include <stdint.h>
6
7
  #include <stdio.h>
7
8
 
8
9
  #include "code.h"
@@ -15,6 +16,7 @@
15
16
  #include "parse.h"
16
17
  #include "resolve.h"
17
18
  #include "trace.h"
19
+ #include "util.h"
18
20
 
19
21
  extern void oj_set_obj_ivar(Val parent, Val kval, VALUE value);
20
22
  extern VALUE oj_parse_xml_time(const char *str, int len); // from object.c
@@ -1058,16 +1060,18 @@ hash_set_num(struct _parseInfo *pi, Val kval, NumInfo ni) {
1058
1060
  // match the expected value.
1059
1061
  parent->val = rb_funcall2(parent->val, oj_utc_id, 0, 0);
1060
1062
  } else if (ni->hasExp) {
1061
- time_t t = (time_t)(ni->i + ni->exp);
1062
- struct tm *st = gmtime(&t);
1063
- VALUE args[8];
1064
-
1065
- args[0] = LONG2NUM(1900 + st->tm_year);
1066
- args[1] = LONG2NUM(1 + st->tm_mon);
1067
- args[2] = LONG2NUM(st->tm_mday);
1068
- args[3] = LONG2NUM(st->tm_hour);
1069
- args[4] = LONG2NUM(st->tm_min);
1070
- args[5] = rb_float_new((double)st->tm_sec + ((double)nsec + 0.5) / 1000000000.0);
1063
+ int64_t t = (int64_t)(ni->i + ni->exp);
1064
+ struct _timeInfo ti;
1065
+ VALUE args[8];
1066
+
1067
+ sec_as_time(t, &ti);
1068
+
1069
+ args[0] = LONG2NUM(ti.year);
1070
+ args[1] = LONG2NUM(ti.mon);
1071
+ args[2] = LONG2NUM(ti.day);
1072
+ args[3] = LONG2NUM(ti.hour);
1073
+ args[4] = LONG2NUM(ti.min);
1074
+ args[5] = rb_float_new((double)ti.sec + ((double)nsec + 0.5) / 1000000000.0);
1071
1075
  args[6] = LONG2NUM(ni->exp);
1072
1076
  parent->val = rb_funcall2(rb_cTime, oj_new_id, 7, args);
1073
1077
  } else {
@@ -3,22 +3,19 @@
3
3
  * All rights reserved.
4
4
  */
5
5
 
6
- #include <stdlib.h>
7
6
  #include <errno.h>
8
- #if !IS_WINDOWS
9
- #include <sys/time.h>
10
- #endif
11
- #include <time.h>
7
+ #include <math.h>
8
+ #include <stdint.h>
12
9
  #include <stdio.h>
10
+ #include <stdlib.h>
13
11
  #include <string.h>
14
- #include <math.h>
15
12
  #include <unistd.h>
16
- #include <errno.h>
17
13
 
18
14
  #include "oj.h"
19
15
  #include "cache8.h"
20
16
  #include "dump.h"
21
17
  #include "odd.h"
18
+ #include "util.h"
22
19
 
23
20
  // Workaround in case INFINITY is not defined in math.h or if the OS is CentOS
24
21
  #define OJ_INFINITY (1.0/0.0)
@@ -493,14 +490,14 @@ oj_dump_ruby_time(VALUE obj, Out out) {
493
490
 
494
491
  void
495
492
  oj_dump_xml_time(VALUE obj, Out out) {
496
- char buf[64];
497
- struct tm *tm;
498
- long one = 1000000000;
499
- time_t sec;
500
- long long nsec;
501
- long tzsecs = NUM2LONG(rb_funcall2(obj, oj_utc_offset_id, 0, 0));
502
- int tzhour, tzmin;
503
- char tzsign = '+';
493
+ char buf[64];
494
+ struct _timeInfo ti;
495
+ long one = 1000000000;
496
+ int64_t sec;
497
+ long long nsec;
498
+ long tzsecs = NUM2LONG(rb_funcall2(obj, oj_utc_offset_id, 0, 0));
499
+ int tzhour, tzmin;
500
+ char tzsign = '+';
504
501
 
505
502
  #ifdef HAVE_RB_TIME_TIMESPEC
506
503
  if (16 <= sizeof(struct timespec)) {
@@ -541,8 +538,7 @@ oj_dump_xml_time(VALUE obj, Out out) {
541
538
  // 2012-01-05T23:58:07.123456000+09:00
542
539
  //tm = localtime(&sec);
543
540
  sec += tzsecs;
544
- tm = gmtime(&sec);
545
- #if 1
541
+ sec_as_time((int64_t)sec, &ti);
546
542
  if (0 > tzsecs) {
547
543
  tzsign = '-';
548
544
  tzhour = (int)(tzsecs / -3600);
@@ -551,26 +547,12 @@ oj_dump_xml_time(VALUE obj, Out out) {
551
547
  tzhour = (int)(tzsecs / 3600);
552
548
  tzmin = (int)(tzsecs / 60) - (tzhour * 60);
553
549
  }
554
- #else
555
- if (0 > tm->tm_gmtoff) {
556
- tzsign = '-';
557
- tzhour = (int)(tm->tm_gmtoff / -3600);
558
- tzmin = (int)(tm->tm_gmtoff / -60) - (tzhour * 60);
559
- } else {
560
- tzhour = (int)(tm->tm_gmtoff / 3600);
561
- tzmin = (int)(tm->tm_gmtoff / 60) - (tzhour * 60);
562
- }
563
- #endif
564
550
  if (0 == nsec || 0 == out->opts->sec_prec) {
565
551
  if (0 == tzsecs && rb_funcall2(obj, oj_utcq_id, 0, 0)) {
566
- sprintf(buf, "%04d-%02d-%02dT%02d:%02d:%02dZ",
567
- tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
568
- tm->tm_hour, tm->tm_min, tm->tm_sec);
552
+ sprintf(buf, "%04d-%02d-%02dT%02d:%02d:%02dZ", ti.year, ti.mon, ti.day, ti.hour, ti.min, ti.sec);
569
553
  oj_dump_cstr(buf, 20, 0, 0, out);
570
554
  } else {
571
- sprintf(buf, "%04d-%02d-%02dT%02d:%02d:%02d%c%02d:%02d",
572
- tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
573
- tm->tm_hour, tm->tm_min, tm->tm_sec,
555
+ sprintf(buf, "%04d-%02d-%02dT%02d:%02d:%02d%c%02d:%02d", ti.year, ti.mon, ti.day, ti.hour, ti.min, ti.sec,
574
556
  tzsign, tzhour, tzmin);
575
557
  oj_dump_cstr(buf, 25, 0, 0, out);
576
558
  }
@@ -582,9 +564,7 @@ oj_dump_xml_time(VALUE obj, Out out) {
582
564
  format[32] = '0' + out->opts->sec_prec;
583
565
  len -= 9 - out->opts->sec_prec;
584
566
  }
585
- sprintf(buf, format,
586
- tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
587
- tm->tm_hour, tm->tm_min, tm->tm_sec, (long)nsec);
567
+ sprintf(buf, format, ti.year, ti.mon, ti.day, ti.hour, ti.min, ti.sec, (long)nsec);
588
568
  oj_dump_cstr(buf, len, 0, 0, out);
589
569
  } else {
590
570
  char format[64] = "%04d-%02d-%02dT%02d:%02d:%02d.%09ld%c%02d:%02d";
@@ -594,10 +574,7 @@ oj_dump_xml_time(VALUE obj, Out out) {
594
574
  format[32] = '0' + out->opts->sec_prec;
595
575
  len -= 9 - out->opts->sec_prec;
596
576
  }
597
- sprintf(buf, format,
598
- tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
599
- tm->tm_hour, tm->tm_min, tm->tm_sec, (long)nsec,
600
- tzsign, tzhour, tzmin);
577
+ sprintf(buf, format, ti.year, ti.mon, ti.day, ti.hour, ti.min, ti.sec, (long)nsec, tzsign, tzhour, tzmin);
601
578
  oj_dump_cstr(buf, len, 0, 0, out);
602
579
  }
603
580
  }
@@ -819,6 +819,8 @@ parse_json(VALUE clas, char *json, bool given, bool allocated) {
819
819
  int ex = 0;
820
820
  volatile VALUE self;
821
821
 
822
+ // TBD are both needed? is stack allocation ever needed?
823
+
822
824
  if (given) {
823
825
  doc = ALLOCA_N(struct _doc, 1);
824
826
  } else {
@@ -862,6 +864,7 @@ parse_json(VALUE clas, char *json, bool given, bool allocated) {
862
864
  if (allocated && 0 != ex) { // will jump so caller will not free
863
865
  xfree(json);
864
866
  }
867
+ rb_gc_enable();
865
868
  } else {
866
869
  result = doc->self;
867
870
  }
@@ -1165,8 +1168,14 @@ doc_open(VALUE clas, VALUE str) {
1165
1168
  } else {
1166
1169
  json = ALLOCA_N(char, len);
1167
1170
  }
1171
+ // It should not be necessaary to stop GC but if it is not stopped and a
1172
+ // large string is parsed that string is corrupted or freed during
1173
+ // parsing. I'm not sure what is going on exactly but disabling GC avoids
1174
+ // the issue.
1175
+ rb_gc_disable();
1168
1176
  memcpy(json, StringValuePtr(str), len);
1169
1177
  obj = parse_json(clas, json, given, allocate);
1178
+ rb_gc_enable();
1170
1179
  if (given && allocate) {
1171
1180
  xfree(json);
1172
1181
  }
@@ -1222,7 +1231,9 @@ doc_open_file(VALUE clas, VALUE filename) {
1222
1231
  }
1223
1232
  fclose(f);
1224
1233
  json[len] = '\0';
1234
+ rb_gc_disable();
1225
1235
  obj = parse_json(clas, json, given, allocate);
1236
+ rb_gc_enable();
1226
1237
  if (given && allocate) {
1227
1238
  xfree(json);
1228
1239
  }
@@ -3,6 +3,7 @@
3
3
  * All rights reserved.
4
4
  */
5
5
 
6
+ #include <stdint.h>
6
7
  #include <stdio.h>
7
8
  #include <time.h>
8
9
 
@@ -14,6 +15,7 @@
14
15
  #include "odd.h"
15
16
  #include "encode.h"
16
17
  #include "trace.h"
18
+ #include "util.h"
17
19
 
18
20
  inline static long
19
21
  read_long(const char *str, size_t len) {
@@ -291,24 +293,19 @@ hat_num(ParseInfo pi, Val parent, Val kval, NumInfo ni) {
291
293
  // match the expected value.
292
294
  parent->val = rb_funcall2(parent->val, oj_utc_id, 0, 0);
293
295
  } else if (ni->hasExp) {
294
- time_t t = (time_t)(ni->i + ni->exp);
295
- struct tm *st = gmtime(&t);
296
- VALUE args[8];
297
-
298
- // Windows does not support dates before 1970 so ignore
299
- // the zone and do the best we can.
300
- if (NULL == st) {
301
- parent->val = rb_time_nano_new(ni->i, (long)nsec);
302
- } else {
303
- args[0] = LONG2NUM((long)(1900 + st->tm_year));
304
- args[1] = LONG2NUM(1 + st->tm_mon);
305
- args[2] = LONG2NUM(st->tm_mday);
306
- args[3] = LONG2NUM(st->tm_hour);
307
- args[4] = LONG2NUM(st->tm_min);
308
- args[5] = rb_float_new((double)st->tm_sec + ((double)nsec + 0.5) / 1000000000.0);
309
- args[6] = LONG2NUM(ni->exp);
310
- parent->val = rb_funcall2(rb_cTime, oj_new_id, 7, args);
311
- }
296
+ int64_t t = (int64_t)(ni->i + ni->exp);
297
+ struct _timeInfo ti;
298
+ VALUE args[8];
299
+
300
+ sec_as_time(t, &ti);
301
+ args[0] = LONG2NUM((long)(ti.year));
302
+ args[1] = LONG2NUM(ti.mon);
303
+ args[2] = LONG2NUM(ti.day);
304
+ args[3] = LONG2NUM(ti.hour);
305
+ args[4] = LONG2NUM(ti.min);
306
+ args[5] = rb_float_new((double)ti.sec + ((double)nsec + 0.5) / 1000000000.0);
307
+ args[6] = LONG2NUM(ni->exp);
308
+ parent->val = rb_funcall2(rb_cTime, oj_new_id, 7, args);
312
309
  } else {
313
310
  parent->val = rb_time_nano_new(ni->i, (long)nsec);
314
311
  }
@@ -462,7 +459,7 @@ hash_set_cstr(ParseInfo pi, Val kval, const char *str, size_t len, const char *o
462
459
  WHICH_TYPE:
463
460
  switch (rb_type(parent->val)) {
464
461
  case T_NIL:
465
- parent->odd_args = 0; // make sure it is 0 in case not odd
462
+ parent->odd_args = NULL; // make sure it is NULL in case not odd
466
463
  if ('^' != *key || !hat_cstr(pi, parent, kval, str, len)) {
467
464
  parent->val = rb_hash_new();
468
465
  goto WHICH_TYPE;
@@ -484,7 +481,7 @@ hash_set_cstr(ParseInfo pi, Val kval, const char *str, size_t len, const char *o
484
481
  oj_set_obj_ivar(parent, kval, rval);
485
482
  break;
486
483
  case T_CLASS:
487
- if (0 == parent->odd_args) {
484
+ if (NULL == parent->odd_args) {
488
485
  oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "%s is not an odd class", rb_class2name(rb_obj_class(parent->val)));
489
486
  return;
490
487
  } else {
@@ -520,7 +517,7 @@ hash_set_num(ParseInfo pi, Val kval, NumInfo ni) {
520
517
  WHICH_TYPE:
521
518
  switch (rb_type(parent->val)) {
522
519
  case T_NIL:
523
- parent->odd_args = 0; // make sure it is 0 in case not odd
520
+ parent->odd_args = NULL; // make sure it is NULL in case not odd
524
521
  if ('^' != *key || !hat_num(pi, parent, kval, ni)) {
525
522
  parent->val = rb_hash_new();
526
523
  goto WHICH_TYPE;
@@ -540,7 +537,7 @@ hash_set_num(ParseInfo pi, Val kval, NumInfo ni) {
540
537
  }
541
538
  break;
542
539
  case T_CLASS:
543
- if (0 == parent->odd_args) {
540
+ if (NULL == parent->odd_args) {
544
541
  oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "%s is not an odd class", rb_class2name(rb_obj_class(parent->val)));
545
542
  return;
546
543
  } else {
@@ -575,7 +572,7 @@ hash_set_value(ParseInfo pi, Val kval, VALUE value) {
575
572
  WHICH_TYPE:
576
573
  switch (rb_type(parent->val)) {
577
574
  case T_NIL:
578
- parent->odd_args = 0; // make sure it is 0 in case not odd
575
+ parent->odd_args = NULL; // make sure it is NULL in case not odd
579
576
  if ('^' != *key || !hat_value(pi, parent, key, klen, value)) {
580
577
  parent->val = rb_hash_new();
581
578
  goto WHICH_TYPE;
@@ -616,7 +613,7 @@ hash_set_value(ParseInfo pi, Val kval, VALUE value) {
616
613
  break;
617
614
  case T_MODULE:
618
615
  case T_CLASS:
619
- if (0 == parent->odd_args) {
616
+ if (NULL == parent->odd_args) {
620
617
  oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "%s is not an odd class", rb_class2name(rb_obj_class(parent->val)));
621
618
  return;
622
619
  } else if (0 != oj_odd_set_arg(parent->odd_args, key, klen, value)) {
@@ -653,12 +650,12 @@ end_hash(ParseInfo pi) {
653
650
 
654
651
  if (Qnil == parent->val) {
655
652
  parent->val = rb_hash_new();
656
- } else if (0 != parent->odd_args) {
653
+ } else if (NULL != parent->odd_args) {
657
654
  OddArgs oa = parent->odd_args;
658
655
 
659
656
  parent->val = rb_funcall2(oa->odd->create_obj, oa->odd->create_op, oa->odd->attr_cnt, oa->args);
660
657
  oj_odd_free(oa);
661
- parent->odd_args = 0;
658
+ parent->odd_args = NULL;
662
659
  }
663
660
  if (Yes == pi->options.trace) {
664
661
  oj_trace_parse_hash_end(pi, __FILE__, __LINE__);
@@ -38,11 +38,11 @@ set_class(Odd odd, const char *classname) {
38
38
 
39
39
  static VALUE
40
40
  get_datetime_secs(VALUE obj) {
41
- VALUE rsecs = rb_funcall(obj, sec_id, 0);
42
- VALUE rfrac = rb_funcall(obj, sec_fraction_id, 0);
43
- long sec = NUM2LONG(rsecs);
44
- long long num = rb_num2ll(rb_funcall(rfrac, numerator_id, 0));
45
- long long den = rb_num2ll(rb_funcall(rfrac, denominator_id, 0));
41
+ volatile VALUE rsecs = rb_funcall(obj, sec_id, 0);
42
+ volatile VALUE rfrac = rb_funcall(obj, sec_fraction_id, 0);
43
+ long sec = NUM2LONG(rsecs);
44
+ long long num = rb_num2ll(rb_funcall(rfrac, numerator_id, 0));
45
+ long long den = rb_num2ll(rb_funcall(rfrac, denominator_id, 0));
46
46
 
47
47
  num += sec * den;
48
48
 
@@ -8,6 +8,7 @@
8
8
  #include "code.h"
9
9
  #include "encode.h"
10
10
  #include "trace.h"
11
+ #include "util.h"
11
12
 
12
13
  #define OJ_INFINITY (1.0/0.0)
13
14
 
@@ -221,9 +222,9 @@ dump_bigdecimal(VALUE obj, int depth, Out out, bool as_ok) {
221
222
  }
222
223
 
223
224
  static void
224
- dump_sec_nano(VALUE obj, time_t sec, long nsec, Out out) {
225
+ dump_sec_nano(VALUE obj, int64_t sec, long nsec, Out out) {
225
226
  char buf[64];
226
- struct tm *tm;
227
+ struct _timeInfo ti;
227
228
  long one = 1000000000;
228
229
  long tzsecs = NUM2LONG(rb_funcall2(obj, oj_utc_offset_id, 0, 0));
229
230
  int tzhour, tzmin;
@@ -248,7 +249,7 @@ dump_sec_nano(VALUE obj, time_t sec, long nsec, Out out) {
248
249
  }
249
250
  // 2012-01-05T23:58:07.123456000+09:00 or 2012/01/05 23:58:07 +0900
250
251
  sec += tzsecs;
251
- tm = gmtime(&sec);
252
+ sec_as_time(sec, &ti);
252
253
  if (0 > tzsecs) {
253
254
  tzsign = '-';
254
255
  tzhour = (int)(tzsecs / -3600);
@@ -258,19 +259,12 @@ dump_sec_nano(VALUE obj, time_t sec, long nsec, Out out) {
258
259
  tzmin = (int)(tzsecs / 60) - (tzhour * 60);
259
260
  }
260
261
  if (!xml_time) {
261
- len = sprintf(buf, "%04d/%02d/%02d %02d:%02d:%02d %c%02d%02d",
262
- tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
263
- tm->tm_hour, tm->tm_min, tm->tm_sec, tzsign, tzhour, tzmin);
262
+ len = sprintf(buf, "%04d/%02d/%02d %02d:%02d:%02d %c%02d%02d", ti.year, ti.mon, ti.day, ti.hour, ti.min, ti.sec, tzsign, tzhour, tzmin);
264
263
  } else if (0 == out->opts->sec_prec) {
265
264
  if (0 == tzsecs && rb_funcall2(obj, oj_utcq_id, 0, 0)) {
266
- len = sprintf(buf, "%04d-%02d-%02dT%02d:%02d:%02dZ",
267
- tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
268
- tm->tm_hour, tm->tm_min, tm->tm_sec);
265
+ len = sprintf(buf, "%04d-%02d-%02dT%02d:%02d:%02dZ", ti.year, ti.mon, ti.day, ti.hour, ti.min, ti.sec);
269
266
  } else {
270
- len = sprintf(buf, "%04d-%02d-%02dT%02d:%02d:%02d%c%02d:%02d",
271
- tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
272
- tm->tm_hour, tm->tm_min, tm->tm_sec,
273
- tzsign, tzhour, tzmin);
267
+ len = sprintf(buf, "%04d-%02d-%02dT%02d:%02d:%02d%c%02d:%02d", ti.year, ti.mon, ti.day, ti.hour, ti.min, ti.sec, tzsign, tzhour, tzmin);
274
268
  }
275
269
  } else if (0 == tzsecs && rb_funcall2(obj, oj_utcq_id, 0, 0)) {
276
270
  char format[64] = "%04d-%02d-%02dT%02d:%02d:%02d.%09ldZ";
@@ -280,9 +274,7 @@ dump_sec_nano(VALUE obj, time_t sec, long nsec, Out out) {
280
274
  format[32] = '0' + out->opts->sec_prec;
281
275
  len -= 9 - out->opts->sec_prec;
282
276
  }
283
- len = sprintf(buf, format,
284
- tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
285
- tm->tm_hour, tm->tm_min, tm->tm_sec, nsec);
277
+ len = sprintf(buf, format, ti.year, ti.mon, ti.day, ti.hour, ti.min, ti.sec, nsec);
286
278
  } else {
287
279
  char format[64] = "%04d-%02d-%02dT%02d:%02d:%02d.%09ld%c%02d:%02d";
288
280
 
@@ -291,10 +283,7 @@ dump_sec_nano(VALUE obj, time_t sec, long nsec, Out out) {
291
283
  format[32] = '0' + out->opts->sec_prec;
292
284
  len -= 9 - out->opts->sec_prec;
293
285
  }
294
- len = sprintf(buf, format,
295
- tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
296
- tm->tm_hour, tm->tm_min, tm->tm_sec, nsec,
297
- tzsign, tzhour, tzmin);
286
+ len = sprintf(buf, format, ti.year, ti.mon, ti.day, ti.hour, ti.min, ti.sec, nsec, tzsign, tzhour, tzmin);
298
287
  }
299
288
  oj_dump_cstr(buf, len, 0, 0, out);
300
289
  }
@@ -323,7 +312,7 @@ dump_time(VALUE obj, int depth, Out out, bool as_ok) {
323
312
 
324
313
  static void
325
314
  dump_timewithzone(VALUE obj, int depth, Out out, bool as_ok) {
326
- time_t sec = NUM2LONG(rb_funcall2(obj, oj_tv_sec_id, 0, 0));
315
+ int64_t sec = NUM2LONG(rb_funcall2(obj, oj_tv_sec_id, 0, 0));
327
316
  long long nsec = 0;
328
317
 
329
318
  if (rb_respond_to(obj, oj_tv_nsec_id)) {
@@ -0,0 +1,136 @@
1
+ // Copyright (c) 2019, Peter Ohler, All rights reserved.
2
+
3
+ #include "util.h"
4
+
5
+ #include <stdbool.h>
6
+ #include <stdint.h>
7
+ #include <stdio.h>
8
+ #include <string.h>
9
+ #include <time.h>
10
+
11
+ #define SECS_PER_DAY 86400LL
12
+ #define SECS_PER_YEAR 31536000LL
13
+ #define SECS_PER_LEAP 31622400LL
14
+ #define SECS_PER_QUAD_YEAR (SECS_PER_YEAR * 3 + SECS_PER_LEAP)
15
+ #define SECS_PER_CENT (SECS_PER_QUAD_YEAR * 24 + SECS_PER_YEAR * 4)
16
+ #define SECS_PER_LEAP_CENT (SECS_PER_CENT + SECS_PER_DAY)
17
+ #define SECS_PER_QUAD_CENT (SECS_PER_CENT * 4 + SECS_PER_DAY)
18
+
19
+ static int64_t eom_secs[] = {
20
+ 2678400, // January (31)
21
+ 5097600, // February (28) 2419200 2505600
22
+ 7776000, // March (31)
23
+ 10368000, // April (30 2592000
24
+ 13046400, // May (31)
25
+ 15638400, // June (30)
26
+ 18316800, // July (31)
27
+ 20995200, // August (31)
28
+ 23587200, // September (30)
29
+ 26265600, // October (31)
30
+ 28857600, // November (30)
31
+ 31536000, // December (31)
32
+ };
33
+
34
+ static int64_t eom_leap_secs[] = {
35
+ 2678400, // January (31)
36
+ 5184000, // February (28) 2419200 2505600
37
+ 7862400, // March (31)
38
+ 10454400, // April (30 2592000
39
+ 13132800, // May (31)
40
+ 15724800, // June (30)
41
+ 18403200, // July (31)
42
+ 21081600, // August (31)
43
+ 23673600, // September (30)
44
+ 26352000, // October (31)
45
+ 28944000, // November (30)
46
+ 31622400, // December (31)
47
+ };
48
+
49
+
50
+ void
51
+ sec_as_time(int64_t secs, TimeInfo ti) {
52
+ int64_t qc = 0;
53
+ int64_t c = 0;
54
+ int64_t qy = 0;
55
+ int64_t y = 0;
56
+ bool leap = false;
57
+ int64_t *ms;
58
+ int m;
59
+ int shift = 0;
60
+
61
+ secs += 62167219200LL; // normalize to first day of the year 0
62
+ if (secs < 0) {
63
+ shift = -secs / SECS_PER_QUAD_CENT;
64
+ shift++;
65
+ secs += shift * SECS_PER_QUAD_CENT;
66
+ }
67
+ qc = secs / SECS_PER_QUAD_CENT;
68
+ secs = secs - qc * SECS_PER_QUAD_CENT;
69
+ if (secs < SECS_PER_LEAP) {
70
+ leap = true;
71
+ } else if (secs < SECS_PER_QUAD_YEAR) {
72
+ if (SECS_PER_LEAP <= secs) {
73
+ secs -= SECS_PER_LEAP;
74
+ y = secs / SECS_PER_YEAR;
75
+ secs = secs - y * SECS_PER_YEAR;
76
+ y++;
77
+ leap = true;
78
+ }
79
+ } else if (secs < SECS_PER_LEAP_CENT) { // first century in 400 years is a leap century (one extra day)
80
+ qy = secs / SECS_PER_QUAD_YEAR;
81
+ secs = secs - qy * SECS_PER_QUAD_YEAR;
82
+ if (secs < SECS_PER_LEAP) {
83
+ leap = true;
84
+ } else {
85
+ secs -= SECS_PER_LEAP;
86
+ y = secs / SECS_PER_YEAR;
87
+ secs = secs - y * SECS_PER_YEAR;
88
+ y++;
89
+ }
90
+ } else {
91
+ secs -= SECS_PER_LEAP_CENT;
92
+ c = secs / SECS_PER_CENT;
93
+ secs = secs - c * SECS_PER_CENT;
94
+ c++;
95
+ if (secs < SECS_PER_YEAR * 4) {
96
+ y = secs / SECS_PER_YEAR;
97
+ secs = secs - y * SECS_PER_YEAR;
98
+ } else {
99
+ secs -= SECS_PER_YEAR * 4;
100
+ qy = secs / SECS_PER_QUAD_YEAR;
101
+ secs = secs - qy * SECS_PER_QUAD_YEAR;
102
+ qy++;
103
+ if (secs < SECS_PER_LEAP) {
104
+ leap = true;
105
+ } else {
106
+ secs -= SECS_PER_LEAP;
107
+ y = secs / SECS_PER_YEAR;
108
+ secs = secs - y * SECS_PER_YEAR;
109
+ y++;
110
+ }
111
+ }
112
+ }
113
+ ti->year = (qc - shift) * 400 + c * 100 + qy * 4 + y;
114
+ if (leap) {
115
+ ms = eom_leap_secs;
116
+ } else {
117
+ ms = eom_secs;
118
+ }
119
+ for (m = 1; m <= 12; m++, ms++) {
120
+ if (secs < *ms) {
121
+ if (1 < m) {
122
+ secs -= *(ms - 1);
123
+ }
124
+ ti->mon = m;
125
+ break;
126
+ }
127
+ }
128
+ ti->day = secs / 86400LL;
129
+ secs = secs - (int64_t)ti->day * 86400LL;
130
+ ti->day++;
131
+ ti->hour = secs / 3600LL;
132
+ secs = secs - (int64_t)ti->hour * 3600LL;
133
+ ti->min = secs / 60LL;
134
+ secs = secs - (int64_t)ti->min * 60LL;
135
+ ti->sec = secs;
136
+ }
@@ -0,0 +1,19 @@
1
+ // Copyright (c) 2019, Peter Ohler, All rights reserved.
2
+
3
+ #ifndef OJ_UTIL_H
4
+ #define OJ_UTIL_H
5
+
6
+ #include <stdint.h>
7
+
8
+ typedef struct _timeInfo {
9
+ int sec;
10
+ int min;
11
+ int hour;
12
+ int day;
13
+ int mon;
14
+ int year;
15
+ } *TimeInfo;
16
+
17
+ extern void sec_as_time(int64_t secs, TimeInfo ti);
18
+
19
+ #endif /* OJ_UTIL_H */
@@ -31,6 +31,7 @@
31
31
  #include <string.h>
32
32
 
33
33
  #include "oj.h"
34
+ #include "odd.h"
34
35
  #include "val_stack.h"
35
36
 
36
37
  static void
@@ -54,6 +55,16 @@ mark(void *ptr) {
54
55
  if (Qnil != v->key_val && Qundef != v->key_val) {
55
56
  rb_gc_mark(v->key_val);
56
57
  }
58
+ if (NULL != v->odd_args) {
59
+ VALUE *a;
60
+ int i;
61
+
62
+ for (i = v->odd_args->odd->attr_cnt, a = v->odd_args->args; 0 < i; i--, a++) {
63
+ if (Qnil != *a) {
64
+ rb_gc_mark(*a);
65
+ }
66
+ }
67
+ }
57
68
  }
58
69
  #if HAVE_LIBPTHREAD
59
70
  pthread_mutex_unlock(&stack->mutex);
@@ -77,12 +88,15 @@ oj_stack_init(ValStack stack) {
77
88
  stack->end = stack->base + sizeof(stack->base) / sizeof(struct _val);
78
89
  stack->tail = stack->head;
79
90
  stack->head->val = Qundef;
80
- stack->head->key = 0;
91
+ stack->head->key = NULL;
81
92
  stack->head->key_val = Qundef;
82
- stack->head->classname = 0;
93
+ stack->head->classname = NULL;
94
+ stack->head->odd_args = NULL;
95
+ stack->head->clas = Qundef;
83
96
  stack->head->klen = 0;
84
97
  stack->head->clen = 0;
85
98
  stack->head->next = NEXT_NONE;
99
+
86
100
  return Data_Wrap_Struct(oj_cstack_class, mark, 0, stack);
87
101
  }
88
102
 
@@ -57,13 +57,9 @@ typedef struct _val {
57
57
  const char *key;
58
58
  char karray[32];
59
59
  volatile VALUE key_val;
60
- union {
61
- struct {
62
- const char *classname;
63
- VALUE clas;
64
- };
65
- OddArgs odd_args;
66
- };
60
+ const char *classname;
61
+ VALUE clas;
62
+ OddArgs odd_args;
67
63
  uint16_t klen;
68
64
  uint16_t clen;
69
65
  char next; // ValNext
@@ -132,6 +128,7 @@ stack_push(ValStack stack, VALUE val, ValNext next) {
132
128
  stack->tail->next = next;
133
129
  stack->tail->classname = NULL;
134
130
  stack->tail->clas = Qundef;
131
+ stack->tail->odd_args = NULL;
135
132
  stack->tail->key = 0;
136
133
  stack->tail->key_val = Qundef;
137
134
  stack->tail->clen = 0;
@@ -15,6 +15,7 @@
15
15
  #include "encode.h"
16
16
  #include "dump.h"
17
17
  #include "trace.h"
18
+ #include "util.h"
18
19
 
19
20
  // Workaround in case INFINITY is not defined in math.h or if the OS is CentOS
20
21
  #define OJ_INFINITY (1.0/0.0)
@@ -193,11 +194,11 @@ dump_hash(VALUE obj, int depth, Out out, bool as_ok) {
193
194
 
194
195
  static void
195
196
  dump_time(VALUE obj, Out out) {
196
- char buf[64];
197
- struct tm *tm;
198
- int len;
199
- time_t sec;
200
- long long nsec;
197
+ char buf[64];
198
+ struct _timeInfo ti;
199
+ int len;
200
+ time_t sec;
201
+ long long nsec;
201
202
 
202
203
  #ifdef HAVE_RB_TIME_TIMESPEC
203
204
  if (16 <= sizeof(struct timespec)) {
@@ -216,11 +217,9 @@ dump_time(VALUE obj, Out out) {
216
217
 
217
218
  assure_size(out, 36);
218
219
  // 2012-01-05T23:58:07.123456000Z
219
- tm = gmtime(&sec);
220
+ sec_as_time(sec, &ti);
220
221
 
221
- len = sprintf(buf, "%04d-%02d-%02dT%02d:%02d:%02d.%09ldZ",
222
- tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
223
- tm->tm_hour, tm->tm_min, tm->tm_sec, (long)nsec);
222
+ len = sprintf(buf, "%04d-%02d-%02dT%02d:%02d:%02d.%09ldZ", ti.year, ti.mon, ti.day, ti.hour, ti.min, ti.sec, (long)nsec);
224
223
  oj_dump_cstr(buf, len, 0, 0, out);
225
224
  }
226
225
 
@@ -1,5 +1,5 @@
1
1
 
2
2
  module Oj
3
3
  # Current version of the module.
4
- VERSION = '3.7.7'
4
+ VERSION = '3.7.8'
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: oj
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.7.7
4
+ version: 3.7.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Peter Ohler
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-01-15 00:00:00.000000000 Z
11
+ date: 2019-01-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake-compiler
@@ -139,6 +139,8 @@ files:
139
139
  - ext/oj/string_writer.c
140
140
  - ext/oj/trace.c
141
141
  - ext/oj/trace.h
142
+ - ext/oj/util.c
143
+ - ext/oj/util.h
142
144
  - ext/oj/val_stack.c
143
145
  - ext/oj/val_stack.h
144
146
  - ext/oj/wab.c
@@ -271,8 +273,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
271
273
  - !ruby/object:Gem::Version
272
274
  version: '0'
273
275
  requirements: []
274
- rubyforge_project:
275
- rubygems_version: 2.7.6
276
+ rubygems_version: 3.0.1
276
277
  signing_key:
277
278
  specification_version: 4
278
279
  summary: A fast JSON parser and serializer.