A Demo Project for the UnrealEngineSDK
Loading...
Searching...
No Matches
VaRestJsonParser.cpp
Go to the documentation of this file.
1// Copyright 2015-2019 Mail.Ru Group. All Rights Reserved.
2
3#include "VaRestJsonParser.h"
4
5#include "VaRestJsonObject.h"
6
7#include "Dom/JsonObject.h"
8#include "Dom/JsonValue.h"
9
10uint32 FUtf8Helper::CodepointFromUtf8(const ANSICHAR*& SourceString, const uint32 SourceLengthRemaining)
11{
12 checkSlow(SourceLengthRemaining > 0);
13
14 const ANSICHAR* OctetPtr = SourceString;
15
16 uint32 Codepoint = 0;
17 uint32 Octet = (uint32)((uint8)*SourceString);
18 uint32 Octet2, Octet3, Octet4;
19
20 if (Octet < 128) // one octet char: 0 to 127
21 {
22 ++SourceString; // skip to next possible start of codepoint.
23 return Octet;
24 }
25 else if (Octet < 192) // bad (starts with 10xxxxxx).
26 {
27 // Apparently each of these is supposed to be flagged as a bogus
28 // char, instead of just resyncing to the next valid codepoint.
29 ++SourceString; // skip to next possible start of codepoint.
30 return UNICODE_BOGUS_CHAR_CODEPOINT;
31 }
32 else if (Octet < 224) // two octets
33 {
34 // Ensure our string has enough characters to read from
35 if (SourceLengthRemaining < 2)
36 {
37 // Skip to end and write out a single char (we always have room for at least 1 char)
38 SourceString += SourceLengthRemaining;
39 return UNICODE_BOGUS_CHAR_CODEPOINT;
40 }
41
42 Octet -= (128 + 64);
43 Octet2 = (uint32)((uint8) * (++OctetPtr));
44 if ((Octet2 & (128 + 64)) != 128) // Format isn't 10xxxxxx?
45 {
46 ++SourceString; // Sequence was not valid UTF-8. Skip the first byte and continue.
47 return UNICODE_BOGUS_CHAR_CODEPOINT;
48 }
49
50 Codepoint = ((Octet << 6) | (Octet2 - 128));
51 if ((Codepoint >= 0x80) && (Codepoint <= 0x7FF))
52 {
53 SourceString += 2; // skip to next possible start of codepoint.
54 return Codepoint;
55 }
56 }
57 else if (Octet < 240) // three octets
58 {
59 // Ensure our string has enough characters to read from
60 if (SourceLengthRemaining < 3)
61 {
62 // Skip to end and write out a single char (we always have room for at least 1 char)
63 SourceString += SourceLengthRemaining;
64 return UNICODE_BOGUS_CHAR_CODEPOINT;
65 }
66
67 Octet -= (128 + 64 + 32);
68 Octet2 = (uint32)((uint8) * (++OctetPtr));
69 if ((Octet2 & (128 + 64)) != 128) // Format isn't 10xxxxxx?
70 {
71 ++SourceString; // Sequence was not valid UTF-8. Skip the first byte and continue.
72 return UNICODE_BOGUS_CHAR_CODEPOINT;
73 }
74
75 Octet3 = (uint32)((uint8) * (++OctetPtr));
76 if ((Octet3 & (128 + 64)) != 128) // Format isn't 10xxxxxx?
77 {
78 ++SourceString; // Sequence was not valid UTF-8. Skip the first byte and continue.
79 return UNICODE_BOGUS_CHAR_CODEPOINT;
80 }
81
82 Codepoint = (((Octet << 12)) | ((Octet2 - 128) << 6) | ((Octet3 - 128)));
83
84 // UTF-8 characters cannot be in the UTF-16 surrogates range
85 if (StringConv::IsHighSurrogate(Codepoint) || StringConv::IsLowSurrogate(Codepoint))
86 {
87 ++SourceString; // Sequence was not valid UTF-8. Skip the first byte and continue.
88 return UNICODE_BOGUS_CHAR_CODEPOINT;
89 }
90
91 // 0xFFFE and 0xFFFF are illegal, too, so we check them at the edge.
92 if ((Codepoint >= 0x800) && (Codepoint <= 0xFFFD))
93 {
94 SourceString += 3; // skip to next possible start of codepoint.
95 return Codepoint;
96 }
97 }
98 else if (Octet < 248) // four octets
99 {
100 // Ensure our string has enough characters to read from
101 if (SourceLengthRemaining < 4)
102 {
103 // Skip to end and write out a single char (we always have room for at least 1 char)
104 SourceString += SourceLengthRemaining;
105 return UNICODE_BOGUS_CHAR_CODEPOINT;
106 }
107
108 Octet -= (128 + 64 + 32 + 16);
109 Octet2 = (uint32)((uint8) * (++OctetPtr));
110 if ((Octet2 & (128 + 64)) != 128) // Format isn't 10xxxxxx?
111 {
112 ++SourceString; // Sequence was not valid UTF-8. Skip the first byte and continue.
113 return UNICODE_BOGUS_CHAR_CODEPOINT;
114 }
115
116 Octet3 = (uint32)((uint8) * (++OctetPtr));
117 if ((Octet3 & (128 + 64)) != 128) // Format isn't 10xxxxxx?
118 {
119 ++SourceString; // Sequence was not valid UTF-8. Skip the first byte and continue.
120 return UNICODE_BOGUS_CHAR_CODEPOINT;
121 }
122
123 Octet4 = (uint32)((uint8) * (++OctetPtr));
124 if ((Octet4 & (128 + 64)) != 128) // Format isn't 10xxxxxx?
125 {
126 ++SourceString; // Sequence was not valid UTF-8. Skip the first byte and continue.
127 return UNICODE_BOGUS_CHAR_CODEPOINT;
128 }
129
130 Codepoint = (((Octet << 18)) | ((Octet2 - 128) << 12) |
131 ((Octet3 - 128) << 6) | ((Octet4 - 128)));
132 if ((Codepoint >= 0x10000) && (Codepoint <= 0x10FFFF))
133 {
134 SourceString += 4; // skip to next possible start of codepoint.
135 return Codepoint;
136 }
137 }
138 // Five and six octet sequences became illegal in rfc3629.
139 // We throw the codepoint away, but parse them to make sure we move
140 // ahead the right number of bytes and don't overflow the buffer.
141 else if (Octet < 252) // five octets
142 {
143 // Ensure our string has enough characters to read from
144 if (SourceLengthRemaining < 5)
145 {
146 // Skip to end and write out a single char (we always have room for at least 1 char)
147 SourceString += SourceLengthRemaining;
148 return UNICODE_BOGUS_CHAR_CODEPOINT;
149 }
150
151 Octet = (uint32)((uint8) * (++OctetPtr));
152 if ((Octet & (128 + 64)) != 128) // Format isn't 10xxxxxx?
153 {
154 ++SourceString; // Sequence was not valid UTF-8. Skip the first byte and continue.
155 return UNICODE_BOGUS_CHAR_CODEPOINT;
156 }
157
158 Octet = (uint32)((uint8) * (++OctetPtr));
159 if ((Octet & (128 + 64)) != 128) // Format isn't 10xxxxxx?
160 {
161 ++SourceString; // Sequence was not valid UTF-8. Skip the first byte and continue.
162 return UNICODE_BOGUS_CHAR_CODEPOINT;
163 }
164
165 Octet = (uint32)((uint8) * (++OctetPtr));
166 if ((Octet & (128 + 64)) != 128) // Format isn't 10xxxxxx?
167 {
168 ++SourceString; // Sequence was not valid UTF-8. Skip the first byte and continue.
169 return UNICODE_BOGUS_CHAR_CODEPOINT;
170 }
171
172 Octet = (uint32)((uint8) * (++OctetPtr));
173 if ((Octet & (128 + 64)) != 128) // Format isn't 10xxxxxx?
174 {
175 ++SourceString; // Sequence was not valid UTF-8. Skip the first byte and continue.
176 return UNICODE_BOGUS_CHAR_CODEPOINT;
177 }
178
179 SourceString += 5; // skip to next possible start of codepoint.
180 return UNICODE_BOGUS_CHAR_CODEPOINT;
181 }
182
183 else // six octets
184 {
185 // Ensure our string has enough characters to read from
186 if (SourceLengthRemaining < 6)
187 {
188 // Skip to end and write out a single char (we always have room for at least 1 char)
189 SourceString += SourceLengthRemaining;
190 return UNICODE_BOGUS_CHAR_CODEPOINT;
191 }
192
193 Octet = (uint32)((uint8) * (++OctetPtr));
194 if ((Octet & (128 + 64)) != 128) // Format isn't 10xxxxxx?
195 {
196 ++SourceString; // Sequence was not valid UTF-8. Skip the first byte and continue.
197 return UNICODE_BOGUS_CHAR_CODEPOINT;
198 }
199
200 Octet = (uint32)((uint8) * (++OctetPtr));
201 if ((Octet & (128 + 64)) != 128) // Format isn't 10xxxxxx?
202 {
203 ++SourceString; // Sequence was not valid UTF-8. Skip the first byte and continue.
204 return UNICODE_BOGUS_CHAR_CODEPOINT;
205 }
206
207 Octet = (uint32)((uint8) * (++OctetPtr));
208 if ((Octet & (128 + 64)) != 128) // Format isn't 10xxxxxx?
209 {
210 ++SourceString; // Sequence was not valid UTF-8. Skip the first byte and continue.
211 return UNICODE_BOGUS_CHAR_CODEPOINT;
212 }
213
214 Octet = (uint32)((uint8) * (++OctetPtr));
215 if ((Octet & (128 + 64)) != 128) // Format isn't 10xxxxxx?
216 {
217 ++SourceString; // Sequence was not valid UTF-8. Skip the first byte and continue.
218 return UNICODE_BOGUS_CHAR_CODEPOINT;
219 }
220
221 Octet = (uint32)((uint8) * (++OctetPtr));
222 if ((Octet & (128 + 64)) != 128) // Format isn't 10xxxxxx?
223 {
224 ++SourceString; // Sequence was not valid UTF-8. Skip the first byte and continue.
225 return UNICODE_BOGUS_CHAR_CODEPOINT;
226 }
227
228 SourceString += 6; // skip to next possible start of codepoint.
229 return UNICODE_BOGUS_CHAR_CODEPOINT;
230 }
231
232 ++SourceString; // Sequence was not valid UTF-8. Skip the first byte and continue.
233 return UNICODE_BOGUS_CHAR_CODEPOINT; // catch everything else.
234}
235
237 : Notation(EJSONNotation::NONE)
238 , bEscape(false)
239 , bError(false)
240 , Quote(UNICODE_BOGUS_CHAR_CODEPOINT)
241{
242 Key.Reserve(1024);
243 Data.Reserve(4096);
244
245 Root = TSharedPtr<FJsonObject>(nullptr);
246
247 Objects.Reserve(64);
248 Tokens.Reserve(64);
249
251
252 Size = 0;
253}
254
256{
257 return Tokens.Num() > Index ? Tokens.Last(Index) : EJSONToken::ERROR;
258}
259
261{
262 return T1 == GetToken(0);
263}
264
266{
267 return T1 == GetToken(1) && T2 == GetToken(0);
268}
269
271{
272 return T1 == GetToken(2) && T2 == GetToken(1) && T3 == GetToken(0);
273}
274
275void FJSONState::PopToken(int32 Num)
276{
277 if (Num > 0)
278 {
279 if (Tokens.Num() >= Num)
280 {
281 Tokens.RemoveAt(Tokens.Num() - Num, Num, false);
282 }
283 else
284 {
285 bError = true;
286 }
287 }
288
290}
291
293{
294 if (Objects.Num() > 0)
295 {
296 const auto Object = Objects.Pop(false);
297 if (Object->Type == EJson::Object)
298 {
299 return;
300 }
301 }
302
303 bError = true;
304}
305
307{
308 if (Objects.Num() > 0)
309 {
310 const auto Object = Objects.Pop(false);
311 if (Object->Type == EJson::Array)
312 {
313 return;
314 }
315 }
316
317 bError = true;
318}
319
320void FJSONState::PopValue(bool bCheckType)
321{
322 if (Objects.Num() > 0)
323 {
324 const auto Value = Objects.Last(0);
325 if (Value->Type == EJson::Object || Value->Type == EJson::Array)
326 {
327 if (bCheckType)
328 {
329 bError = true;
330 }
331 }
332 else
333 {
334 Objects.Pop(false);
335 if (Objects.Num() > 0)
336 {
337 switch (Value->Type)
338 {
339 case EJson::Null:
340 {
341 const auto LowerCase = Data.ToLower();
342 if (LowerCase != TEXT("null"))
343 {
344 bError = true;
345 }
346 break;
347 }
348 case EJson::String:
349 {
350 FJsonValueNonConstString* JsonValueString = ((FJsonValueNonConstString*)Value.Get());
351 JsonValueString->AsNonConstString() = Data;
352 JsonValueString->AsNonConstString().Shrink();
353 Size += JsonValueString->AsNonConstString().GetAllocatedSize();
354 break;
355 }
356 case EJson::Number:
357 {
358 const FString LowerCase = Data.ToLower();
359 int32 ePosition = INDEX_NONE;
360 LowerCase.FindChar('e', ePosition);
361 if (ePosition == INDEX_NONE)
362 {
363 if (LowerCase.IsNumeric())
364 {
365 ((FJsonValueNonConstNumber*)Value.Get())->AsNonConstNumber() = FCString::Atod(*LowerCase);
366 }
367 else
368 {
369 bError = true;
370 }
371 }
372 else if (LowerCase.Len() > ePosition + 2)
373 {
374 const FString Left = LowerCase.Left(ePosition);
375 const FString Rigth = LowerCase.Right(LowerCase.Len() - ePosition - 1);
376 if (Left.IsNumeric() && Rigth.IsNumeric())
377 {
378 ((FJsonValueNonConstNumber*)Value.Get())->AsNonConstNumber() = FCString::Atod(*Left) * FMath::Pow(10.f, FCString::Atoi(*Rigth));
379 }
380 else
381 {
382 bError = true;
383 }
384 }
385 else
386 {
387 bError = true;
388 }
389 break;
390 }
391 case EJson::Boolean:
392 {
393 const auto LowerCase = Data.ToLower();
394 if (LowerCase == TEXT("true"))
395 {
396 ((FJsonValueNonConstBoolean*)Value.Get())->AsNonConstBool() = true;
397 }
398 else if (LowerCase == TEXT("false"))
399 {
400 ((FJsonValueNonConstBoolean*)Value.Get())->AsNonConstBool() = false;
401 }
402 else
403 {
404 bError = true;
405 }
406 break;
407 }
408 default:
409 {
410 bError = true;
411 return;
412 }
413 }
414
415 ClearData();
416
417 const auto Container = Objects.Last(0);
418 if (Container->Type == EJson::Object)
419 {
420 if (Key.Len() > 0)
421 {
422 FString KeyCopy = Key;
423 KeyCopy.Shrink();
424 Container->AsObject()->SetField(KeyCopy, Value);
425 Size += KeyCopy.GetAllocatedSize();
426 ClearKey();
427 }
428 else
429 {
430 bError = true;
431 }
432 }
433 else if (Container->Type == EJson::Array)
434 {
435 ((FJsonValueNonConstArray*)Container.Get())->AsNonConstArray().Add(Value);
436 }
437 else
438 {
439 bError = true;
440 }
441 }
442 else
443 {
444 bError = true;
445 }
446 }
447 }
448 else
449 {
450 bError = true;
451 }
452}
453
455{
456 if (Objects.Num() > 0)
457 {
458 return Objects.Last(0).Get();
459 }
460 bError = true;
461 return nullptr;
462}
463
464FJsonValueObject* FJSONState::GetObject()
465{
466 FJsonValue* Value = GetLast();
467 if (Value != nullptr && Value->Type == EJson::Object)
468 {
469 return (FJsonValueObject*)Value;
470 }
471 bError = true;
472 return nullptr;
473}
474
476{
477 FJsonValue* Value = GetLast();
478 if (Value != nullptr && Value->Type == EJson::Array)
479 {
480 return (FJsonValueNonConstArray*)Value;
481 }
482 bError = true;
483 return nullptr;
484}
485
486TSharedPtr<FJsonValueObject> FJSONState::PushObject()
487{
488 TSharedPtr<FJsonValueObject> Result(new FJsonValueObject(TSharedPtr<FJsonObject>(new FJsonObject())));
489 Objects.Add(Result);
490 Size += sizeof(TSharedPtr<FJsonValueObject>) + sizeof(FJsonValueObject);
491 return Result;
492}
493
494TSharedPtr<FJsonValueObject> FJSONState::PushObject(TSharedPtr<FJsonObject> Object)
495{
496 TSharedPtr<FJsonValueObject> Result(new FJsonValueObject(Object));
497 Objects.Add(Result);
498 Size += sizeof(TSharedPtr<FJsonValueObject>) + sizeof(FJsonValueObject);
499 return Result;
500}
501
502TSharedPtr<FJsonValueNonConstArray> FJSONState::PushArray()
503{
504 const TArray<TSharedPtr<FJsonValue>> Empty;
505 TSharedPtr<FJsonValueNonConstArray> Result(new FJsonValueNonConstArray(Empty));
506 Objects.Add(Result);
507 Size += sizeof(TSharedPtr<FJsonValueNonConstArray>) + sizeof(FJsonValueNonConstArray);
508 return Result;
509}
510
511TSharedPtr<FJsonValueNonConstBoolean> FJSONState::PushBoolean()
512{
513 TSharedPtr<FJsonValueNonConstBoolean> Result(new FJsonValueNonConstBoolean(false));
514 Objects.Add(Result);
515 Size += sizeof(TSharedPtr<FJsonValueNonConstBoolean>) + sizeof(FJsonValueNonConstBoolean);
516 return Result;
517}
518
519TSharedPtr<FJsonValueNull> FJSONState::PushNull()
520{
521 TSharedPtr<FJsonValueNull> Result(new FJsonValueNull());
522 Objects.Add(Result);
523 Size += sizeof(TSharedPtr<FJsonValueNull>) + sizeof(FJsonValueNull);
524 return Result;
525}
526
527TSharedPtr<FJsonValueNonConstNumber> FJSONState::PushNumber()
528{
529 TSharedPtr<FJsonValueNonConstNumber> Result(new FJsonValueNonConstNumber(0.f));
530 Objects.Add(Result);
531 Size += sizeof(TSharedPtr<FJsonValueNonConstNumber>) + sizeof(FJsonValueNonConstNumber);
532 return Result;
533}
534
535TSharedPtr<FJsonValueNonConstString> FJSONState::PushString()
536{
537 TSharedPtr<FJsonValueNonConstString> Result(new FJsonValueNonConstString(TEXT("")));
538 Objects.Add(Result);
539 Size += sizeof(TSharedPtr<FJsonValueNonConstString>) + sizeof(FJsonValueNonConstString);
540 return Result;
541}
542
544{
545 Data.Empty(Data.GetCharArray().Max());
546}
547
549{
550 Key.Empty(Key.GetCharArray().Max());
551}
552
554{
555 ClearKey();
556 Key += Data;
557 ClearData();
558}
559
561{
562 bError = true;
563}
564
568
569bool FJSONReader::IsNewLine(const TCHAR& Char)
570{
571 return Char == '\n';
572}
573
574bool FJSONReader::IsSpace(const TCHAR& Char)
575{
576 return IsNewLine(Char) || Char == ' ' || Char == '\t' || Char == '\r';
577}
578
579bool FJSONReader::FindToken(const TCHAR& Char)
580{
581 if (State.bEscape)
582 {
583 return false;
584 }
585
587 {
588 switch (Char)
589 {
590 case '{': State.Tokens.Add(EJSONToken::CURLY_BEGIN); return true;
591 case '}': State.Tokens.Add(EJSONToken::CURLY_END); return true;
592 case '[': State.Tokens.Add(EJSONToken::SQUARE_BEGIN); return true;
593 case ']': State.Tokens.Add(EJSONToken::SQUARE_END); return true;
594 case ',': State.Tokens.Add(EJSONToken::COMMA); return true;
595 case ':': State.Tokens.Add(EJSONToken::COLON); return true;
596 }
597 }
598 return false;
599}
600
602{
603 switch (State.GetToken())
604 {
605 case EJSONToken::ROOT:
606 {
607 return;
608 }
610 {
612 {
614 auto Value = State.GetArray();
615 if (Value != nullptr)
616 {
617 Value->AsNonConstArray().Add(State.PushObject());
618 }
619 else
620 {
621 State.Error();
622 }
623 }
625 {
626 if (State.Key.Len() > 0)
627 {
629 const auto Value = State.GetObject();
630 if (Value != nullptr)
631 {
632 Value->AsObject()->SetField(State.Key, State.PushObject());
633 State.ClearKey();
634 }
635 else
636 {
637 State.Error();
638 }
639 }
640 else
641 {
642 State.Error();
643 }
644 }
645 else if (State.CheckTokens(EJSONToken::ROOT, EJSONToken::CURLY_BEGIN)) // Root object "{"
646 {
647 if (State.Root.IsValid())
648 {
649 State.Error();
650 }
651 else
652 {
653 State.Root = TSharedPtr<FJsonObject>(new FJsonObject());
654 State.PushObject(State.Root); // add root object
656 }
657 }
658 else
659 {
660 State.Error();
661 }
662 break;
663 }
665 {
667 {
668 State.PopToken(2); // pop "{}"
669 State.PopObject(); // remove object
670 }
672 {
673 State.PopToken(3); // pop "{:}"
674 State.PopValue(); // remove value
675 State.PopObject(); // remove object
676 }
677 else
678 {
679 State.Error();
680 }
681
682 if (State.CheckTokens(EJSONToken::COLON)) // Object in object ":"
683 {
684 State.PopToken(1); // pop ":"
685 }
686
688
689 break;
690 }
692 {
694 {
696 auto Value = State.GetArray();
697 if (Value != nullptr)
698 {
699 Value->AsNonConstArray().Add(State.PushArray());
700 }
701 else
702 {
703 State.Error();
704 }
705 }
707 {
709 if (State.Key.Len() > 0)
710 {
711 const auto Value = State.GetObject();
712 if (Value != nullptr)
713 {
714 Value->AsObject()->SetField(State.Key, State.PushArray());
715 State.ClearKey();
716 }
717 else
718 {
719 State.Error();
720 }
721 }
722 else
723 {
724 State.Error();
725 }
726 }
727 else if (State.CheckTokens(EJSONToken::ROOT, EJSONToken::SQUARE_BEGIN)) // Root array "{"
728 {
729 State.Error(); // Not support
730 }
731 else
732 {
733 State.Error();
734 }
735 break;
736 }
738 {
740 {
741 State.PopToken(2); // remove token "[]"
742 State.PopValue(false); // remove value if exists
743 State.PopArray(); // remove array
744
745 if (State.CheckTokens(EJSONToken::COLON)) // Array in object ":"
746 {
747 State.PopToken(1); // pop ":"
748 }
749 }
750 else
751 {
752 State.Error();
753 }
754
756
757 break;
758 }
760 {
762 {
763 State.PopToken(2); // remove token ":,"
764 State.PopValue(false); // remove value
766 }
767 else if (State.CheckTokens(EJSONToken::CURLY_BEGIN, EJSONToken::COMMA)) // Next record in object "{,"
768 {
769 State.PopToken(1); // remove token ","
771 }
772 else if (State.CheckTokens(EJSONToken::SQUARE_BEGIN, EJSONToken::COMMA)) // Next record in array "[,"
773 {
774 State.PopToken(1); // remove token ","
775 State.PopValue(false); // remove value
777 }
778 else
779 {
780 State.Error();
781 }
782 break;
783 }
785 {
786 if (State.CheckTokens(EJSONToken::CURLY_BEGIN, EJSONToken::COLON)) // Object key close "{:"
787 {
789 if (State.Data.Len() > 0)
790 {
792 }
793 else
794 {
795 State.Error();
796 }
797 }
798 else
799 {
800 State.Error();
801 }
802 break;
803 }
805 {
806 State.Error();
807 break;
808 }
809 }
810
812 {
814 }
815}
816
817void FJSONReader::ReadAsString(const TCHAR& Char)
818{
819 if (IsNewLine(Char))
820 {
821 State.Error();
822 return;
823 }
824
825 if (!State.bEscape && State.Quote == Char)
826 {
827 State.Quote = UNICODE_BOGUS_CHAR_CODEPOINT;
829 }
830 else
831 {
832 if (State.bEscape)
833 {
834 switch (Char)
835 {
836 case 'n': State.Data.AppendChar('\n'); break;
837 case 't': State.Data.AppendChar('\t'); break;
838 default: State.Data.AppendChar(Char); break;
839 }
840 }
841 else
842 {
843 State.Data.AppendChar(Char);
844 }
845 }
846}
847
848void FJSONReader::ReadAsStringSpecial(const TCHAR& Char)
849{
850 if (IsSpace(Char) && State.Data.Len() > 0)
851 {
853 return;
854 }
855
856 State.Data.AppendChar(Char);
857}
858
859void FJSONReader::ReadAsNumber(const TCHAR& Char)
860{
861 if (IsSpace(Char) && State.Data.Len() > 0)
862 {
864 return;
865 }
866
867 if ((Char >= '0' && Char <= '9') || Char == '-' || Char == '.' || Char == '+' || Char == 'e' || Char == 'E')
868 {
869 State.Data.AppendChar(Char);
870 }
871 else
872 {
873 State.Error();
874 }
875}
876
877void FJSONReader::ReadBasicValue(const TCHAR& Char)
878{
879 switch (Char)
880 {
881 case 'T':
882 case 't':
883 case 'F':
884 case 'f':
885 {
889 return;
890 }
891 case 'N':
892 case 'n':
893 {
894 State.PushNull();
897 return;
898 }
899 case '\'':
900 case '"':
901 {
904 State.Quote = Char;
905 return;
906 }
907 }
908
909 if ((Char >= '0' && Char <= '9') || Char == '-')
910 {
913 ReadAsNumber(Char);
914 return;
915 }
916}
917
918void FJSONReader::ReadAsArray(const TCHAR& Char)
919{
920 if (IsSpace(Char))
921 {
922 return;
923 }
924 ReadBasicValue(Char);
925}
926
927void FJSONReader::ReadAsObject(const TCHAR& Char)
928{
929 if (IsSpace(Char))
930 {
931 return;
932 }
933
934 if (State.CheckTokens(EJSONToken::CURLY_BEGIN)) // read key "{"
935 {
936 if (Char == '\'' || Char == '"')
937 {
939 State.Quote = Char;
940 }
941 else
942 {
945 }
946 }
947 else if (State.CheckTokens(EJSONToken::CURLY_BEGIN, EJSONToken::COLON)) // read value "{:"
948 {
949 ReadBasicValue(Char);
950 }
951}
952
953void FJSONReader::Skip(const TCHAR& Char)
954{
955 if (!IsSpace(Char))
956 {
957 State.Error();
958 }
959}
960
961bool FJSONReader::Read(const TCHAR Char)
962{
963 if (Char == '\\' && !State.bEscape)
964 {
965 State.bEscape = true;
966 return true;
967 }
968
969 if (FindToken(Char))
970 {
973 return true;
974 }
975
976 switch (State.Notation)
977 {
978 case EJSONNotation::NONE: UpdateNotation(); break;
979
980 case EJSONNotation::STRING: ReadAsString(Char); break;
982 case EJSONNotation::NUMBER: ReadAsNumber(Char); break;
983 case EJSONNotation::ARRAY: ReadAsArray(Char); break;
984 case EJSONNotation::OBJECT: ReadAsObject(Char); break;
985
986 case EJSONNotation::SKIP: Skip(Char); break;
987 }
988
989 if (State.bError)
990 {
991 State.Root = TSharedPtr<FJsonObject>(nullptr);
992 State.Size = 0;
993 return false;
994 }
995
996 State.bEscape = false;
997
998 return true;
999}
1000
1004
1005bool FJSONWriter::GetStartChar(const TSharedPtr<FJsonValue>& JsonValue, FString& Str)
1006{
1007 switch (JsonValue->Type)
1008 {
1009 case EJson::Object:
1010 Str = FString(TEXT("{"));
1011 break;
1012 case EJson::Array:
1013 Str = FString(TEXT("["));
1014 break;
1015 case EJson::String:
1016 Str = FString(TEXT("\""));
1017 break;
1018 default:
1019 return false;
1020 break;
1021 }
1022
1023 return true;
1024}
1025
1026bool FJSONWriter::GetEndChar(const TSharedPtr<FJsonValue>& JsonValue, FString& Str)
1027{
1028 switch (JsonValue->Type)
1029 {
1030 case EJson::Object:
1031 Str = FString(TEXT("}"));
1032 break;
1033 case EJson::Array:
1034 Str = FString(TEXT("]"));
1035 break;
1036 case EJson::String:
1037 Str = FString(TEXT("\""));
1038 break;
1039 default:
1040 return false;
1041 break;
1042 }
1043
1044 return true;
1045}
1046
1047void FJSONWriter::Write(TSharedPtr<FJsonValue> JsonValue, FArchive* Writer, bool IsLastElement)
1048{
1049 FString Str;
1050 FArchive& Ar = *Writer;
1051
1052 if (GetStartChar(JsonValue, Str))
1053 {
1054 UVaRestJsonObject::WriteStringToArchive(Ar, *Str, Str.Len());
1055 }
1056
1057 switch (JsonValue->Type)
1058 {
1059 case EJson::Object:
1060 {
1061 int ElementsCount = 0;
1062 auto Values = JsonValue->AsObject()->Values;
1063
1064 for (auto& ChildJsonPair : Values)
1065 {
1066 Str = FString(TEXT("\""));
1067 UVaRestJsonObject::WriteStringToArchive(Ar, *Str, Str.Len());
1068
1069 const TCHAR* BufferPtr = *ChildJsonPair.Key;
1070 for (int i = 0; i < ChildJsonPair.Key.Len(); ++i)
1071 {
1072 Str = FString(1, &ChildJsonPair.Key[i]);
1073 UVaRestJsonObject::WriteStringToArchive(Ar, *Str, Str.Len());
1074 }
1075
1076 Str = FString(TEXT("\""));
1077 UVaRestJsonObject::WriteStringToArchive(Ar, *Str, Str.Len());
1078
1079 Str = FString(TEXT(":"));
1080 UVaRestJsonObject::WriteStringToArchive(Ar, *Str, Str.Len());
1081
1082 ++ElementsCount;
1083
1084 Write(ChildJsonPair.Value, Writer, ElementsCount >= Values.Num());
1085 }
1086 break;
1087 }
1088 case EJson::Array:
1089 {
1090 int ElementsCount = 0;
1091 auto Array = JsonValue->AsArray();
1092
1093 for (auto& ChildJsonValue : Array)
1094 {
1095 ++ElementsCount;
1096 Write(ChildJsonValue, Writer, ElementsCount >= Array.Num());
1097 }
1098 break;
1099 }
1100 default:
1101 {
1102 const FString Value = JsonValue->AsString();
1103
1104 const TCHAR* BufferPtr = *Value;
1105 for (int i = 0; i < Value.Len(); ++i)
1106 {
1107 Str = FString(1, &BufferPtr[i]);
1108 if (Str == TEXT("\""))
1109 {
1110 Str = FString(TEXT("\\"));
1111 UVaRestJsonObject::WriteStringToArchive(Ar, *Str, Str.Len());
1112 Str = FString(1, &BufferPtr[i]);
1113 }
1114 if (Str == TEXT("\n"))
1115 {
1116 Str = FString(TEXT("\\"));
1117 UVaRestJsonObject::WriteStringToArchive(Ar, *Str, Str.Len());
1118 Str = FString(TEXT("n"));
1119 UVaRestJsonObject::WriteStringToArchive(Ar, *Str, Str.Len());
1120 Str = FString(1, &BufferPtr[i]);
1121 }
1122 else if (Str == TEXT("\t"))
1123 {
1124 Str = FString(TEXT("\\"));
1125 UVaRestJsonObject::WriteStringToArchive(Ar, *Str, Str.Len());
1126 Str = FString(TEXT("t"));
1127 UVaRestJsonObject::WriteStringToArchive(Ar, *Str, Str.Len());
1128 Str = FString(1, &BufferPtr[i]);
1129 }
1130 else
1131 {
1132 UVaRestJsonObject::WriteStringToArchive(Ar, *Str, Str.Len());
1133 }
1134 }
1135
1136 break;
1137 }
1138 }
1139
1140 if (GetEndChar(JsonValue, Str))
1141 {
1142 UVaRestJsonObject::WriteStringToArchive(Ar, *Str, Str.Len());
1143 }
1144
1145 if (!IsLastElement)
1146 {
1147 Str = FString(TEXT(","));
1148 UVaRestJsonObject::WriteStringToArchive(Ar, *Str, Str.Len());
1149 }
1150}
EJSONToken
EJSONNotation
TArray< TSharedPtr< FJsonValue > > & AsNonConstArray()
static bool WriteStringToArchive(FArchive &Ar, const TCHAR *StrPtr, int64 Len)
FORCEINLINE bool IsNewLine(const TCHAR &Char)
FORCEINLINE void Skip(const TCHAR &Char)
FORCEINLINE void UpdateNotation()
bool Read(const TCHAR Char)
FORCEINLINE void ReadAsArray(const TCHAR &Char)
FJSONState State
FORCEINLINE void ReadBasicValue(const TCHAR &Char)
FORCEINLINE bool FindToken(const TCHAR &Char)
FORCEINLINE void ReadAsObject(const TCHAR &Char)
FORCEINLINE void ReadAsStringSpecial(const TCHAR &Char)
FORCEINLINE bool IsSpace(const TCHAR &Char)
FORCEINLINE void ReadAsNumber(const TCHAR &Char)
FORCEINLINE void ReadAsString(const TCHAR &Char)
FORCEINLINE void Error()
TSharedPtr< FJsonObject > Root
FORCEINLINE void PopValue(bool bCheckType=true)
FORCEINLINE TSharedPtr< FJsonValueNonConstBoolean > PushBoolean()
FORCEINLINE void PopToken(int32 Num)
FORCEINLINE TSharedPtr< FJsonValueObject > PushObject()
FORCEINLINE FJsonValueObject * GetObject()
FORCEINLINE TSharedPtr< FJsonValueNonConstString > PushString()
EJSONToken GetToken(int32 Index=0)
FORCEINLINE void PopArray()
TArray< TSharedPtr< FJsonValue > > Objects
FORCEINLINE FJsonValueNonConstArray * GetArray()
FORCEINLINE TSharedPtr< FJsonValueNonConstArray > PushArray()
EJSONNotation Notation
FORCEINLINE bool CheckTokens(EJSONToken T1)
FORCEINLINE void ClearData()
FORCEINLINE FJsonValue * GetLast()
FORCEINLINE void DataToKey()
FORCEINLINE void ClearKey()
FORCEINLINE void PopObject()
FORCEINLINE TSharedPtr< FJsonValueNull > PushNull()
TArray< EJSONToken > Tokens
FORCEINLINE TSharedPtr< FJsonValueNonConstNumber > PushNumber()
FORCEINLINE bool GetStartChar(const TSharedPtr< FJsonValue > &JsonValue, FString &Char)
void Write(TSharedPtr< FJsonValue > JsonValue, FArchive *Writer, bool IsLastElement)
FORCEINLINE bool GetEndChar(const TSharedPtr< FJsonValue > &JsonValue, FString &Char)
static uint32 CodepointFromUtf8(const ANSICHAR *&SourceString, const uint32 SourceLengthRemaining)