1/*
2 * Copyright 2017-2023, Andrew Lindesay <apl@lindesay.co.nz>
3 * Copyright 2014-2017, Augustin Cavalier (waddlesplash)
4 * Copyright 2014, Stephan A��mus <superstippi@gmx.de>
5 * Distributed under the terms of the MIT License.
6 */
7
8
9#include "Json.h"
10
11#include <cstdio>
12#include <cstdlib>
13#include <ctype.h>
14#include <cerrno>
15
16#include <AutoDeleter.h>
17#include <DataIO.h>
18#include <UnicodeChar.h>
19
20#include "JsonEventListener.h"
21#include "JsonMessageWriter.h"
22
23
24// #pragma mark - Public methods
25
26namespace BPrivate {
27
28/*!	A buffer is used to assemble strings into. This will be the initial size
29	of this buffer.
30*/
31
32static const size_t kInitialAssemblyBufferSize = 64;
33
34/*!	A buffer is used to assemble strings into. This buffer starts off small
35	but is able to grow as the string it needs to process as encountered. To
36	avoid frequent reallocation of the buffer, the buffer will be retained
37	between strings. This is the maximum size of buffer that will be retained.
38*/
39
40static const size_t kRetainedAssemblyBufferSize = 32 * 1024;
41
42static const size_t kAssemblyBufferSizeIncrement = 256;
43
44static const size_t kMaximumUtf8SequenceLength = 7;
45
46
47class JsonParseAssemblyBuffer {
48public:
49	JsonParseAssemblyBuffer()
50		:
51		fAssemblyBuffer(NULL),
52		fAssemblyBufferAllocatedSize(0),
53		fAssemblyBufferUsedSize(0)
54	{
55		fAssemblyBuffer = (char*) malloc(kInitialAssemblyBufferSize);
56		if (fAssemblyBuffer != NULL)
57			fAssemblyBufferAllocatedSize = kInitialAssemblyBufferSize;
58	}
59
60	~JsonParseAssemblyBuffer()
61	{
62		if (fAssemblyBuffer != NULL)
63			free(fAssemblyBuffer);
64	}
65
66	const char* Buffer() const
67	{
68		return fAssemblyBuffer;
69	}
70
71	/*! This method should be used each time that the assembly buffer has
72		been finished with by some section of logic.
73	*/
74
75	status_t Reset()
76	{
77		fAssemblyBufferUsedSize = 0;
78
79		if (fAssemblyBufferAllocatedSize > kRetainedAssemblyBufferSize) {
80			fAssemblyBuffer = (char*) realloc(fAssemblyBuffer, kRetainedAssemblyBufferSize);
81			if (fAssemblyBuffer == NULL) {
82				fAssemblyBufferAllocatedSize = 0;
83				return B_NO_MEMORY;
84			}
85			fAssemblyBufferAllocatedSize = kRetainedAssemblyBufferSize;
86		}
87
88		return B_OK;
89	}
90
91	status_t AppendCharacter(char c)
92	{
93		status_t result = _EnsureAssemblyBufferAllocatedSize(fAssemblyBufferUsedSize + 1);
94
95		if (result == B_OK) {
96			fAssemblyBuffer[fAssemblyBufferUsedSize] = c;
97			fAssemblyBufferUsedSize++;
98		}
99
100		return result;
101	}
102
103	status_t AppendCharacters(char* str, size_t len)
104	{
105		status_t result = _EnsureAssemblyBufferAllocatedSize(fAssemblyBufferUsedSize + len);
106
107		if (result == B_OK) {
108			memcpy(&fAssemblyBuffer[fAssemblyBufferUsedSize], str, len);
109			fAssemblyBufferUsedSize += len;
110		}
111
112		return result;
113	}
114
115	status_t AppendUnicodeCharacter(uint32 c)
116	{
117		status_t result = _EnsureAssemblyBufferAllocatedSize(
118			fAssemblyBufferUsedSize + kMaximumUtf8SequenceLength);
119		if (result == B_OK) {
120			char* insertPtr = &fAssemblyBuffer[fAssemblyBufferUsedSize];
121			char* ptr = insertPtr;
122			BUnicodeChar::ToUTF8(c, &ptr);
123			size_t sequenceLength = static_cast<uint32>(ptr - insertPtr);
124			fAssemblyBufferUsedSize += sequenceLength;
125		}
126
127		return result;
128	}
129
130private:
131
132	/*!	This method will return the assembly buffer ensuring that it has at
133		least `minimumSize` bytes available.
134	*/
135
136	status_t _EnsureAssemblyBufferAllocatedSize(size_t minimumSize)
137	{
138		if (fAssemblyBufferAllocatedSize < minimumSize) {
139			size_t requestedSize = minimumSize;
140
141			// if the requested quantity of memory is less than the retained buffer size then
142			// it makes sense to request a wee bit more in order to reduce the number of small
143			// requests to increment the buffer over time.
144
145			if (requestedSize < kRetainedAssemblyBufferSize - kAssemblyBufferSizeIncrement) {
146				requestedSize = ((requestedSize / kAssemblyBufferSizeIncrement) + 1)
147					* kAssemblyBufferSizeIncrement;
148			}
149
150			fAssemblyBuffer = (char*) realloc(fAssemblyBuffer, requestedSize);
151			if (fAssemblyBuffer == NULL) {
152				fAssemblyBufferAllocatedSize = 0;
153				return B_NO_MEMORY;
154			}
155			fAssemblyBufferAllocatedSize = requestedSize;
156		}
157		return B_OK;
158	}
159
160private:
161	char*					fAssemblyBuffer;
162	size_t					fAssemblyBufferAllocatedSize;
163	size_t					fAssemblyBufferUsedSize;
164};
165
166
167class JsonParseAssemblyBufferResetter {
168public:
169	JsonParseAssemblyBufferResetter(JsonParseAssemblyBuffer* assemblyBuffer)
170		:
171		fAssemblyBuffer(assemblyBuffer)
172	{
173	}
174
175	~JsonParseAssemblyBufferResetter()
176	{
177		fAssemblyBuffer->Reset();
178	}
179
180private:
181	JsonParseAssemblyBuffer*
182							fAssemblyBuffer;
183};
184
185
186/*! This class carries state around the parsing process. */
187
188class JsonParseContext {
189public:
190	JsonParseContext(BDataIO* data, BJsonEventListener* listener)
191		:
192		fListener(listener),
193		fData(data),
194		fLineNumber(1), // 1 is the first line
195		fPushbackChar(0),
196		fHasPushbackChar(false),
197		fAssemblyBuffer(new JsonParseAssemblyBuffer())
198	{
199	}
200
201
202	~JsonParseContext()
203	{
204		delete fAssemblyBuffer;
205	}
206
207
208	BJsonEventListener* Listener() const
209	{
210		return fListener;
211	}
212
213
214	BDataIO* Data() const
215	{
216		return fData;
217	}
218
219
220	int LineNumber() const
221	{
222		return fLineNumber;
223	}
224
225
226	void IncrementLineNumber()
227	{
228		fLineNumber++;
229	}
230
231	status_t NextChar(char* buffer)
232	{
233		if (fHasPushbackChar) {
234			buffer[0] = fPushbackChar;
235			fHasPushbackChar = false;
236			return B_OK;
237		}
238
239		return Data()->ReadExactly(buffer, 1);
240	}
241
242	void PushbackChar(char c)
243	{
244		if (fHasPushbackChar)
245			debugger("illegal state - more than one character pushed back");
246		fPushbackChar = c;
247		fHasPushbackChar = true;
248	}
249
250
251	JsonParseAssemblyBuffer* AssemblyBuffer()
252	{
253		return fAssemblyBuffer;
254	}
255
256
257private:
258	BJsonEventListener*		fListener;
259	BDataIO*				fData;
260	uint32					fLineNumber;
261	char					fPushbackChar;
262	bool					fHasPushbackChar;
263	JsonParseAssemblyBuffer*
264							fAssemblyBuffer;
265};
266
267
268status_t
269BJson::Parse(const BString& JSON, BMessage& message)
270{
271	return Parse(JSON.String(), message);
272}
273
274
275status_t
276BJson::Parse(const char* JSON, size_t length, BMessage& message)
277{
278	BMemoryIO* input = new BMemoryIO(JSON, length);
279	ObjectDeleter<BMemoryIO> inputDeleter(input);
280	BJsonMessageWriter* writer = new BJsonMessageWriter(message);
281	ObjectDeleter<BJsonMessageWriter> writerDeleter(writer);
282
283	Parse(input, writer);
284	status_t result = writer->ErrorStatus();
285
286	return result;
287}
288
289
290status_t
291BJson::Parse(const char* JSON, BMessage& message)
292{
293	return Parse(JSON, strlen(JSON), message);
294}
295
296
297/*! The data is read as a stream of JSON data.  As the JSON is read, events are
298    raised such as;
299     - string
300     - number
301     - true
302     - array start
303     - object end
304    Each event is sent to the listener to process as required.
305*/
306
307void
308BJson::Parse(BDataIO* data, BJsonEventListener* listener)
309{
310	JsonParseContext context(data, listener);
311	ParseAny(context);
312	listener->Complete();
313}
314
315
316// #pragma mark - Specific parse logic.
317
318
319bool
320BJson::NextChar(JsonParseContext& jsonParseContext, char* c)
321{
322	status_t result = jsonParseContext.NextChar(c);
323
324	switch (result) {
325		case B_OK:
326			return true;
327
328		case B_PARTIAL_READ:
329		{
330			jsonParseContext.Listener()->HandleError(B_BAD_DATA,
331				jsonParseContext.LineNumber(), "unexpected end of input");
332			return false;
333		}
334
335		default:
336		{
337			jsonParseContext.Listener()->HandleError(result, -1,
338				"io related read error");
339			return false;
340		}
341	}
342}
343
344
345bool
346BJson::NextNonWhitespaceChar(JsonParseContext& jsonParseContext, char* c)
347{
348	while (true) {
349		if (!NextChar(jsonParseContext, c))
350			return false;
351
352		switch (*c) {
353			case 0x0a: // newline
354			case 0x0d: // cr
355				jsonParseContext.IncrementLineNumber();
356			case ' ': // space
357					// swallow whitespace as it is not syntactically
358					// significant.
359				break;
360
361			default:
362				return true;
363		}
364	}
365}
366
367
368bool
369BJson::ParseAny(JsonParseContext& jsonParseContext)
370{
371	char c;
372
373	if (!NextNonWhitespaceChar(jsonParseContext, &c))
374		return false;
375
376	switch (c) {
377		case 'f': // [f]alse
378			return ParseExpectedVerbatimStringAndRaiseEvent(
379				jsonParseContext, "alse", 4, 'f', B_JSON_FALSE);
380
381		case 't': // [t]rue
382			return ParseExpectedVerbatimStringAndRaiseEvent(
383				jsonParseContext, "rue", 3, 't', B_JSON_TRUE);
384
385		case 'n': // [n]ull
386			return ParseExpectedVerbatimStringAndRaiseEvent(
387				jsonParseContext, "ull", 3, 'n', B_JSON_NULL);
388
389		case '"':
390			return ParseString(jsonParseContext, B_JSON_STRING);
391
392		case '{':
393			return ParseObject(jsonParseContext);
394
395		case '[':
396			return ParseArray(jsonParseContext);
397
398		case '+':
399		case '-':
400		case '0':
401		case '1':
402		case '2':
403		case '3':
404		case '4':
405		case '5':
406		case '6':
407		case '7':
408		case '8':
409		case '9':
410			jsonParseContext.PushbackChar(c); // keeps the parse simple
411			return ParseNumber(jsonParseContext);
412
413		default:
414		{
415			BString errorMessage;
416			if (c >= 0x20 && c < 0x7f) {
417				errorMessage.SetToFormat("unexpected character [%" B_PRIu8 "]"
418					" (%c) when parsing element", static_cast<uint8>(c), c);
419			} else {
420				errorMessage.SetToFormat("unexpected character [%" B_PRIu8 "]"
421					" when parsing element", (uint8) c);
422			}
423			jsonParseContext.Listener()->HandleError(B_BAD_DATA,
424				jsonParseContext.LineNumber(), errorMessage.String());
425			return false;
426		}
427	}
428
429	return true;
430}
431
432
433/*! This method captures an object name, a separator ':' and then any value. */
434
435bool
436BJson::ParseObjectNameValuePair(JsonParseContext& jsonParseContext)
437{
438	bool didParseName = false;
439	char c;
440
441	while (true) {
442		if (!NextNonWhitespaceChar(jsonParseContext, &c))
443			return false;
444
445		switch (c) {
446			case '\"': // name of the object
447			{
448				if (!didParseName) {
449					if (!ParseString(jsonParseContext, B_JSON_OBJECT_NAME))
450						return false;
451
452					didParseName = true;
453				} else {
454					jsonParseContext.Listener()->HandleError(B_BAD_DATA,
455						jsonParseContext.LineNumber(), "unexpected"
456							" [\"] character when parsing object name-"
457							" value separator");
458					return false;
459				}
460				break;
461			}
462
463			case ':': // separator
464			{
465				if (didParseName) {
466					if (!ParseAny(jsonParseContext))
467						return false;
468					return true;
469				} else {
470					jsonParseContext.Listener()->HandleError(B_BAD_DATA,
471						jsonParseContext.LineNumber(), "unexpected"
472							" [:] character when parsing object name-"
473							" value pair");
474					return false;
475				}
476			}
477
478			default:
479			{
480				BString errorMessage;
481				errorMessage.SetToFormat(
482					"unexpected character [%c] when parsing object"
483					" name-value pair",
484					c);
485				jsonParseContext.Listener()->HandleError(B_BAD_DATA,
486					jsonParseContext.LineNumber(), errorMessage.String());
487				return false;
488			}
489		}
490	}
491}
492
493
494bool
495BJson::ParseObject(JsonParseContext& jsonParseContext)
496{
497	if (!jsonParseContext.Listener()->Handle(
498			BJsonEvent(B_JSON_OBJECT_START))) {
499		return false;
500	}
501
502	char c;
503	bool firstItem = true;
504
505	while (true) {
506		if (!NextNonWhitespaceChar(jsonParseContext, &c))
507			return false;
508
509		switch (c) {
510			case '}': // terminate the object
511			{
512				if (!jsonParseContext.Listener()->Handle(
513						BJsonEvent(B_JSON_OBJECT_END))) {
514					return false;
515				}
516				return true;
517			}
518
519			case ',': // next value.
520			{
521				if (firstItem) {
522					jsonParseContext.Listener()->HandleError(B_BAD_DATA,
523						jsonParseContext.LineNumber(), "unexpected"
524							" item separator when parsing start of"
525							" object");
526					return false;
527				}
528
529				if (!ParseObjectNameValuePair(jsonParseContext))
530					return false;
531				break;
532			}
533
534			default:
535			{
536				if (firstItem) {
537					jsonParseContext.PushbackChar(c);
538					if (!ParseObjectNameValuePair(jsonParseContext))
539						return false;
540					firstItem = false;
541				} else {
542					jsonParseContext.Listener()->HandleError(B_BAD_DATA,
543						jsonParseContext.LineNumber(), "expected"
544							" separator when parsing an object");
545				}
546			}
547		}
548	}
549
550	return true;
551}
552
553
554bool
555BJson::ParseArray(JsonParseContext& jsonParseContext)
556{
557	if (!jsonParseContext.Listener()->Handle(
558			BJsonEvent(B_JSON_ARRAY_START))) {
559		return false;
560	}
561
562	char c;
563	bool firstItem = true;
564
565	while (true) {
566		if (!NextNonWhitespaceChar(jsonParseContext, &c))
567			return false;
568
569		switch (c) {
570			case ']': // terminate the array
571			{
572				if (!jsonParseContext.Listener()->Handle(
573						BJsonEvent(B_JSON_ARRAY_END))) {
574					return false;
575				}
576				return true;
577			}
578
579			case ',': // next value.
580			{
581				if (firstItem) {
582					jsonParseContext.Listener()->HandleError(B_BAD_DATA,
583						jsonParseContext.LineNumber(), "unexpected"
584							" item separator when parsing start of"
585							" array");
586				}
587
588				if (!ParseAny(jsonParseContext))
589					return false;
590				break;
591			}
592
593			default:
594			{
595				if (firstItem) {
596					jsonParseContext.PushbackChar(c);
597					if (!ParseAny(jsonParseContext))
598						return false;
599					firstItem = false;
600				} else {
601					jsonParseContext.Listener()->HandleError(B_BAD_DATA,
602						jsonParseContext.LineNumber(), "expected"
603							" separator when parsing an array");
604				}
605			}
606		}
607	}
608
609	return true;
610}
611
612
613bool
614BJson::ParseEscapeUnicodeSequence(JsonParseContext& jsonParseContext)
615{
616	char ch;
617	uint32 unicodeCh = 0;
618
619	for (int i = 3; i >= 0; i--) {
620		if (!NextChar(jsonParseContext, &ch)) {
621			jsonParseContext.Listener()->HandleError(B_ERROR, jsonParseContext.LineNumber(),
622				"unable to read unicode sequence");
623			return false;
624		}
625
626		if (ch >= '0' && ch <= '9')
627			unicodeCh |= static_cast<uint32>(ch - '0') << (i * 4);
628		else if (ch >= 'a' && ch <= 'f')
629			unicodeCh |= (10 + static_cast<uint32>(ch - 'a')) << (i * 4);
630		else if (ch >= 'A' && ch <= 'F')
631			unicodeCh |= (10 + static_cast<uint32>(ch - 'A')) << (i * 4);
632		else {
633			BString errorMessage;
634			errorMessage.SetToFormat(
635				"malformed hex character [%c] in unicode sequence in string parsing", ch);
636			jsonParseContext.Listener()->HandleError(B_BAD_DATA, jsonParseContext.LineNumber(),
637				errorMessage.String());
638			return false;
639		}
640	}
641
642	JsonParseAssemblyBuffer* assemblyBuffer = jsonParseContext.AssemblyBuffer();
643	status_t result = assemblyBuffer->AppendUnicodeCharacter(unicodeCh);
644
645	if (result != B_OK) {
646		jsonParseContext.Listener()->HandleError(result, jsonParseContext.LineNumber(),
647			"unable to store unicode char as utf-8");
648		return false;
649	}
650
651	return true;
652}
653
654
655bool
656BJson::ParseStringEscapeSequence(JsonParseContext& jsonParseContext)
657{
658	char c;
659
660	if (!NextChar(jsonParseContext, &c))
661		return false;
662
663	JsonParseAssemblyBuffer* assemblyBuffer = jsonParseContext.AssemblyBuffer();
664
665	switch (c) {
666		case 'n':
667			assemblyBuffer->AppendCharacter('\n');
668			break;
669		case 'r':
670			assemblyBuffer->AppendCharacter('\r');
671			break;
672		case 'b':
673			assemblyBuffer->AppendCharacter('\b');
674			break;
675		case 'f':
676			assemblyBuffer->AppendCharacter('\f');
677			break;
678		case '\\':
679			assemblyBuffer->AppendCharacter('\\');
680			break;
681		case '/':
682			assemblyBuffer->AppendCharacter('/');
683			break;
684		case 't':
685			assemblyBuffer->AppendCharacter('\t');
686			break;
687		case '"':
688			assemblyBuffer->AppendCharacter('"');
689			break;
690		case 'u':
691		{
692				// unicode escape sequence.
693			if (!ParseEscapeUnicodeSequence(jsonParseContext)) {
694				return false;
695			}
696			break;
697		}
698		default:
699		{
700			BString errorMessage;
701			errorMessage.SetToFormat("unexpected escaped character [%c] in string parsing", c);
702			jsonParseContext.Listener()->HandleError(B_BAD_DATA,
703				jsonParseContext.LineNumber(), errorMessage.String());
704			return false;
705		}
706	}
707
708	return true;
709}
710
711
712bool
713BJson::ParseString(JsonParseContext& jsonParseContext,
714	json_event_type eventType)
715{
716	char c;
717	JsonParseAssemblyBuffer* assemblyBuffer = jsonParseContext.AssemblyBuffer();
718	JsonParseAssemblyBufferResetter assembleBufferResetter(assemblyBuffer);
719
720	while(true) {
721		if (!NextChar(jsonParseContext, &c))
722    		return false;
723
724		switch (c) {
725			case '"':
726			{
727					// terminates the string assembled so far.
728				assemblyBuffer->AppendCharacter(0);
729				jsonParseContext.Listener()->Handle(
730					BJsonEvent(eventType, assemblyBuffer->Buffer()));
731				return true;
732			}
733
734			case '\\':
735			{
736				if (!ParseStringEscapeSequence(jsonParseContext))
737					return false;
738				break;
739			}
740
741			default:
742			{
743				uint8 uc = static_cast<uint8>(c);
744
745				if(uc < 0x20) { // control characters are not allowed
746					BString errorMessage;
747					errorMessage.SetToFormat("illegal control character"
748						" [%" B_PRIu8 "] when parsing a string", uc);
749					jsonParseContext.Listener()->HandleError(B_BAD_DATA,
750						jsonParseContext.LineNumber(),
751						errorMessage.String());
752					return false;
753				}
754
755				assemblyBuffer->AppendCharacter(c);
756				break;
757			}
758		}
759	}
760}
761
762
763bool
764BJson::ParseExpectedVerbatimStringAndRaiseEvent(
765	JsonParseContext& jsonParseContext, const char* expectedString,
766	size_t expectedStringLength, char leadingChar,
767	json_event_type jsonEventType)
768{
769	if (ParseExpectedVerbatimString(jsonParseContext, expectedString,
770			expectedStringLength, leadingChar)) {
771		if (!jsonParseContext.Listener()->Handle(BJsonEvent(jsonEventType)))
772			return false;
773	}
774
775	return true;
776}
777
778/*! This will make sure that the constant string is available at the input. */
779
780bool
781BJson::ParseExpectedVerbatimString(JsonParseContext& jsonParseContext,
782	const char* expectedString, size_t expectedStringLength, char leadingChar)
783{
784	char c;
785	size_t offset = 0;
786
787	while (offset < expectedStringLength) {
788		if (!NextChar(jsonParseContext, &c))
789			return false;
790
791		if (c != expectedString[offset]) {
792			BString errorMessage;
793			errorMessage.SetToFormat("malformed json primative literal; "
794				"expected [%c%s], but got [%c] at position %" B_PRIdSSIZE,
795				leadingChar, expectedString, c, offset);
796			jsonParseContext.Listener()->HandleError(B_BAD_DATA,
797				jsonParseContext.LineNumber(), errorMessage.String());
798			return false;
799		}
800
801		offset++;
802	}
803
804	return true;
805}
806
807
808/*! This function checks to see that the supplied string is a well formed
809    JSON number.  It does this from a string rather than a stream for
810    convenience.  This is not anticipated to impact performance because
811    the string values are short.
812*/
813
814bool
815BJson::IsValidNumber(const char* value)
816{
817	int32 offset = 0;
818	int32 len = strlen(value);
819
820	if (offset < len && value[offset] == '-')
821		offset++;
822
823	if (offset >= len)
824		return false;
825
826	if (isdigit(value[offset]) && value[offset] != '0') {
827		while (offset < len && isdigit(value[offset]))
828			offset++;
829	} else {
830		if (value[offset] == '0')
831			offset++;
832		else
833			return false;
834	}
835
836	if (offset < len && value[offset] == '.') {
837		offset++;
838
839		if (offset >= len)
840			return false;
841
842		while (offset < len && isdigit(value[offset]))
843			offset++;
844	}
845
846	if (offset < len && (value[offset] == 'E' || value[offset] == 'e')) {
847		offset++;
848
849		if(offset < len && (value[offset] == '+' || value[offset] == '-'))
850		 	offset++;
851
852		if (offset >= len)
853			return false;
854
855		while (offset < len && isdigit(value[offset]))
856			offset++;
857	}
858
859	return offset == len;
860}
861
862
863/*! Note that this method hits the 'NextChar' method on the context directly
864    and handles any end-of-file state itself because it is feasible that the
865    entire JSON payload is a number and because (unlike other structures, the
866    number can take the end-of-file to signify the end of the number.
867*/
868
869bool
870BJson::ParseNumber(JsonParseContext& jsonParseContext)
871{
872	JsonParseAssemblyBuffer* assemblyBuffer = jsonParseContext.AssemblyBuffer();
873	JsonParseAssemblyBufferResetter assembleBufferResetter(assemblyBuffer);
874
875	while (true) {
876		char c;
877		status_t result = jsonParseContext.NextChar(&c);
878
879		switch (result) {
880			case B_OK:
881			{
882				if (isdigit(c) || c == '.' || c == '-' || c == 'e' || c == 'E' || c == '+') {
883					assemblyBuffer->AppendCharacter(c);
884					break;
885				}
886
887				jsonParseContext.PushbackChar(c);
888				// intentional fall through
889			}
890			case B_PARTIAL_READ:
891			{
892				errno = 0;
893				assemblyBuffer->AppendCharacter(0);
894
895				if (!IsValidNumber(assemblyBuffer->Buffer())) {
896					jsonParseContext.Listener()->HandleError(B_BAD_DATA,
897						jsonParseContext.LineNumber(), "malformed number");
898					return false;
899				}
900
901				jsonParseContext.Listener()->Handle(BJsonEvent(B_JSON_NUMBER,
902					assemblyBuffer->Buffer()));
903
904				return true;
905			}
906			default:
907			{
908				jsonParseContext.Listener()->HandleError(result, -1,
909					"io related read error");
910				return false;
911			}
912		}
913	}
914}
915
916} // namespace BPrivate
917