oj 3.12.3 → 3.13.0

Sign up to get free protection for your applications and to get access to all the features.
data/ext/oj/intern.h ADDED
@@ -0,0 +1,27 @@
1
+ // Copyright (c) 2011, 2021 Peter Ohler. All rights reserved.
2
+ // Licensed under the MIT License. See LICENSE file in the project root for license details.
3
+
4
+ #ifndef OJ_INTERN_H
5
+ #define OJ_INTERN_H
6
+
7
+ #include <stdbool.h>
8
+ #include <ruby.h>
9
+
10
+ struct _parseInfo;
11
+
12
+ extern void oj_hash_init();
13
+
14
+ extern VALUE oj_str_intern(const char *key, size_t len);
15
+ extern VALUE oj_sym_intern(const char *key, size_t len);
16
+ extern ID oj_attr_intern(const char *key, size_t len);
17
+ extern VALUE oj_class_intern(const char * key,
18
+ size_t len,
19
+ bool safe,
20
+ struct _parseInfo *pi,
21
+ int auto_define,
22
+ VALUE error_class);
23
+
24
+ extern void oj_hash_print();
25
+ extern char *oj_strndup(const char *s, size_t len);
26
+
27
+ #endif /* OJ_INTERN_H */
data/ext/oj/object.c CHANGED
@@ -7,7 +7,7 @@
7
7
 
8
8
  #include "encode.h"
9
9
  #include "err.h"
10
- #include "hash.h"
10
+ #include "intern.h"
11
11
  #include "odd.h"
12
12
  #include "oj.h"
13
13
  #include "parse.h"
@@ -59,17 +59,17 @@ static VALUE calc_hash_key(ParseInfo pi, Val kval, char k1) {
59
59
  }
60
60
  #else
61
61
  if (':' == k1) {
62
- rkey = rb_str_new(kval->key + 1, kval->klen - 1);
63
- rkey = oj_encode(rkey);
64
- rkey = rb_str_intern(rkey);
62
+ rkey = ID2SYM(rb_intern3(kval->key + 1, kval->klen - 1, oj_utf8_encoding));
65
63
  } else {
66
- rkey = rb_str_new(kval->key, kval->klen);
67
- rkey = oj_encode(rkey);
68
64
  if (Yes == pi->options.sym_key) {
69
- rkey = rb_str_intern(rkey);
65
+ rkey = ID2SYM(rb_intern3(kval->key, kval->klen, oj_utf8_encoding));
66
+ } else {
67
+ rkey = rb_str_new(kval->key, kval->klen);
68
+ rkey = oj_encode(rkey);
70
69
  }
71
70
  }
72
71
  #endif
72
+ OBJ_FREEZE(rkey);
73
73
  return rkey;
74
74
  }
75
75
 
