json 2.2.0 → 2.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGES.md +51 -0
  3. data/LICENSE +56 -0
  4. data/README.md +17 -1
  5. data/VERSION +1 -1
  6. data/ext/json/ext/generator/generator.c +222 -48
  7. data/ext/json/ext/generator/generator.h +5 -2
  8. data/ext/json/ext/parser/extconf.rb +25 -0
  9. data/ext/json/ext/parser/parser.c +150 -102
  10. data/ext/json/ext/parser/parser.h +1 -0
  11. data/ext/json/ext/parser/parser.rl +80 -32
  12. data/ext/json/extconf.rb +1 -0
  13. data/json.gemspec +0 -0
  14. data/lib/json.rb +549 -29
  15. data/lib/json/add/bigdecimal.rb +2 -2
  16. data/lib/json/add/complex.rb +2 -3
  17. data/lib/json/add/rational.rb +2 -3
  18. data/lib/json/add/regexp.rb +2 -2
  19. data/lib/json/common.rb +370 -125
  20. data/lib/json/pure/generator.rb +31 -10
  21. data/lib/json/pure/parser.rb +31 -5
  22. data/lib/json/version.rb +1 -1
  23. data/tests/fixtures/fail29.json +1 -0
  24. data/tests/fixtures/fail30.json +1 -0
  25. data/tests/fixtures/fail31.json +1 -0
  26. data/tests/fixtures/fail32.json +1 -0
  27. data/tests/json_addition_test.rb +0 -4
  28. data/tests/json_common_interface_test.rb +47 -4
  29. data/tests/json_fixtures_test.rb +9 -1
  30. data/tests/json_generator_test.rb +30 -8
  31. data/tests/json_parser_test.rb +39 -14
  32. data/tests/lib/core_assertions.rb +763 -0
  33. data/tests/lib/envutil.rb +365 -0
  34. data/tests/lib/find_executable.rb +22 -0
  35. data/tests/lib/helper.rb +4 -0
  36. data/tests/ractor_test.rb +30 -0
  37. data/tests/test_helper.rb +3 -3
  38. metadata +30 -40
  39. data/.gitignore +0 -17
  40. data/.travis.yml +0 -23
  41. data/README-json-jruby.md +0 -33
  42. data/Rakefile +0 -408
  43. data/diagrams/.keep +0 -0
  44. data/install.rb +0 -23
  45. data/java/src/json/ext/ByteListTranscoder.java +0 -166
  46. data/java/src/json/ext/Generator.java +0 -443
  47. data/java/src/json/ext/GeneratorMethods.java +0 -231
  48. data/java/src/json/ext/GeneratorService.java +0 -42
  49. data/java/src/json/ext/GeneratorState.java +0 -490
  50. data/java/src/json/ext/OptionsReader.java +0 -113
  51. data/java/src/json/ext/Parser.java +0 -2362
  52. data/java/src/json/ext/Parser.rl +0 -893
  53. data/java/src/json/ext/ParserService.java +0 -34
  54. data/java/src/json/ext/RuntimeInfo.java +0 -116
  55. data/java/src/json/ext/StringDecoder.java +0 -166
  56. data/java/src/json/ext/StringEncoder.java +0 -111
  57. data/java/src/json/ext/Utils.java +0 -88
  58. data/json-java.gemspec +0 -38
  59. data/json_pure.gemspec +0 -38
  60. data/references/rfc7159.txt +0 -899
  61. data/tools/diff.sh +0 -18
  62. data/tools/fuzz.rb +0 -131
  63. data/tools/server.rb +0 -62
