json 2.4.0 → 2.4.1

Sign up to get free protection for your applications and to get access to all the features.
File without changes
data/install.rb DELETED
@@ -1,23 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- require 'fileutils'
4
- include FileUtils::Verbose
5
- require 'rbconfig'
6
- include\
7
- begin
8
- RbConfig
9
- rescue NameError
10
- Config
11
- end
12
-
13
- sitelibdir = CONFIG["sitelibdir"]
14
- cd 'lib' do
15
- install('json.rb', sitelibdir)
16
- mkdir_p File.join(sitelibdir, 'json')
17
- for file in Dir['json/**/*}']
18
- d = File.join(sitelibdir, file)
19
- mkdir_p File.dirname(d)
20
- install(file, d)
21
- end
22
- end
23
- warn " *** Installed PURE ruby library."
@@ -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 class specialized in transcoding a certain String format into another,
14
- * using UTF-8 ByteLists as both input and output.
15
- */
16
- abstract class ByteListTranscoder {
17
- protected final ThreadContext context;
18
-
19
- protected ByteList src;
20
- protected int srcEnd;
21
- /** Position where the last read character started */
22
- protected int charStart;
23
- /** Position of the next character to read */
24
- protected int pos;
25
-
26
- private ByteList out;
27
- /**
28
- * When a character that can be copied straight into the output is found,
29
- * its index is stored on this variable, and copying is delayed until
30
- * the sequence of characters that can be copied ends.
31
- *
32
- * <p>The variable stores -1 when not in a plain sequence.
33
- */
34
- private int quoteStart = -1;
35
-
36
- protected ByteListTranscoder(ThreadContext context) {
37
- this.context = context;
38
- }
39
-
40
- protected void init(ByteList src, ByteList out) {
41
- this.init(src, 0, src.length(), out);
42
- }
43
-
44
- protected void init(ByteList src, int start, int end, ByteList out) {
45
- this.src = src;
46
- this.pos = start;
47
- this.charStart = start;
48
- this.srcEnd = end;
49
- this.out = out;
50
- }
51
-
52
- /**
53
- * Returns whether there are any characters left to be read.
54
- */
55
- protected boolean hasNext() {
56
- return pos < srcEnd;
57
- }
58
-
59
- /**
60
- * Returns the next character in the buffer.
61
- */
62
- private char next() {
63
- return src.charAt(pos++);
64
- }
65
-
66
- /**
67
- * Reads an UTF-8 character from the input and returns its code point,
68
- * while advancing the input position.
69
- *
70
- * <p>Raises an {@link #invalidUtf8()} exception if an invalid byte
71
- * is found.
72
- */
73
- protected int readUtf8Char() {
74
- charStart = pos;
75
- char head = next();
76
- if (head <= 0x7f) { // 0b0xxxxxxx (ASCII)
77
- return head;
78
- }
79
- if (head <= 0xbf) { // 0b10xxxxxx
80
- throw invalidUtf8(); // tail byte with no head
81
- }
82
- if (head <= 0xdf) { // 0b110xxxxx
83
- ensureMin(1);
84
- int cp = ((head & 0x1f) << 6)
85
- | nextPart();
86
- if (cp < 0x0080) throw invalidUtf8();
87
- return cp;
88
- }
89
- if (head <= 0xef) { // 0b1110xxxx
90
- ensureMin(2);
91
- int cp = ((head & 0x0f) << 12)
92
- | (nextPart() << 6)
93
- | nextPart();
94
- if (cp < 0x0800) throw invalidUtf8();
95
- return cp;
96
- }
97
- if (head <= 0xf7) { // 0b11110xxx
98
- ensureMin(3);
99
- int cp = ((head & 0x07) << 18)
100
- | (nextPart() << 12)
101
- | (nextPart() << 6)
102
- | nextPart();
103
- if (!Character.isValidCodePoint(cp)) throw invalidUtf8();
104
- return cp;
105
- }
106
- // 0b11111xxx?
107
- throw invalidUtf8();
108
- }
109
-
110
- /**
111
- * Throws a GeneratorError if the input list doesn't have at least this
112
- * many bytes left.
113
- */
114
- protected void ensureMin(int n) {
115
- if (pos + n > srcEnd) throw incompleteUtf8();
116
- }
117
-
118
- /**
119
- * Reads the next byte of a multi-byte UTF-8 character and returns its
120
- * contents (lower 6 bits).
121
- *
122
- * <p>Throws a GeneratorError if the byte is not a valid tail.
123
- */
124
- private int nextPart() {
125
- char c = next();
126
- // tail bytes must be 0b10xxxxxx
127
- if ((c & 0xc0) != 0x80) throw invalidUtf8();
128
- return c & 0x3f;
129
- }
130
-
131
-
132
- protected void quoteStart() {
133
- if (quoteStart == -1) quoteStart = charStart;
134
- }
135
-
136
- /**
137
- * When in a sequence of characters that can be copied directly,
138
- * interrupts the sequence and copies it to the output buffer.
139
- *
140
- * @param endPos The offset until which the direct character quoting should
141
- * occur. You may pass {@link #pos} to quote until the most
142
- * recently read character, or {@link #charStart} to quote
143
- * until the character before it.
144
- */
145
- protected void quoteStop(int endPos) {
146
- if (quoteStart != -1) {
147
- out.append(src, quoteStart, endPos - quoteStart);
148
- quoteStart = -1;
149
- }
150
- }
151
-
152
- protected void append(int b) {
153
- out.append(b);
154
- }
155
-
156
- protected void append(byte[] origin, int start, int length) {
157
- out.append(origin, start, length);
158
- }
159
-
160
-
161
- protected abstract RaiseException invalidUtf8();
162
-
163
- protected RaiseException incompleteUtf8() {
164
- return invalidUtf8();
165
- }
166
- }
@@ -1,447 +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.RubyBasicObject;
11
- import org.jruby.RubyBignum;
12
- import org.jruby.RubyBoolean;
13
- import org.jruby.RubyFixnum;
14
- import org.jruby.RubyFloat;
15
- import org.jruby.RubyHash;
16
- import org.jruby.RubyString;
17
- import org.jruby.runtime.ThreadContext;
18
- import org.jruby.runtime.builtin.IRubyObject;
19
- import org.jruby.util.ByteList;
20
-
21
- public final class Generator {
22
- private Generator() {
23
- throw new RuntimeException();
24
- }
25
-
26
- /**
27
- * Encodes the given object as a JSON string, using the given handler.
28
- */
29
- static <T extends IRubyObject> RubyString
30
- generateJson(ThreadContext context, T object,
31
- Handler<? super T> handler, IRubyObject[] args) {
32
- Session session = new Session(context, args.length > 0 ? args[0] : null);
33
- return session.infect(handler.generateNew(session, object));
34
- }
35
-
36
- /**
37
- * Encodes the given object as a JSON string, detecting the appropriate handler
38
- * for the given object.
39
- */
40
- static <T extends IRubyObject> RubyString
41
- generateJson(ThreadContext context, T object, IRubyObject[] args) {
42
- Handler<? super T> handler = getHandlerFor(context.runtime, object);
43
- return generateJson(context, object, handler, args);
44
- }
45
-
46
- /**
47
- * Encodes the given object as a JSON string, using the appropriate
48
- * handler if one is found or calling #to_json if not.
49
- */
50
- public static <T extends IRubyObject> RubyString
51
- generateJson(ThreadContext context, T object,
52
- GeneratorState config) {
53
- Session session = new Session(context, config);
54
- Handler<? super T> handler = getHandlerFor(context.runtime, object);
55
- return handler.generateNew(session, object);
56
- }
57
-
58
- /**
59
- * Returns the best serialization handler for the given object.
60
- */
61
- // Java's generics can't handle this satisfactorily, so I'll just leave
62
- // the best I could get and ignore the warnings
63
- @SuppressWarnings("unchecked")
64
- private static <T extends IRubyObject> Handler<? super T> getHandlerFor(Ruby runtime, T object) {
65
- switch (((RubyBasicObject) object).getNativeClassIndex()) {
66
- case NIL : return (Handler) NIL_HANDLER;
67
- case TRUE : return (Handler) TRUE_HANDLER;
68
- case FALSE : return (Handler) FALSE_HANDLER;
69
- case FLOAT : return (Handler) FLOAT_HANDLER;
70
- case FIXNUM : return (Handler) FIXNUM_HANDLER;
71
- case BIGNUM : return (Handler) BIGNUM_HANDLER;
72
- case STRING :
73
- if (((RubyBasicObject) object).getMetaClass() != runtime.getString()) break;
74
- return (Handler) STRING_HANDLER;
75
- case ARRAY :
76
- if (((RubyBasicObject) object).getMetaClass() != runtime.getArray()) break;
77
- return (Handler) ARRAY_HANDLER;
78
- case HASH :
79
- if (((RubyBasicObject) object).getMetaClass() != runtime.getHash()) break;
80
- return (Handler) HASH_HANDLER;
81
- }
82
- return GENERIC_HANDLER;
83
- }
84
-
85
-
86
- /* Generator context */
87
-
88
- /**
89
- * A class that concentrates all the information that is shared by
90
- * generators working on a single session.
91
- *
92
- * <p>A session is defined as the process of serializing a single root
93
- * object; any handler directly called by container handlers (arrays and
94
- * hashes/objects) shares this object with its caller.
95
- *
96
- * <p>Note that anything called indirectly (via {@link GENERIC_HANDLER})
97
- * won't be part of the session.
98
- */
99
- static class Session {
100
- private final ThreadContext context;
101
- private GeneratorState state;
102
- private IRubyObject possibleState;
103
- private RuntimeInfo info;
104
- private StringEncoder stringEncoder;
105
-
106
- private boolean tainted = false;
107
- private boolean untrusted = false;
108
-
109
- Session(ThreadContext context, GeneratorState state) {
110
- this.context = context;
111
- this.state = state;
112
- }
113
-
114
- Session(ThreadContext context, IRubyObject possibleState) {
115
- this.context = context;
116
- this.possibleState = possibleState == null || possibleState.isNil()
117
- ? null : possibleState;
118
- }
119
-
120
- public ThreadContext getContext() {
121
- return context;
122
- }
123
-
124
- public Ruby getRuntime() {
125
- return context.getRuntime();
126
- }
127
-
128
- public GeneratorState getState() {
129
- if (state == null) {
130
- state = GeneratorState.fromState(context, getInfo(), possibleState);
131
- }
132
- return state;
133
- }
134
-
135
- public RuntimeInfo getInfo() {
136
- if (info == null) info = RuntimeInfo.forRuntime(getRuntime());
137
- return info;
138
- }
139
-
140
- public StringEncoder getStringEncoder() {
141
- if (stringEncoder == null) {
142
- stringEncoder = new StringEncoder(context, getState().asciiOnly(), getState().escapeSlash());
143
- }
144
- return stringEncoder;
145
- }
146
-
147
- public void infectBy(IRubyObject object) {
148
- if (object.isTaint()) tainted = true;
149
- if (object.isUntrusted()) untrusted = true;
150
- }
151
-
152
- public <T extends IRubyObject> T infect(T object) {
153
- if (tainted) object.setTaint(true);
154
- if (untrusted) object.setUntrusted(true);
155
- return object;
156
- }
157
- }
158
-
159
-
160
- /* Handler base classes */
161
-
162
- private static abstract class Handler<T extends IRubyObject> {
163
- /**
164
- * Returns an estimative of how much space the serialization of the
165
- * given object will take. Used for allocating enough buffer space
166
- * before invoking other methods.
167
- */
168
- int guessSize(Session session, T object) {
169
- return 4;
170
- }
171
-
172
- RubyString generateNew(Session session, T object) {
173
- RubyString result;
174
- ByteList buffer = new ByteList(guessSize(session, object));
175
- generate(session, object, buffer);
176
- result = RubyString.newString(session.getRuntime(), buffer);
177
- ThreadContext context = session.getContext();
178
- RuntimeInfo info = session.getInfo();
179
- result.force_encoding(context, info.utf8.get());
180
- return result;
181
- }
182
-
183
- abstract void generate(Session session, T object, ByteList buffer);
184
- }
185
-
186
- /**
187
- * A handler that returns a fixed keyword regardless of the passed object.
188
- */
189
- private static class KeywordHandler<T extends IRubyObject>
190
- extends Handler<T> {
191
- private final ByteList keyword;
192
-
193
- private KeywordHandler(String keyword) {
194
- this.keyword = new ByteList(ByteList.plain(keyword), false);
195
- }
196
-
197
- @Override
198
- int guessSize(Session session, T object) {
199
- return keyword.length();
200
- }
201
-
202
- @Override
203
- RubyString generateNew(Session session, T object) {
204
- return RubyString.newStringShared(session.getRuntime(), keyword);
205
- }
206
-
207
- @Override
208
- void generate(Session session, T object, ByteList buffer) {
209
- buffer.append(keyword);
210
- }
211
- }
212
-
213
-
214
- /* Handlers */
215
-
216
- static final Handler<RubyBignum> BIGNUM_HANDLER =
217
- new Handler<RubyBignum>() {
218
- @Override
219
- void generate(Session session, RubyBignum object, ByteList buffer) {
220
- // JRUBY-4751: RubyBignum.to_s() returns generic object
221
- // representation (fixed in 1.5, but we maintain backwards
222
- // compatibility; call to_s(IRubyObject[]) then
223
- buffer.append(((RubyString)object.to_s(IRubyObject.NULL_ARRAY)).getByteList());
224
- }
225
- };
226
-
227
- static final Handler<RubyFixnum> FIXNUM_HANDLER =
228
- new Handler<RubyFixnum>() {
229
- @Override
230
- void generate(Session session, RubyFixnum object, ByteList buffer) {
231
- buffer.append(object.to_s().getByteList());
232
- }
233
- };
234
-
235
- static final Handler<RubyFloat> FLOAT_HANDLER =
236
- new Handler<RubyFloat>() {
237
- @Override
238
- void generate(Session session, RubyFloat object, ByteList buffer) {
239
- double value = RubyFloat.num2dbl(object);
240
-
241
- if (Double.isInfinite(value) || Double.isNaN(value)) {
242
- if (!session.getState().allowNaN()) {
243
- throw Utils.newException(session.getContext(),
244
- Utils.M_GENERATOR_ERROR,
245
- object + " not allowed in JSON");
246
- }
247
- }
248
- buffer.append(((RubyString)object.to_s()).getByteList());
249
- }
250
- };
251
-
252
- static final Handler<RubyArray> ARRAY_HANDLER =
253
- new Handler<RubyArray>() {
254
- @Override
255
- int guessSize(Session session, RubyArray object) {
256
- GeneratorState state = session.getState();
257
- int depth = state.getDepth();
258
- int perItem =
259
- 4 // prealloc
260
- + (depth + 1) * state.getIndent().length() // indent
261
- + 1 + state.getArrayNl().length(); // ',' arrayNl
262
- return 2 + object.size() * perItem;
263
- }
264
-
265
- @Override
266
- void generate(Session session, RubyArray object, ByteList buffer) {
267
- ThreadContext context = session.getContext();
268
- Ruby runtime = context.getRuntime();
269
- GeneratorState state = session.getState();
270
- int depth = state.increaseDepth();
271
-
272
- ByteList indentUnit = state.getIndent();
273
- byte[] shift = Utils.repeat(indentUnit, depth);
274
-
275
- ByteList arrayNl = state.getArrayNl();
276
- byte[] delim = new byte[1 + arrayNl.length()];
277
- delim[0] = ',';
278
- System.arraycopy(arrayNl.unsafeBytes(), arrayNl.begin(), delim, 1,
279
- arrayNl.length());
280
-
281
- session.infectBy(object);
282
-
283
- buffer.append((byte)'[');
284
- buffer.append(arrayNl);
285
- boolean firstItem = true;
286
- for (int i = 0, t = object.getLength(); i < t; i++) {
287
- IRubyObject element = object.eltInternal(i);
288
- session.infectBy(element);
289
- if (firstItem) {
290
- firstItem = false;
291
- } else {
292
- buffer.append(delim);
293
- }
294
- buffer.append(shift);
295
- Handler<IRubyObject> handler = getHandlerFor(runtime, element);
296
- handler.generate(session, element, buffer);
297
- }
298
-
299
- state.decreaseDepth();
300
- if (arrayNl.length() != 0) {
301
- buffer.append(arrayNl);
302
- buffer.append(shift, 0, state.getDepth() * indentUnit.length());
303
- }
304
-
305
- buffer.append((byte)']');
306
- }
307
- };
308
-
309
- static final Handler<RubyHash> HASH_HANDLER =
310
- new Handler<RubyHash>() {
311
- @Override
312
- int guessSize(Session session, RubyHash object) {
313
- GeneratorState state = session.getState();
314
- int perItem =
315
- 12 // key, colon, comma
316
- + (state.getDepth() + 1) * state.getIndent().length()
317
- + state.getSpaceBefore().length()
318
- + state.getSpace().length();
319
- return 2 + object.size() * perItem;
320
- }
321
-
322
- @Override
323
- void generate(final Session session, RubyHash object,
324
- final ByteList buffer) {
325
- ThreadContext context = session.getContext();
326
- final Ruby runtime = context.getRuntime();
327
- final GeneratorState state = session.getState();
328
- final int depth = state.increaseDepth();
329
-
330
- final ByteList objectNl = state.getObjectNl();
331
- final byte[] indent = Utils.repeat(state.getIndent(), depth);
332
- final ByteList spaceBefore = state.getSpaceBefore();
333
- final ByteList space = state.getSpace();
334
-
335
- buffer.append((byte)'{');
336
- buffer.append(objectNl);
337
-
338
- final boolean[] firstPair = new boolean[]{true};
339
- object.visitAll(new RubyHash.Visitor() {
340
- @Override
341
- public void visit(IRubyObject key, IRubyObject value) {
342
- if (firstPair[0]) {
343
- firstPair[0] = false;
344
- } else {
345
- buffer.append((byte)',');
346
- buffer.append(objectNl);
347
- }
348
- if (objectNl.length() != 0) buffer.append(indent);
349
-
350
- STRING_HANDLER.generate(session, key.asString(), buffer);
351
- session.infectBy(key);
352
-
353
- buffer.append(spaceBefore);
354
- buffer.append((byte)':');
355
- buffer.append(space);
356
-
357
- Handler<IRubyObject> valueHandler = getHandlerFor(runtime, value);
358
- valueHandler.generate(session, value, buffer);
359
- session.infectBy(value);
360
- }
361
- });
362
- state.decreaseDepth();
363
- if (!firstPair[0] && objectNl.length() != 0) {
364
- buffer.append(objectNl);
365
- buffer.append(Utils.repeat(state.getIndent(), state.getDepth()));
366
- }
367
- buffer.append((byte)'}');
368
- }
369
- };
370
-
371
- static final Handler<RubyString> STRING_HANDLER =
372
- new Handler<RubyString>() {
373
- @Override
374
- int guessSize(Session session, RubyString object) {
375
- // for most applications, most strings will be just a set of
376
- // printable ASCII characters without any escaping, so let's
377
- // just allocate enough space for that + the quotes
378
- return 2 + object.getByteList().length();
379
- }
380
-
381
- @Override
382
- void generate(Session session, RubyString object, ByteList buffer) {
383
- RuntimeInfo info = session.getInfo();
384
- RubyString src;
385
-
386
- if (object.encoding(session.getContext()) != info.utf8.get()) {
387
- src = (RubyString)object.encode(session.getContext(),
388
- info.utf8.get());
389
- } else {
390
- src = object;
391
- }
392
-
393
- session.getStringEncoder().encode(src.getByteList(), buffer);
394
- }
395
- };
396
-
397
- static final Handler<RubyBoolean> TRUE_HANDLER =
398
- new KeywordHandler<RubyBoolean>("true");
399
- static final Handler<RubyBoolean> FALSE_HANDLER =
400
- new KeywordHandler<RubyBoolean>("false");
401
- static final Handler<IRubyObject> NIL_HANDLER =
402
- new KeywordHandler<IRubyObject>("null");
403
-
404
- /**
405
- * The default handler (<code>Object#to_json</code>): coerces the object
406
- * to string using <code>#to_s</code>, and serializes that string.
407
- */
408
- static final Handler<IRubyObject> OBJECT_HANDLER =
409
- new Handler<IRubyObject>() {
410
- @Override
411
- RubyString generateNew(Session session, IRubyObject object) {
412
- RubyString str = object.asString();
413
- return STRING_HANDLER.generateNew(session, str);
414
- }
415
-
416
- @Override
417
- void generate(Session session, IRubyObject object, ByteList buffer) {
418
- RubyString str = object.asString();
419
- STRING_HANDLER.generate(session, str, buffer);
420
- }
421
- };
422
-
423
- /**
424
- * A handler that simply calls <code>#to_json(state)</code> on the
425
- * given object.
426
- */
427
- static final Handler<IRubyObject> GENERIC_HANDLER =
428
- new Handler<IRubyObject>() {
429
- @Override
430
- RubyString generateNew(Session session, IRubyObject object) {
431
- if (object.respondsTo("to_json")) {
432
- IRubyObject result = object.callMethod(session.getContext(), "to_json",
433
- new IRubyObject[] {session.getState()});
434
- if (result instanceof RubyString) return (RubyString)result;
435
- throw session.getRuntime().newTypeError("to_json must return a String");
436
- } else {
437
- return OBJECT_HANDLER.generateNew(session, object);
438
- }
439
- }
440
-
441
- @Override
442
- void generate(Session session, IRubyObject object, ByteList buffer) {
443
- RubyString result = generateNew(session, object);
444
- buffer.append(result.getByteList());
445
- }
446
- };
447
- }