@@ -77,9 +77,7 @@ static VALUE str_to_value(ParseInfo pi, const char *str, size_t len, const char
77
77
  volatile VALUE rstr = Qnil;
78
78
 
79
79
  if (':' == *orig && 0 < len) {
80
- rstr = rb_str_new(str + 1, len - 1);
81
- rstr = oj_encode(rstr);
82
- rstr = rb_funcall(rstr, oj_to_sym_id, 0);
80
+ rstr = ID2SYM(rb_intern3(str + 1, len - 1, oj_utf8_encoding));
83
81
  } else if (pi->circ_array && 3 <= len && '^' == *orig && 'r' == orig[1]) {
84
82
  long i = read_long(str + 2, len - 2);
85
83
 
@@ -258,9 +256,7 @@ static int hat_cstr(ParseInfo pi, Val parent, Val kval, const char *str, size_t
258
256
  parent->odd_args = oj_odd_alloc_args(odd);
259
257
  } break;
260
258
  case 'm':
261
- parent->val = rb_str_new(str + 1, len - 1);
262
- parent->val = oj_encode(parent->val);
263
- parent->val = rb_funcall(parent->val, oj_to_sym_id, 0);
259
+ parent->val = ID2SYM(rb_intern3(str + 1, len - 1, oj_utf8_encoding));
264
260
  break;
265
261
  case 's':
266
262
  parent->val = rb_str_new(str, len);
@@ -416,51 +412,7 @@ static int hat_value(ParseInfo pi, Val parent, const char *key, size_t klen, vol
416
412
  }
417
413
 
418
414
  void oj_set_obj_ivar(Val parent, Val kval, VALUE value) {
419
- const char *key = kval->key;
420
- int klen = kval->klen;
421
- ID var_id;
422
- ID * slot;
423
-
424
- #ifdef HAVE_PTHREAD_MUTEX_INIT
425
- pthread_mutex_lock(&oj_cache_mutex);
426
- #else
427
- rb_mutex_lock(oj_cache_mutex);
428
- #endif
429
- if (0 == (var_id = oj_attr_hash_get(key, klen, &slot))) {
430
- char attr[256];
431
-
432
- if ((int)sizeof(attr) <= klen + 2) {
433
- char *buf = ALLOC_N(char, klen + 2);
434
-
435
- if ('~' == *key) {
436
- memcpy(buf, key + 1, klen - 1);
437
- buf[klen - 1] = '\0';
438
- } else {
439
- *buf = '@';
440
- memcpy(buf + 1, key, klen);
441
- buf[klen + 1] = '\0';
442
- }
443
- var_id = rb_intern(buf);
444
- xfree(buf);
445
- } else {
446
- if ('~' == *key) {
447
- memcpy(attr, key + 1, klen - 1);
448
- attr[klen - 1] = '\0';
449
- } else {
450
- *attr = '@';
451
- memcpy(attr + 1, key, klen);
452
- attr[klen + 1] = '\0';
453
- }
454
- var_id = rb_intern(attr);
455
- }
456
- *slot = var_id;
457
- }
458
- #ifdef HAVE_PTHREAD_MUTEX_INIT
459
- pthread_mutex_unlock(&oj_cache_mutex);
460
- #else
461
- rb_mutex_unlock(oj_cache_mutex);
462
- #endif
463
- rb_ivar_set(parent->val, var_id, value);
415
+ rb_ivar_set(parent->val, oj_attr_intern(kval->key, kval->klen), value);
464
416
  }
465
417
 
466
418
  static void hash_set_cstr(ParseInfo pi, Val kval, const char *str, size_t len, const char *orig) {
data/ext/oj/odd.c CHANGED
@@ -206,7 +206,7 @@ void oj_reg_odd(VALUE clas,
206
206
  *fp = 0;
207
207
  switch (rb_type(*members)) {
208
208
  case T_STRING:
209
- if (NULL == (*np = strdup(rb_string_value_ptr(members)))) {
209
+ if (NULL == (*np = strdup(RSTRING_PTR(*members)))) {
210
210
  rb_raise(rb_eNoMemError, "for attribute name.");
211
211
  }
212
212
  break;
data/ext/oj/oj.c CHANGED
@@ -13,7 +13,7 @@
13
13
 
14
14
  #include "dump.h"
15
15
  #include "encode.h"
16
- #include "hash.h"
16
+ #include "intern.h"
17
17
  #include "odd.h"
18
18
  #include "parse.h"
19
19
  #include "rails.h"
@@ -158,6 +158,8 @@ pthread_mutex_t oj_cache_mutex;
158
158
  VALUE oj_cache_mutex = Qnil;
159
159
  #endif
160
160
 
161
+ extern void oj_parser_init();
162
+
161
163
  const char oj_json_class[] = "json_class";
162
164
 
163
165
  struct _options oj_default_options = {
@@ -589,7 +591,8 @@ bool oj_hash_has_key(VALUE hash, VALUE key)
589
591
  return true;
590
592
  }
591
593
 
592
- void oj_parse_options(VALUE ropts, Options copts) {
594
+ bool set_yesno_options(VALUE key, VALUE value, Options copts)
595
+ {
593
596
  struct _yesNoOpt ynos[] = {{circular_sym, &copts->circular},
594
597
  {auto_define_sym, &copts->auto_define},
595
598
  {symbol_keys_sym, &copts->sym_key},
@@ -612,15 +615,37 @@ void oj_parse_options(VALUE ropts, Options copts) {
612
615
  {oj_create_additions_sym, &copts->create_ok},
613
616
  {cache_keys_sym, &copts->cache_keys},
614
617
  {Qnil, 0}};
615
- YesNoOpt o;
616
- volatile VALUE v;
617
- size_t len;
618
+ YesNoOpt o;
619
+
620
+ for (o = ynos; 0 != o->attr; o++) {
621
+ if (key == o->sym) {
622
+ if (Qnil == value) {
623
+ *o->attr = NotSet;
624
+ } else if (Qtrue == value) {
625
+ *o->attr = Yes;
626
+ } else if (Qfalse == value) {
627
+ *o->attr = No;
628
+ } else {
629
+ rb_raise(rb_eArgError,
630
+ "%s must be true, false, or nil.",
631
+ rb_id2name(key));
632
+ }
633
+ return true;
634
+ }
635
+ }
636
+ return false;
637
+ }
618
638
 
619
- if (T_HASH != rb_type(ropts)) {
620
- return;
639
+ static int parse_options_cb(VALUE k, VALUE v, VALUE opts)
640
+ {
641
+ Options copts = (Options)opts;
642
+ size_t len;
643
+
644
+ if (set_yesno_options(k, v, copts)) {
645
+ return ST_CONTINUE;
621
646
  }
622
- if (oj_hash_has_key(ropts, oj_indent_sym)) {
623
- v = rb_hash_lookup(ropts, oj_indent_sym);
647
+
648
+ if (oj_indent_sym == k) {
624
649
  switch (rb_type(v)) {
625
650
  case T_NIL:
626
651
  copts->dump_opts.indent_size = 0;
@@ -644,8 +669,7 @@ void oj_parse_options(VALUE ropts, Options copts) {
644
669
  break;
645
670
  default: rb_raise(rb_eTypeError, "indent must be a Fixnum, String, or nil."); break;
646
671
  }
647
- }
648
- if (Qnil != (v = rb_hash_lookup(ropts, float_prec_sym))) {
672
+ } else if (float_prec_sym == k) {
649
673
  int n;
650
674
 
651
675
  #ifdef RUBY_INTEGER_UNIFICATION
@@ -668,8 +692,7 @@ void oj_parse_options(VALUE ropts, Options copts) {
668
692
  sprintf(copts->float_fmt, "%%0.%dg", n);
669
693
  copts->float_prec = n;
670
694
  }
671
- }
672
- if (Qnil != (v = rb_hash_lookup(ropts, cache_str_sym))) {
695
+ } else if (cache_str_sym == k) {
673
696
  int n;
674
697
 
675
698
  #ifdef RUBY_INTEGER_UNIFICATION
@@ -690,8 +713,7 @@ void oj_parse_options(VALUE ropts, Options copts) {
690
713
  }
691
714
  copts->cache_str = (char)n;
692
715
  }
693
- }
694
- if (Qnil != (v = rb_hash_lookup(ropts, sec_prec_sym))) {
716
+ } else if (sec_prec_sym == k) {
695
717
  int n;
696
718
 
697
719
  #ifdef RUBY_INTEGER_UNIFICATION
@@ -714,8 +736,7 @@ void oj_parse_options(VALUE ropts, Options copts) {
714
736
  copts->sec_prec_set = true;
715
737
  }
716
738
  copts->sec_prec = n;
717
- }
718
- if (Qnil != (v = rb_hash_lookup(ropts, mode_sym))) {
739
+ } else if (mode_sym == k) {
719
740
  if (wab_sym == v) {
720
741
  copts->mode = WabMode;
721
742
  } else if (object_sym == v) {
@@ -734,8 +755,7 @@ void oj_parse_options(VALUE ropts, Options copts) {
734
755
  rb_raise(rb_eArgError,
735
756
  ":mode must be :object, :strict, :compat, :null, :custom, :rails, or :wab.");
736
757
  }
737
- }
738
- if (Qnil != (v = rb_hash_lookup(ropts, time_format_sym))) {
758
+ } else if (time_format_sym == k) {
739
759
  if (unix_sym == v) {
740
760
  copts->time_format = UnixTime;
741
761
  } else if (unix_zone_sym == v) {
@@ -747,8 +767,7 @@ void oj_parse_options(VALUE ropts, Options copts) {
747
767
  } else {
748
768
  rb_raise(rb_eArgError, ":time_format must be :unix, :unix_zone, :xmlschema, or :ruby.");
749
769
  }
750
- }
751
- if (Qnil != (v = rb_hash_lookup(ropts, escape_mode_sym))) {
770
+ } else if (escape_mode_sym == k) {
752
771
  if (newline_sym == v) {
753
772
  copts->escape_mode = NLEsc;
754
773
  } else if (json_sym == v) {
@@ -763,8 +782,11 @@ void oj_parse_options(VALUE ropts, Options copts) {
763
782
  rb_raise(rb_eArgError,
764
783
  ":encoding must be :newline, :json, :xss_safe, :unicode_xss, or :ascii.");
765
784
  }
766
- }
767
- if (Qnil != (v = rb_hash_lookup(ropts, bigdecimal_load_sym))) {
785
+ } else if (bigdecimal_load_sym == k) {
786
+ if (Qnil == v) {
787
+ return ST_CONTINUE;
788
+ }
789
+
768
790
  if (bigdecimal_sym == v || Qtrue == v) {
769
791
  copts->bigdec_load = BigDec;
770
792
  } else if (float_sym == v) {
@@ -776,12 +798,13 @@ void oj_parse_options(VALUE ropts, Options copts) {
776
798
  } else {
777
799
  rb_raise(rb_eArgError, ":bigdecimal_load must be :bigdecimal, :float, or :auto.");
778
800
  }
779
- }
780
- if (Qnil != (v = rb_hash_lookup(ropts, compat_bigdecimal_sym))) {
801
+ } else if (compat_bigdecimal_sym == k) {
802
+ if (Qnil == v) {
803
+ return ST_CONTINUE;
804
+ }
805
+
781
806
  copts->compat_bigdec = (Qtrue == v);
782
- }
783
- if (oj_hash_has_key(ropts, oj_decimal_class_sym)) {
784
- v = rb_hash_lookup(ropts, oj_decimal_class_sym);
807
+ } else if (oj_decimal_class_sym == k) {
785
808
  if (rb_cFloat == v) {
786
809
  copts->compat_bigdec = false;
787
810
  } else if (oj_bigdecimal_class == v) {
@@ -789,9 +812,7 @@ void oj_parse_options(VALUE ropts, Options copts) {
789
812
  } else {
790
813
  rb_raise(rb_eArgError, ":decimal_class must be BigDecimal or Float.");
791
814
  }
792
- }
793
- if (oj_hash_has_key(ropts, create_id_sym)) {
794
- v = rb_hash_lookup(ropts, create_id_sym);
815
+ } else if (create_id_sym == k) {
795
816
  if (Qnil == v) {
796
817
  if (oj_json_class != oj_default_options.create_id && NULL != copts->create_id) {
797
818
  xfree((char *)oj_default_options.create_id);
@@ -810,25 +831,8 @@ void oj_parse_options(VALUE ropts, Options copts) {
810
831
  } else {
811
832
  rb_raise(rb_eArgError, ":create_id must be string.");
812
833
  }
813
- }
814
- for (o = ynos; 0 != o->attr; o++) {
815
- if (oj_hash_has_key(ropts, o->sym)) {
816
- v = rb_hash_lookup(ropts, o->sym);
817
- if (Qnil == v) {
818
- *o->attr = NotSet;
819
- } else if (Qtrue == v) {
820
- *o->attr = Yes;
821
- } else if (Qfalse == v) {
822
- *o->attr = No;
823
- } else {
824
- rb_raise(rb_eArgError,
825
- "%s must be true, false, or nil.",
826
- rb_id2name(SYM2ID(o->sym)));
827
- }
828
- }
829
- }
830
- if (oj_hash_has_key(ropts, oj_space_sym)) {
831
- if (Qnil == (v = rb_hash_lookup(ropts, oj_space_sym))) {
834
+ } else if (oj_space_sym == k) {
835
+ if (Qnil == v) {
832
836
  copts->dump_opts.after_size = 0;
833
837
  *copts->dump_opts.after_sep = '\0';
834
838
  } else {
@@ -841,9 +845,8 @@ void oj_parse_options(VALUE ropts, Options copts) {
841
845
  strcpy(copts->dump_opts.after_sep, StringValuePtr(v));
842
846
  copts->dump_opts.after_size = (uint8_t)len;
843
847
  }
844
- }
845
- if (oj_hash_has_key(ropts, oj_space_before_sym)) {
846
- if (Qnil == (v = rb_hash_lookup(ropts, oj_space_before_sym))) {
848
+ } else if (oj_space_before_sym == k) {
849
+ if (Qnil == v) {
847
850
  copts->dump_opts.before_size = 0;
848
851
  *copts->dump_opts.before_sep = '\0';
849
852
  } else {
@@ -856,9 +859,8 @@ void oj_parse_options(VALUE ropts, Options copts) {
856
859
  strcpy(copts->dump_opts.before_sep, StringValuePtr(v));
857
860
  copts->dump_opts.before_size = (uint8_t)len;
858
861
  }
859
- }
860
- if (oj_hash_has_key(ropts, oj_object_nl_sym)) {
861
- if (Qnil == (v = rb_hash_lookup(ropts, oj_object_nl_sym))) {
862
+ } else if (oj_object_nl_sym == k) {
863
+ if (Qnil == v) {
862
864
  copts->dump_opts.hash_size = 0;
863
865
  *copts->dump_opts.hash_nl = '\0';
864
866
  } else {
@@ -871,9 +873,8 @@ void oj_parse_options(VALUE ropts, Options copts) {
871
873
  strcpy(copts->dump_opts.hash_nl, StringValuePtr(v));
872
874
  copts->dump_opts.hash_size = (uint8_t)len;
873
875
  }
874
- }
875
- if (oj_hash_has_key(ropts, oj_array_nl_sym)) {
876
- if (Qnil == (v = rb_hash_lookup(ropts, oj_array_nl_sym))) {
876
+ } else if (oj_array_nl_sym == k) {
877
+ if (Qnil == v) {
877
878
  copts->dump_opts.array_size = 0;
878
879
  *copts->dump_opts.array_nl = '\0';
879
880
  } else {
@@ -886,8 +887,11 @@ void oj_parse_options(VALUE ropts, Options copts) {
886
887
  strcpy(copts->dump_opts.array_nl, StringValuePtr(v));
887
888
  copts->dump_opts.array_size = (uint8_t)len;
888
889
  }
889
- }
890
- if (Qnil != (v = rb_hash_lookup(ropts, nan_sym))) {
890
+ } else if (nan_sym == k) {
891
+ if (Qnil == v) {
892
+ return ST_CONTINUE;
893
+ }
894
+
891
895
  if (null_sym == v) {
892
896
  copts->dump_opts.nan_dump = NullNan;
893
897
  } else if (huge_sym == v) {
@@ -901,11 +905,11 @@ void oj_parse_options(VALUE ropts, Options copts) {
901
905
  } else {
902
906
  rb_raise(rb_eArgError, ":nan must be :null, :huge, :word, :raise, or :auto.");
903
907
  }
904
- }
905
- copts->dump_opts.use = (0 < copts->dump_opts.indent_size || 0 < copts->dump_opts.after_size ||
906
- 0 < copts->dump_opts.before_size || 0 < copts->dump_opts.hash_size ||
907
- 0 < copts->dump_opts.array_size);
908
- if (Qnil != (v = rb_hash_lookup(ropts, omit_nil_sym))) {
908
+ } else if (omit_nil_sym == k) {
909
+ if (Qnil == v) {
910
+ return ST_CONTINUE;
911
+ }
912
+
909
913
  if (Qtrue == v) {
910
914
  copts->dump_opts.omit_nil = true;
911
915
  } else if (Qfalse == v) {
@@ -913,43 +917,38 @@ void oj_parse_options(VALUE ropts, Options copts) {
913
917
  } else {
914
918
  rb_raise(rb_eArgError, ":omit_nil must be true or false.");
915
919
  }
916
- }
917
- // This is here only for backwards compatibility with the original Oj.
918
- v = rb_hash_lookup(ropts, oj_ascii_only_sym);
919
- if (Qtrue == v) {
920
- copts->escape_mode = ASCIIEsc;
921
- } else if (Qfalse == v) {
922
- copts->escape_mode = JSONEsc;
923
- }
924
- if (oj_hash_has_key(ropts, oj_hash_class_sym)) {
925
- if (Qnil == (v = rb_hash_lookup(ropts, oj_hash_class_sym))) {
920
+ } else if(oj_ascii_only_sym == k) {
921
+ // This is here only for backwards compatibility with the original Oj.
922
+ if (Qtrue == v) {
923
+ copts->escape_mode = ASCIIEsc;
924
+ } else if (Qfalse == v) {
925
+ copts->escape_mode = JSONEsc;
926
+ }
927
+ } else if (oj_hash_class_sym == k) {
928
+ if (Qnil == v) {
926
929
  copts->hash_class = Qnil;
927
930
  } else {
928
931
  rb_check_type(v, T_CLASS);
929
932
  copts->hash_class = v;
930
933
  }
931
- }
932
- if (oj_hash_has_key(ropts, oj_object_class_sym)) {
933
- if (Qnil == (v = rb_hash_lookup(ropts, oj_object_class_sym))) {
934
+ } else if (oj_object_class_sym == k) {
935
+ if (Qnil == v) {
934
936
  copts->hash_class = Qnil;
935
937
  } else {
936
938
  rb_check_type(v, T_CLASS);
937
939
  copts->hash_class = v;
938
940
  }
939
- }
940
- if (oj_hash_has_key(ropts, oj_array_class_sym)) {
941
- if (Qnil == (v = rb_hash_lookup(ropts, oj_array_class_sym))) {
941
+ } else if (oj_array_class_sym == k) {
942
+ if (Qnil == v) {
942
943
  copts->array_class = Qnil;
943
944
  } else {
944
945
  rb_check_type(v, T_CLASS);
945
946
  copts->array_class = v;
946
947
  }
947
- }
948
- oj_parse_opt_match_string(&copts->str_rx, ropts);
949
- if (oj_hash_has_key(ropts, ignore_sym)) {
948
+ } else if (ignore_sym == k) {
950
949
  xfree(copts->ignore);
951
950
  copts->ignore = NULL;
952
- if (Qnil != (v = rb_hash_lookup(ropts, ignore_sym))) {
951
+ if (Qnil != v) {
953
952
  int cnt;
954
953
 
955
954
  rb_check_type(v, T_ARRAY);
@@ -964,8 +963,11 @@ void oj_parse_options(VALUE ropts, Options copts) {
964
963
  copts->ignore[i] = Qnil;
965
964
  }
966
965
  }
967
- }
968
- if (Qnil != (v = rb_hash_lookup(ropts, integer_range_sym))) {
966
+ } else if (integer_range_sym == k) {
967
+ if (Qnil == v) {
968
+ return ST_CONTINUE;
969
+ }
970
+
969
971
  if (TYPE(v) == T_STRUCT && rb_obj_class(v) == rb_cRange) {
970
972
  VALUE min = rb_funcall(v, oj_begin_id, 0);
971
973
  VALUE max = rb_funcall(v, oj_end_id, 0);
@@ -980,6 +982,22 @@ void oj_parse_options(VALUE ropts, Options copts) {
980
982
  rb_raise(rb_eArgError, ":integer_range must be a range of Fixnum.");
981
983
  }
982
984
  }
985
+
986
+ return ST_CONTINUE;
987
+ }
988
+
989
+ void oj_parse_options(VALUE ropts, Options copts) {
990
+ if (T_HASH != rb_type(ropts)) {
991
+ return;
992
+ }
993
+
994
+ rb_hash_foreach(ropts, parse_options_cb, (VALUE)copts);
995
+ oj_parse_opt_match_string(&copts->str_rx, ropts);
996
+
997
+ copts->dump_opts.use = (0 < copts->dump_opts.indent_size || 0 < copts->dump_opts.after_size ||
998
+ 0 < copts->dump_opts.before_size || 0 < copts->dump_opts.hash_size ||
999
+ 0 < copts->dump_opts.array_size);
1000
+ return;
983
1001
  }
984
1002
 
985
1003
  static int match_string_cb(VALUE key, VALUE value, VALUE rx) {
@@ -1761,6 +1779,9 @@ static VALUE protect_require(VALUE x) {
1761
1779
  void Init_oj() {
1762
1780
  int err = 0;
1763
1781
 
1782
+ #if HAVE_RB_EXT_RACTOR_SAFE
1783
+ rb_ext_ractor_safe(true);
1784
+ #endif
1764
1785
  Oj = rb_define_module("Oj");
1765
1786
 
1766
1787
  oj_cstack_class = rb_define_class_under(Oj, "CStack", rb_cObject);
@@ -2035,4 +2056,6 @@ void Init_oj() {
2035
2056
  rb_gc_register_address(&oj_cache_mutex);
2036
2057
  #endif
2037
2058
  oj_init_doc();
2059
+
2060
+ oj_parser_init();
2038
2061
  }