30 t =
t.findEndOfWhitespace();
32 switch (
t.getAndAdvance())
35 case '{':
return parseObject (
t, result);
36 case '[':
return parseArray (
t, result);
39 return createFail (
"Expected '{' or '['", &
t);
48 auto c =
t.getAndAdvance();
55 c =
t.getAndAdvance();
64 case 'a':
c =
'\a';
break;
65 case 'b':
c =
'\b';
break;
66 case 'f':
c =
'\f';
break;
67 case 'n':
c =
'\n';
break;
68 case 'r':
c =
'\r';
break;
69 case 't':
c =
'\t';
break;
75 for (
int i = 4; --i >= 0;)
80 return createFail (
"Syntax error in unicode escape sequence");
91 return createFail (
"Unexpected end-of-input in string constant");
102 t =
t.findEndOfWhitespace();
105 switch (
t2.getAndAdvance())
107 case '{':
t =
t2;
return parseObject (
t, result);
108 case '[':
t =
t2;
return parseArray (
t, result);
109 case '"':
t =
t2;
return parseString (
'"',
t, result);
110 case '\'':
t =
t2;
return parseString (
'\'',
t, result);
113 t2 =
t2.findEndOfWhitespace();
118 return parseNumber (
t, result,
true);
120 case '0':
case '1':
case '2':
case '3':
case '4':
121 case '5':
case '6':
case '7':
case '8':
case '9':
122 return parseNumber (
t, result,
false);
125 if (
t2.getAndAdvance() ==
'r' &&
t2.getAndAdvance() ==
'u' &&
t2.getAndAdvance() ==
'e')
134 if (
t2.getAndAdvance() ==
'a' &&
t2.getAndAdvance() ==
'l'
135 &&
t2.getAndAdvance() ==
's' &&
t2.getAndAdvance() ==
'e')
138 result =
var (
false);
144 if (
t2.getAndAdvance() ==
'u' &&
t2.getAndAdvance() ==
'l' &&
t2.getAndAdvance() ==
'l')
156 return createFail (
"Syntax error", &
t);
163 if (location !=
nullptr)
164 m <<
": \"" <<
String (*location, 20) <<
'"';
173 int64 intValue =
t.getAndAdvance() -
'0';
174 jassert (intValue >= 0 && intValue < 10);
179 auto c =
t.getAndAdvance();
182 if (isPositiveAndBelow (
digit, 10))
184 intValue = intValue * 10 +
digit;
188 if (
c ==
'e' ||
c ==
'E' ||
c ==
'.')
197 ||
c ==
',' ||
c ==
'}' ||
c ==
']' ||
c == 0)
203 return createFail (
"Syntax error in number", &
oldT);
208 if ((intValue >> 31) != 0)
224 t =
t.findEndOfWhitespace();
227 auto c =
t.getAndAdvance();
233 return createFail (
"Unexpected end-of-input in object declaration");
247 t =
t.findEndOfWhitespace();
250 auto c2 =
t.getAndAdvance();
253 return createFail (
"Expected ':', but found", &
oldT);
263 t =
t.findEndOfWhitespace();
276 return createFail (
"Expected object member declaration, but found", &
oldT);
289 t =
t.findEndOfWhitespace();
292 auto c =
t.getAndAdvance();
298 return createFail (
"Unexpected end-of-input in array declaration");
307 t =
t.findEndOfWhitespace();
318 return createFail (
"Expected object array item, but found", &
oldT);
334 writeString (
out,
v.toString().getCharPointer());
341 else if (
v.isUndefined())
349 else if (
v.isDouble())
351 auto d =
static_cast<double> (
v);
353 if (juce_isfinite (d))
355 out << serialiseDouble (d);
362 else if (
v.isArray())
366 else if (
v.isObject())
368 if (
auto*
object =
v.getDynamicObject())
376 jassert (! (
v.isMethod() ||
v.isBinaryData()));
382 static void writeEscapedChar (
OutputStream&
out,
const unsigned short value)
391 auto c =
t.getAndAdvance();
397 case '\"':
out <<
"\\\"";
break;
398 case '\\':
out <<
"\\\\";
break;
399 case '\a':
out <<
"\\a";
break;
400 case '\b':
out <<
"\\b";
break;
401 case '\f':
out <<
"\\f";
break;
402 case '\t':
out <<
"\\t";
break;
403 case '\r':
out <<
"\\r";
break;
404 case '\n':
out <<
"\\n";
break;
407 if (
c >= 32 &&
c < 127)
419 for (
int i = 0; i < 2; ++i)
420 writeEscapedChar (
out, (
unsigned short)
chars[i]);
424 writeEscapedChar (
out, (
unsigned short)
c);
448 for (
int i = 0; i < array.
size(); ++i)
455 if (i < array.
size() - 1)
460 out <<
',' << newLine;
473 enum { indentSize = 2 };
481 if (!
parse (text, result))
491 if (! JSONParser::parseAny (text.
text, result))
509 return JSONParser::parseObjectOrArray (text.
getCharPointer(), result);
527 JSONFormatter::writeString (
mo,
s.text);
528 return mo.toString();
533 auto quote =
t.getAndAdvance();
536 return JSONParser::parseString (
quote,
t, result);
552 juce_wchar buffer[40] = { 0 };
554 for (
int i = 0; i < numElementsInArray (buffer) - 1; ++i)
560 buffer[i] = (juce_wchar) (1 + r.nextInt (0x10ffff - 1));
565 buffer[i] = (juce_wchar) (1 + r.nextInt (0xff));
568 return CharPointer_UTF32 (buffer);
573 char buffer[30] = { 0 };
575 for (
int i = 0; i < numElementsInArray (buffer) - 1; ++i)
577 static const char chars[] =
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-:";
578 buffer[i] =
chars [r.nextInt (
sizeof (
chars) - 1)];
581 return CharPointer_ASCII (buffer);
588 return var ((r.nextDouble() * 1000.0) + 0.1);
593 switch (r.nextInt (
depth > 3 ? 6 : 8))
596 case 1:
return r.nextInt();
597 case 2:
return r.nextInt64();
598 case 3:
return r.nextBool();
606 for (
int i = 1 + r.nextInt (30); --i >= 0;)
614 DynamicObject*
o =
new DynamicObject();
616 for (
int i = r.nextInt (30); --i >= 0;)
627 void runTest()
override
632 Random r = getRandom();
638 expect (
JSON::parse (
"[ 12345678901234 ]")[0].isInt64());
639 expect (
JSON::parse (
"[ 1.123e3 ]")[0].isDouble());
641 expect (
JSON::parse (
"[-12345678901234]")[0].isInt64());
644 for (
int i = 100; --i >= 0;)
651 const bool oneLine = r.nextBool();
660 beginTest (
"Float formatting");
662 std::map<double, String>
tests;
665 tests[1.01] =
"1.01";
666 tests[0.76378] =
"0.76378";
667 tests[-10] =
"-10.0";
668 tests[10.01] =
"10.01";
669 tests[0.0123] =
"0.0123";
670 tests[-3.7e-27] =
"-3.7e-27";
672 tests[-12345678901234567.0] =
"-1.234567890123457e16";
673 tests[192000] =
"192000.0";
674 tests[1234567] =
"1.234567e6";
675 tests[0.00006] =
"0.00006";
676 tests[0.000006] =
"6.0e-6";
684static JSONTests JSONUnitTests;
Holds a resizable array of primitive or copy-by-value objects.
bool isEmpty() const noexcept
Returns true if the array is empty, false otherwise.
int size() const noexcept
Returns the current number of elements in the array.
Array()=default
Creates an empty array.
void add(const ElementType &newElement)
Appends a new element at the end of the array.
ElementType & getReference(int index) const noexcept
Returns a direct reference to one of the elements in the array, without checking the index passed in.
void set(int indexToChange, ParameterType newValue)
Replaces an element with a new value.
Wraps a pointer to a null-terminated UTF-16 character string, and provides various methods to operate...
static size_t getBytesRequiredFor(juce_wchar charToWrite) noexcept
Returns the number of bytes that would be needed to represent the given unicode character in this enc...
static bool canRepresent(juce_wchar character) noexcept
Returns true if the given unicode character can be represented in this encoding.
Wraps a pointer to a null-terminated UTF-8 character string, and provides various methods to operate ...
static bool isDigit(char character) noexcept
Checks whether a character is a digit.
static double readDoubleValue(CharPointerType &text) noexcept
Parses a character string to read a floating-point number.
static int getHexDigitValue(juce_wchar digit) noexcept
Returns 0 to 16 for '0' to 'F", or -1 for characters that aren't a legal hex digit.
static bool isWhitespace(char character) noexcept
Checks whether a character is whitespace.
Represents a dynamically implemented object.
Represents a local file or directory.
String loadFileAsString() const
Reads a file into memory as a string.
Represents a string identifier, designed for accessing properties by name.
static var fromString(StringRef)
Parses a string that was created with the toString() method.
static Result parse(const String &text, var &parsedResult)
Parses a string of JSON-formatted text, and returns a result code containing any parse errors.
static String escapeString(StringRef)
Returns a version of a string with any extended characters escaped.
static String toString(const var &objectToFormat, bool allOnOneLine=false, int maximumDecimalPlaces=15)
Returns a string which contains a JSON-formatted representation of the var object.
static void writeToStream(OutputStream &output, const var &objectToFormat, bool allOnOneLine=false, int maximumDecimalPlaces=15)
Writes a JSON-formatted representation of the var object to the given stream.
static Result parseQuotedString(String::CharPointerType &text, var &result)
Parses a quoted string-literal in JSON format, returning the un-escaped result in the result paramete...
Writes data to an internal memory buffer, which grows as required.
String toUTF8() const
Returns a String created from the (UTF8) data that has been written to the stream.
bool appendUTF8Char(juce_wchar character)
Appends the utf-8 bytes for a unicode character.
The base class for streams that write data to some kind of destination.
Represents the 'success' or 'failure' of an operation, and holds an associated error message to descr...
static Result fail(const String &errorMessage) noexcept
Creates a 'failure' result.
static Result ok() noexcept
Creates and returns a 'successful' result.
A simple class for holding temporary references to a string literal or String.
String::CharPointerType text
The text that is referenced.
CharPointerType getCharPointer() const noexcept
Returns the character pointer currently being used to store this string.
static String toHexString(IntegerType number)
Returns a string representing this numeric value in hexadecimal.
This is a base class for classes that perform a unit test.
A variant class, that can be used to hold a range of primitive values.
Array< var > * getArray() const noexcept
If this variant holds an array, this provides access to it.