@@ -1,34 +0,0 @@
1
- /*
2
- * This code is copyrighted work by Daniel Luz <dev at mernen dot com>.
3
- *
4
- * Distributed under the Ruby license: https://www.ruby-lang.org/en/about/license.txt
5
- */
6
- package json.ext;
7
-
8
- import java.io.IOException;
9
- import java.lang.ref.WeakReference;
10
-
11
- import org.jruby.Ruby;
12
- import org.jruby.RubyClass;
13
- import org.jruby.RubyModule;
14
- import org.jruby.runtime.load.BasicLibraryService;
15
-
16
- /**
17
- * The service invoked by JRuby's {@link org.jruby.runtime.load.LoadService LoadService}.
18
- * Defines the <code>JSON::Ext::Parser</code> class.
19
- * @author mernen
20
- */
21
- public class ParserService implements BasicLibraryService {
22
- public boolean basicLoad(Ruby runtime) throws IOException {
23
- runtime.getLoadService().require("json/common");
24
- RuntimeInfo info = RuntimeInfo.initRuntime(runtime);
25
-
26
- info.jsonModule = new WeakReference<RubyModule>(runtime.defineModule("JSON"));
27
- RubyModule jsonExtModule = info.jsonModule.get().defineModuleUnder("Ext");
28
- RubyClass parserClass =
29
- jsonExtModule.defineClassUnder("Parser", runtime.getObject(),
30
- Parser.ALLOCATOR);
31
- parserClass.defineAnnotatedMethods(Parser.class);
32
- return true;
33
- }
34
- }
@@ -1,116 +0,0 @@
1
- /*
2
- * This code is copyrighted work by Daniel Luz <dev at mernen dot com>.
3
- *
4
- * Distributed under the Ruby license: https://www.ruby-lang.org/en/about/license.txt
5
- */
6
- package json.ext;
7
-
8
- import java.lang.ref.WeakReference;
9
- import java.util.HashMap;
10
- import java.util.Map;
11
- import java.util.WeakHashMap;
12
- import org.jruby.Ruby;
13
- import org.jruby.RubyClass;
14
- import org.jruby.RubyEncoding;
15
- import org.jruby.RubyModule;
16
- import org.jruby.runtime.ThreadContext;
17
- import org.jruby.runtime.builtin.IRubyObject;
18
-
19
-
20
- final class RuntimeInfo {
21
- // since the vast majority of cases runs just one runtime,
22
- // we optimize for that
23
- private static WeakReference<Ruby> runtime1 = new WeakReference<Ruby>(null);
24
- private static RuntimeInfo info1;
25
- // store remaining runtimes here (does not include runtime1)
26
- private static Map<Ruby, RuntimeInfo> runtimes;
27
-
28
- // these fields are filled by the service loaders
29
- // Use WeakReferences so that RuntimeInfo doesn't indirectly hold a hard reference to
30
- // the Ruby runtime object, which would cause memory leaks in the runtimes map above.
31
- /** JSON */
32
- WeakReference<RubyModule> jsonModule;
33
- /** JSON::Ext::Generator::GeneratorMethods::String::Extend */
34
- WeakReference<RubyModule> stringExtendModule;
35
- /** JSON::Ext::Generator::State */
36
- WeakReference<RubyClass> generatorStateClass;
37
- /** JSON::SAFE_STATE_PROTOTYPE */
38
- WeakReference<GeneratorState> safeStatePrototype;
39
-
40
- final WeakReference<RubyEncoding> utf8;
41
- final WeakReference<RubyEncoding> ascii8bit;
42
- // other encodings
43
- private final Map<String, WeakReference<RubyEncoding>> encodings;
44
-
45
- private RuntimeInfo(Ruby runtime) {
46
- RubyClass encodingClass = runtime.getEncoding();
47
- if (encodingClass == null) { // 1.8 mode
48
- utf8 = ascii8bit = null;
49
- encodings = null;
50
- } else {
51
- ThreadContext context = runtime.getCurrentContext();
52
-
53
- utf8 = new WeakReference<RubyEncoding>((RubyEncoding)RubyEncoding.find(context,
54
- encodingClass, runtime.newString("utf-8")));
55
- ascii8bit = new WeakReference<RubyEncoding>((RubyEncoding)RubyEncoding.find(context,
56
- encodingClass, runtime.newString("ascii-8bit")));
57
- encodings = new HashMap<String, WeakReference<RubyEncoding>>();
58
- }
59
- }
60
-
61
- static RuntimeInfo initRuntime(Ruby runtime) {
62
- synchronized (RuntimeInfo.class) {
63
- if (runtime1.get() == runtime) {
64
- return info1;
65
- } else if (runtime1.get() == null) {
66
- runtime1 = new WeakReference<Ruby>(runtime);
67
- info1 = new RuntimeInfo(runtime);
68
- return info1;
69
- } else {
70
- if (runtimes == null) {
71
- runtimes = new WeakHashMap<Ruby, RuntimeInfo>(1);
72
- }
73
- RuntimeInfo cache = runtimes.get(runtime);
74
- if (cache == null) {
75
- cache = new RuntimeInfo(runtime);
76
- runtimes.put(runtime, cache);
77
- }
78
- return cache;
79
- }
80
- }
81
- }
82
-
83
- public static RuntimeInfo forRuntime(Ruby runtime) {
84
- synchronized (RuntimeInfo.class) {
85
- if (runtime1.get() == runtime) return info1;
86
- RuntimeInfo cache = null;
87
- if (runtimes != null) cache = runtimes.get(runtime);
88
- assert cache != null : "Runtime given has not initialized JSON::Ext";
89
- return cache;
90
- }
91
- }
92
-
93
- public RubyEncoding getEncoding(ThreadContext context, String name) {
94
- synchronized (encodings) {
95
- WeakReference<RubyEncoding> encoding = encodings.get(name);
96
- if (encoding == null) {
97
- Ruby runtime = context.getRuntime();
98
- encoding = new WeakReference<RubyEncoding>((RubyEncoding)RubyEncoding.find(context,
99
- runtime.getEncoding(), runtime.newString(name)));
100
- encodings.put(name, encoding);
101
- }
102
- return encoding.get();
103
- }
104
- }
105
-
106
- public GeneratorState getSafeStatePrototype(ThreadContext context) {
107
- if (safeStatePrototype == null) {
108
- IRubyObject value = jsonModule.get().getConstant("SAFE_STATE_PROTOTYPE");
109
- if (!(value instanceof GeneratorState)) {
110
- throw context.getRuntime().newTypeError(value, generatorStateClass.get());
111
- }
112
- safeStatePrototype = new WeakReference<GeneratorState>((GeneratorState)value);
113
- }
114
- return safeStatePrototype.get();
115
- }
116
- }
@@ -1,166 +0,0 @@
1
- /*
2
- * This code is copyrighted work by Daniel Luz <dev at mernen dot com>.
3
- *
4
- * Distributed under the Ruby license: https://www.ruby-lang.org/en/about/license.txt
5
- */
6
- package json.ext;
7
-
8
- import org.jruby.exceptions.RaiseException;
9
- import org.jruby.runtime.ThreadContext;
10
- import org.jruby.util.ByteList;
11
-
12
- /**
13
- * A decoder that reads a JSON-encoded string from the given sources and
14
- * returns its decoded form on a new ByteList. Escaped Unicode characters
15
- * are encoded as UTF-8.
16
- */
17
- final class StringDecoder extends ByteListTranscoder {
18
- /**
19
- * Stores the offset of the high surrogate when reading a surrogate pair,
20
- * or -1 when not.
21
- */
22
- private int surrogatePairStart = -1;
23
-
24
- // Array used for writing multi-byte characters into the buffer at once
25
- private final byte[] aux = new byte[4];
26
-
27
- StringDecoder(ThreadContext context) {
28
- super(context);
29
- }
30
-
31
- ByteList decode(ByteList src, int start, int end) {
32
- ByteList out = new ByteList(end - start);
33
- out.setEncoding(src.getEncoding());
34
- init(src, start, end, out);
35
- while (hasNext()) {
36
- handleChar(readUtf8Char());
37
- }
38
- quoteStop(pos);
39
- return out;
40
- }
41
-
42
- private void handleChar(int c) {
43
- if (c == '\\') {
44
- quoteStop(charStart);
45
- handleEscapeSequence();
46
- } else {
47
- quoteStart();
48
- }
49
- }
50
-
51
- private void handleEscapeSequence() {
52
- ensureMin(1);
53
- switch (readUtf8Char()) {
54
- case 'b':
55
- append('\b');
56
- break;
57
- case 'f':
58
- append('\f');
59
- break;
60
- case 'n':
61
- append('\n');
62
- break;
63
- case 'r':
64
- append('\r');
65
- break;
66
- case 't':
67
- append('\t');
68
- break;
69
- case 'u':
70
- ensureMin(4);
71
- int cp = readHex();
72
- if (Character.isHighSurrogate((char)cp)) {
73
- handleLowSurrogate((char)cp);
74
- } else if (Character.isLowSurrogate((char)cp)) {
75
- // low surrogate with no high surrogate
76
- throw invalidUtf8();
77
- } else {
78
- writeUtf8Char(cp);
79
- }
80
- break;
81
- default: // '\\', '"', '/'...
82
- quoteStart();
83
- }
84
- }
85
-
86
- private void handleLowSurrogate(char highSurrogate) {
87
- surrogatePairStart = charStart;
88
- ensureMin(1);
89
- int lowSurrogate = readUtf8Char();
90
-
91
- if (lowSurrogate == '\\') {
92
- ensureMin(5);
93
- if (readUtf8Char() != 'u') throw invalidUtf8();
94
- lowSurrogate = readHex();
95
- }
96
-
97
- if (Character.isLowSurrogate((char)lowSurrogate)) {
98
- writeUtf8Char(Character.toCodePoint(highSurrogate,
99
- (char)lowSurrogate));
100
- surrogatePairStart = -1;
101
- } else {
102
- throw invalidUtf8();
103
- }
104
- }
105
-
106
- private void writeUtf8Char(int codePoint) {
107
- if (codePoint < 0x80) {
108
- append(codePoint);
109
- } else if (codePoint < 0x800) {
110
- aux[0] = (byte)(0xc0 | (codePoint >>> 6));
111
- aux[1] = tailByte(codePoint & 0x3f);
112
- append(aux, 0, 2);
113
- } else if (codePoint < 0x10000) {
114
- aux[0] = (byte)(0xe0 | (codePoint >>> 12));
115
- aux[1] = tailByte(codePoint >>> 6);
116
- aux[2] = tailByte(codePoint);
117
- append(aux, 0, 3);
118
- } else {
119
- aux[0] = (byte)(0xf0 | codePoint >>> 18);
120
- aux[1] = tailByte(codePoint >>> 12);
121
- aux[2] = tailByte(codePoint >>> 6);
122
- aux[3] = tailByte(codePoint);
123
- append(aux, 0, 4);
124
- }
125
- }
126
-
127
- private byte tailByte(int value) {
128
- return (byte)(0x80 | (value & 0x3f));
129
- }
130
-
131
- /**
132
- * Reads a 4-digit unsigned hexadecimal number from the source.
133
- */
134
- private int readHex() {
135
- int numberStart = pos;
136
- int result = 0;
137
- int length = 4;
138
- for (int i = 0; i < length; i++) {
139
- int digit = readUtf8Char();
140
- int digitValue;
141
- if (digit >= '0' && digit <= '9') {
142
- digitValue = digit - '0';
143
- } else if (digit >= 'a' && digit <= 'f') {
144
- digitValue = 10 + digit - 'a';
145
- } else if (digit >= 'A' && digit <= 'F') {
146
- digitValue = 10 + digit - 'A';
147
- } else {
148
- throw new NumberFormatException("Invalid base 16 number "
149
- + src.subSequence(numberStart, numberStart + length));
150
- }
151
- result = result * 16 + digitValue;
152
- }
153
- return result;
154
- }
155
-
156
- @Override
157
- protected RaiseException invalidUtf8() {
158
- ByteList message = new ByteList(
159
- ByteList.plain("partial character in source, " +
160
- "but hit end near "));
161
- int start = surrogatePairStart != -1 ? surrogatePairStart : charStart;
162
- message.append(src, start, srcEnd - start);
163
- return Utils.newException(context, Utils.M_PARSER_ERROR,
164
- context.getRuntime().newString(message));
165
- }
166
- }
@@ -1,111 +0,0 @@
1
- /*
2
- * This code is copyrighted work by Daniel Luz <dev at mernen dot com>.
3
- *
4
- * Distributed under the Ruby license: https://www.ruby-lang.org/en/about/license.txt
5
- */
6
- package json.ext;
7
-
8
- import org.jruby.exceptions.RaiseException;
9
- import org.jruby.runtime.ThreadContext;
10
- import org.jruby.util.ByteList;
11
-
12
- /**
13
- * An encoder that reads from the given source and outputs its representation
14
- * to another ByteList. The source string is fully checked for UTF-8 validity,
15
- * and throws a GeneratorError if any problem is found.
16
- */
17
- final class StringEncoder extends ByteListTranscoder {
18
- private final boolean asciiOnly;
19
-
20
- // Escaped characters will reuse this array, to avoid new allocations
21
- // or appending them byte-by-byte
22
- private final byte[] aux =
23
- new byte[] {/* First unicode character */
24
- '\\', 'u', 0, 0, 0, 0,
25
- /* Second unicode character (for surrogate pairs) */
26
- '\\', 'u', 0, 0, 0, 0,
27
- /* "\X" characters */
28
- '\\', 0};
29
- // offsets on the array above
30
- private static final int ESCAPE_UNI1_OFFSET = 0;
31
- private static final int ESCAPE_UNI2_OFFSET = ESCAPE_UNI1_OFFSET + 6;
32
- private static final int ESCAPE_CHAR_OFFSET = ESCAPE_UNI2_OFFSET + 6;
33
- /** Array used for code point decomposition in surrogates */
34
- private final char[] utf16 = new char[2];
35
-
36
- private static final byte[] HEX =
37
- new byte[] {'0', '1', '2', '3', '4', '5', '6', '7',
38
- '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
39
-
40
- StringEncoder(ThreadContext context, boolean asciiOnly) {
41
- super(context);
42
- this.asciiOnly = asciiOnly;
43
- }
44
-
45
- void encode(ByteList src, ByteList out) {
46
- init(src, out);
47
- append('"');
48
- while (hasNext()) {
49
- handleChar(readUtf8Char());
50
- }
51
- quoteStop(pos);
52
- append('"');
53
- }
54
-
55
- private void handleChar(int c) {
56
- switch (c) {
57
- case '"':
58
- case '\\':
59
- escapeChar((char)c);
60
- break;
61
- case '\n':
62
- escapeChar('n');
63
- break;
64
- case '\r':
65
- escapeChar('r');
66
- break;
67
- case '\t':
68
- escapeChar('t');
69
- break;
70
- case '\f':
71
- escapeChar('f');
72
- break;
73
- case '\b':
74
- escapeChar('b');
75
- break;
76
- default:
77
- if (c >= 0x20 && c <= 0x7f ||
78
- (c >= 0x80 && !asciiOnly)) {
79
- quoteStart();
80
- } else {
81
- quoteStop(charStart);
82
- escapeUtf8Char(c);
83
- }
84
- }
85
- }
86
-
87
- private void escapeChar(char c) {
88
- quoteStop(charStart);
89
- aux[ESCAPE_CHAR_OFFSET + 1] = (byte)c;
90
- append(aux, ESCAPE_CHAR_OFFSET, 2);
91
- }
92
-
93
- private void escapeUtf8Char(int codePoint) {
94
- int numChars = Character.toChars(codePoint, utf16, 0);
95
- escapeCodeUnit(utf16[0], ESCAPE_UNI1_OFFSET + 2);
96
- if (numChars > 1) escapeCodeUnit(utf16[1], ESCAPE_UNI2_OFFSET + 2);
97
- append(aux, ESCAPE_UNI1_OFFSET, 6 * numChars);
98
- }
99
-
100
- private void escapeCodeUnit(char c, int auxOffset) {
101
- for (int i = 0; i < 4; i++) {
102
- aux[auxOffset + i] = HEX[(c >>> (12 - 4 * i)) & 0xf];
103
- }
104
- }
105
-
106
- @Override
107
- protected RaiseException invalidUtf8() {
108
- return Utils.newException(context, Utils.M_GENERATOR_ERROR,
109
- "source sequence is illegal/malformed utf-8");
110
- }
111
- }
@@ -1,88 +0,0 @@
1
- /*
2
- * This code is copyrighted work by Daniel Luz <dev at mernen dot com>.
3
- *
4
- * Distributed under the Ruby license: https://www.ruby-lang.org/en/about/license.txt
5
- */
6
- package json.ext;
7
-
8
- import org.jruby.Ruby;
9
- import org.jruby.RubyArray;
10
- import org.jruby.RubyClass;
11
- import org.jruby.RubyException;
12
- import org.jruby.RubyHash;
13
- import org.jruby.RubyString;
14
- import org.jruby.exceptions.RaiseException;
15
- import org.jruby.runtime.Block;
16
- import org.jruby.runtime.ThreadContext;
17
- import org.jruby.runtime.builtin.IRubyObject;
18
- import org.jruby.util.ByteList;
19
-
20
- /**
21
- * Library of miscellaneous utility functions
22
- */
23
- final class Utils {
24
- public static final String M_GENERATOR_ERROR = "GeneratorError";
25
- public static final String M_NESTING_ERROR = "NestingError";
26
- public static final String M_PARSER_ERROR = "ParserError";
27
-
28
- private Utils() {
29
- throw new RuntimeException();
30
- }
31
-
32
- /**
33
- * Safe {@link RubyArray} type-checking.
34
- * Returns the given object if it is an <code>Array</code>,
35
- * or throws an exception if not.
36
- * @param object The object to test
37
- * @return The given object if it is an <code>Array</code>
38
- * @throws RaiseException <code>TypeError</code> if the object is not
39
- * of the expected type
40
- */
41
- static RubyArray ensureArray(IRubyObject object) throws RaiseException {
42
- if (object instanceof RubyArray) return (RubyArray)object;
43
- Ruby runtime = object.getRuntime();
44
- throw runtime.newTypeError(object, runtime.getArray());
45
- }
46
-
47
- static RubyHash ensureHash(IRubyObject object) throws RaiseException {
48
- if (object instanceof RubyHash) return (RubyHash)object;
49
- Ruby runtime = object.getRuntime();
50
- throw runtime.newTypeError(object, runtime.getHash());
51
- }
52
-
53
- static RubyString ensureString(IRubyObject object) throws RaiseException {
54
- if (object instanceof RubyString) return (RubyString)object;
55
- Ruby runtime = object.getRuntime();
56
- throw runtime.newTypeError(object, runtime.getString());
57
- }
58
-
59
- static RaiseException newException(ThreadContext context,
60
- String className, String message) {
61
- return newException(context, className,
62
- context.getRuntime().newString(message));
63
- }
64
-
65
- static RaiseException newException(ThreadContext context,
66
- String className, RubyString message) {
67
- RuntimeInfo info = RuntimeInfo.forRuntime(context.getRuntime());
68
- RubyClass klazz = info.jsonModule.get().getClass(className);
69
- RubyException excptn =
70
- (RubyException)klazz.newInstance(context,
71
- new IRubyObject[] {message}, Block.NULL_BLOCK);
72
- return new RaiseException(excptn);
73
- }
74
-
75
- static byte[] repeat(ByteList a, int n) {
76
- return repeat(a.unsafeBytes(), a.begin(), a.length(), n);
77
- }
78
-
79
- static byte[] repeat(byte[] a, int begin, int length, int n) {
80
- if (length == 0) return ByteList.NULL_ARRAY;
81
- int resultLen = length * n;
82
- byte[] result = new byte[resultLen];
83
- for (int pos = 0; pos < resultLen; pos += length) {
84
- System.arraycopy(a, begin, result, pos, length);
85
- }
86
- return result;
87
- }
88
- }