2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
22 unit Thrift.Protocol.JSON;
37 IJSONProtocol = interface( IProtocol)
38 ['{F0DAFDBD-692A-4B71-9736-F5D485A2178F}']
39 // Read a byte that must match b; otherwise an exception is thrown.
40 procedure ReadJSONSyntaxChar( b : Byte);
43 // JSON protocol implementation for thrift.
44 // This is a full-featured protocol supporting Write and Read.
45 // Please see the C++ class header for a detailed description of the protocol's wire format.
46 // Adapted from the C# version.
47 TJSONProtocolImpl = class( TProtocolImpl, IJSONProtocol)
50 TFactory = class( TInterfacedObject, IProtocolFactory)
52 function GetProtocol( const trans: ITransport): IProtocol;
56 class function GetTypeNameForTypeID(typeID : TType) : string;
57 class function GetTypeIDForTypeName( const name : string) : TType;
61 // Base class for tracking JSON contexts that may require
62 // inserting/Reading additional JSON syntax characters.
63 // This base context does nothing.
64 TJSONBaseContext = class
66 FProto : Pointer; // weak IJSONProtocol;
68 constructor Create( const aProto : IJSONProtocol);
69 procedure Write; virtual;
70 procedure Read; virtual;
71 function EscapeNumbers : Boolean; virtual;
74 // Context for JSON lists.
75 // Will insert/Read commas before each item except for the first one.
76 TJSONListContext = class( TJSONBaseContext)
80 constructor Create( const aProto : IJSONProtocol);
81 procedure Write; override;
82 procedure Read; override;
85 // Context for JSON records. Will insert/Read colons before the value portion of each record
86 // pair, and commas before each key except the first. In addition, will indicate that numbers
87 // in the key position need to be escaped in quotes (since JSON keys must be strings).
88 TJSONPairContext = class( TJSONBaseContext)
90 FFirst, FColon : Boolean;
92 constructor Create( const aProto : IJSONProtocol);
93 procedure Write; override;
94 procedure Read; override;
95 function EscapeNumbers : Boolean; override;
98 // Holds up to one byte from the transport
99 TLookaheadReader = class
101 FProto : Pointer; // weak IJSONProtocol;
102 constructor Create( const aProto : IJSONProtocol);
109 // Return and consume the next byte to be Read, either taking it from the
110 // data buffer if present or getting it from the transport otherwise.
111 function Read : Byte;
113 // Return the next byte to be Read without consuming, filling the data
114 // buffer if it has not been filled alReady.
115 function Peek : Byte;
119 // Stack of nested contexts that we may be in
120 FContextStack : TStack<TJSONBaseContext>;
122 // Current context that we are in
123 FContext : TJSONBaseContext;
125 // Reader that manages a 1-byte buffer
126 FReader : TLookaheadReader;
128 // Push/pop a new JSON context onto/from the stack.
129 procedure ResetContextStack;
130 procedure PushContext( const aCtx : TJSONBaseContext);
131 procedure PopContext;
134 // TJSONProtocolImpl Constructor
135 constructor Create( const aTrans : ITransport);
136 destructor Destroy; override;
140 // Read a byte that must match b; otherwise an exception is thrown.
141 procedure ReadJSONSyntaxChar( b : Byte);
144 // Convert a byte containing a hex char ('0'-'9' or 'a'-'f') into its corresponding hex value
145 class function HexVal( ch : Byte) : Byte;
147 // Convert a byte containing a hex value to its corresponding hex character
148 class function HexChar( val : Byte) : Byte;
150 // Write the bytes in array buf as a JSON characters, escaping as needed
151 procedure WriteJSONString( const b : TBytes); overload;
152 procedure WriteJSONString( const str : string); overload;
154 // Write out number as a JSON value. If the context dictates so, it will be
155 // wrapped in quotes to output as a JSON string.
156 procedure WriteJSONInteger( const num : Int64);
158 // Write out a double as a JSON value. If it is NaN or infinity or if the
159 // context dictates escaping, Write out as JSON string.
160 procedure WriteJSONDouble( const num : Double);
162 // Write out contents of byte array b as a JSON string with base-64 encoded data
163 procedure WriteJSONBase64( const b : TBytes);
165 procedure WriteJSONObjectStart;
166 procedure WriteJSONObjectEnd;
167 procedure WriteJSONArrayStart;
168 procedure WriteJSONArrayEnd;
172 procedure WriteMessageBegin( const aMsg : TThriftMessage); override;
173 procedure WriteMessageEnd; override;
174 procedure WriteStructBegin( const struc: TThriftStruct); override;
175 procedure WriteStructEnd; override;
176 procedure WriteFieldBegin( const field: TThriftField); override;
177 procedure WriteFieldEnd; override;
178 procedure WriteFieldStop; override;
179 procedure WriteMapBegin( const map: TThriftMap); override;
180 procedure WriteMapEnd; override;
181 procedure WriteListBegin( const list: TThriftList); override;
182 procedure WriteListEnd(); override;
183 procedure WriteSetBegin( const set_: TThriftSet ); override;
184 procedure WriteSetEnd(); override;
185 procedure WriteBool( b: Boolean); override;
186 procedure WriteByte( b: ShortInt); override;
187 procedure WriteI16( i16: SmallInt); override;
188 procedure WriteI32( i32: Integer); override;
189 procedure WriteI64( const i64: Int64); override;
190 procedure WriteDouble( const d: Double); override;
191 procedure WriteString( const s: string ); override;
192 procedure WriteBinary( const b: TBytes); override;
194 function ReadMessageBegin: TThriftMessage; override;
195 procedure ReadMessageEnd(); override;
196 function ReadStructBegin: TThriftStruct; override;
197 procedure ReadStructEnd; override;
198 function ReadFieldBegin: TThriftField; override;
199 procedure ReadFieldEnd(); override;
200 function ReadMapBegin: TThriftMap; override;
201 procedure ReadMapEnd(); override;
202 function ReadListBegin: TThriftList; override;
203 procedure ReadListEnd(); override;
204 function ReadSetBegin: TThriftSet; override;
205 procedure ReadSetEnd(); override;
206 function ReadBool: Boolean; override;
207 function ReadByte: ShortInt; override;
208 function ReadI16: SmallInt; override;
209 function ReadI32: Integer; override;
210 function ReadI64: Int64; override;
211 function ReadDouble:Double; override;
212 function ReadString : string; override;
213 function ReadBinary: TBytes; override;
219 // Read in a JSON string, unescaping as appropriate.
220 // Skip Reading from the context if skipContext is true.
221 function ReadJSONString( skipContext : Boolean) : TBytes;
223 // Return true if the given byte could be a valid part of a JSON number.
224 function IsJSONNumeric( b : Byte) : Boolean;
226 // Read in a sequence of characters that are all valid in JSON numbers. Does
227 // not do a complete regex check to validate that this is actually a number.
228 function ReadJSONNumericChars : String;
230 // Read in a JSON number. If the context dictates, Read in enclosing quotes.
231 function ReadJSONInteger : Int64;
233 // Read in a JSON double value. Throw if the value is not wrapped in quotes
234 // when expected or if wrapped in quotes when not expected.
235 function ReadJSONDouble : Double;
237 // Read in a JSON string containing base-64 encoded data and decode it.
238 function ReadJSONBase64 : TBytes;
240 procedure ReadJSONObjectStart;
241 procedure ReadJSONObjectEnd;
242 procedure ReadJSONArrayStart;
243 procedure ReadJSONArrayEnd;
262 JSON_CHAR_TABLE : array[0..$2F] of Byte
263 = (0,0,0,0, 0,0,0,0, Byte('b'),Byte('t'),Byte('n'),0, Byte('f'),Byte('r'),0,0,
264 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
265 1,1,Byte('"'),1, 1,1,1,1, 1,1,1,1, 1,1,1,1);
267 ESCAPE_CHARS = '"\/btnfr';
268 ESCAPE_CHAR_VALS = '"\/'#8#9#10#12#13;
270 DEF_STRING_SIZE = 16;
284 INVARIANT_CULTURE : TFormatSettings
285 = ( ThousandSeparator: ',';
286 DecimalSeparator: '.');
290 //--- TJSONProtocolImpl ----------------------
293 function TJSONProtocolImpl.TFactory.GetProtocol( const trans: ITransport): IProtocol;
295 result := TJSONProtocolImpl.Create(trans);
298 class function TJSONProtocolImpl.GetTypeNameForTypeID(typeID : TType) : string;
301 TType.Bool_: result := NAME_BOOL;
302 TType.Byte_: result := NAME_BYTE;
303 TType.I16: result := NAME_I16;
304 TType.I32: result := NAME_I32;
305 TType.I64: result := NAME_I64;
306 TType.Double_: result := NAME_DOUBLE;
307 TType.String_: result := NAME_STRING;
308 TType.Struct: result := NAME_STRUCT;
309 TType.Map: result := NAME_MAP;
310 TType.Set_: result := NAME_SET;
311 TType.List: result := NAME_LIST;
313 raise TProtocolExceptionNotImplemented.Create('Unrecognized type ('+IntToStr(Ord(typeID))+')');
318 class function TJSONProtocolImpl.GetTypeIDForTypeName( const name : string) : TType;
320 if name = NAME_BOOL then result := TType.Bool_
321 else if name = NAME_BYTE then result := TType.Byte_
322 else if name = NAME_I16 then result := TType.I16
323 else if name = NAME_I32 then result := TType.I32
324 else if name = NAME_I64 then result := TType.I64
325 else if name = NAME_DOUBLE then result := TType.Double_
326 else if name = NAME_STRUCT then result := TType.Struct
327 else if name = NAME_STRING then result := TType.String_
328 else if name = NAME_MAP then result := TType.Map
329 else if name = NAME_LIST then result := TType.List
330 else if name = NAME_SET then result := TType.Set_
331 else raise TProtocolExceptionNotImplemented.Create('Unrecognized type ('+name+')');
335 constructor TJSONProtocolImpl.TJSONBaseContext.Create( const aProto : IJSONProtocol);
338 FProto := Pointer(aProto);
342 procedure TJSONProtocolImpl.TJSONBaseContext.Write;
348 procedure TJSONProtocolImpl.TJSONBaseContext.Read;
354 function TJSONProtocolImpl.TJSONBaseContext.EscapeNumbers : Boolean;
360 constructor TJSONProtocolImpl.TJSONListContext.Create( const aProto : IJSONProtocol);
362 inherited Create( aProto);
367 procedure TJSONProtocolImpl.TJSONListContext.Write;
371 else IJSONProtocol(FProto).Transport.Write( COMMA);
375 procedure TJSONProtocolImpl.TJSONListContext.Read;
379 else IJSONProtocol(FProto).ReadJSONSyntaxChar( COMMA[0]);
383 constructor TJSONProtocolImpl.TJSONPairContext.Create( const aProto : IJSONProtocol);
385 inherited Create( aProto);
391 procedure TJSONProtocolImpl.TJSONPairContext.Write;
399 then IJSONProtocol(FProto).Transport.Write( COLON)
400 else IJSONProtocol(FProto).Transport.Write( COMMA);
401 FColon := not FColon;
406 procedure TJSONProtocolImpl.TJSONPairContext.Read;
414 then IJSONProtocol(FProto).ReadJSONSyntaxChar( COLON[0])
415 else IJSONProtocol(FProto).ReadJSONSyntaxChar( COMMA[0]);
416 FColon := not FColon;
421 function TJSONProtocolImpl.TJSONPairContext.EscapeNumbers : Boolean;
427 constructor TJSONProtocolImpl.TLookaheadReader.Create( const aProto : IJSONProtocol);
430 FProto := Pointer(aProto);
435 function TJSONProtocolImpl.TLookaheadReader.Read : Byte;
438 then FHasData := FALSE
440 IJSONProtocol(FProto).Transport.ReadAll( @FData, SizeOf(FData), 0, 1);
446 function TJSONProtocolImpl.TLookaheadReader.Peek : Byte;
448 if not FHasData then begin
449 IJSONProtocol(FProto).Transport.ReadAll( @FData, SizeOf(FData), 0, 1);
456 constructor TJSONProtocolImpl.Create( const aTrans : ITransport);
458 inherited Create( aTrans);
460 // Stack of nested contexts that we may be in
461 FContextStack := TStack<TJSONBaseContext>.Create;
463 FContext := TJSONBaseContext.Create( Self);
464 FReader := TLookaheadReader.Create( Self);
468 destructor TJSONProtocolImpl.Destroy;
471 ResetContextStack; // free any contents
472 FreeAndNil( FReader);
473 FreeAndNil( FContext);
474 FreeAndNil( FContextStack);
481 procedure TJSONProtocolImpl.ResetContextStack;
483 while FContextStack.Count > 0
488 procedure TJSONProtocolImpl.PushContext( const aCtx : TJSONBaseContext);
490 FContextStack.Push( FContext);
495 procedure TJSONProtocolImpl.PopContext;
497 FreeAndNil(FContext);
498 FContext := FContextStack.Pop;
502 procedure TJSONProtocolImpl.ReadJSONSyntaxChar( b : Byte);
507 then raise TProtocolExceptionInvalidData.Create('Unexpected character ('+Char(ch)+')');
511 class function TJSONProtocolImpl.HexVal( ch : Byte) : Byte;
514 i := StrToIntDef( '$0'+Char(ch), -1);
515 if (0 <= i) and (i < $10)
517 else raise TProtocolExceptionInvalidData.Create('Expected hex character ('+Char(ch)+')');
521 class function TJSONProtocolImpl.HexChar( val : Byte) : Byte;
522 const HEXCHARS = '0123456789ABCDEF';
524 result := Byte( PChar(HEXCHARS)[val and $0F]);
525 ASSERT( Pos( Char(result), HEXCHARS) > 0);
529 procedure TJSONProtocolImpl.WriteJSONString( const str : string);
531 WriteJSONString( SysUtils.TEncoding.UTF8.GetBytes( str));
535 procedure TJSONProtocolImpl.WriteJSONString( const b : TBytes);
540 Transport.Write( QUOTE);
541 for i := 0 to Length(b)-1 do begin
543 if (b[i] and $00FF) >= $30 then begin
545 if (b[i] = BACKSLASH[0]) then begin
546 Transport.Write( BACKSLASH);
547 Transport.Write( BACKSLASH);
550 Transport.Write( b, i, 1);
556 tmp[0] := JSON_CHAR_TABLE[b[i]];
557 if (tmp[0] = 1) then begin
558 Transport.Write( b, i, 1)
560 else if (tmp[0] > 1) then begin
561 Transport.Write( BACKSLASH);
562 Transport.Write( tmp, 0, 1);
565 Transport.Write( ESCSEQ);
566 tmp[0] := HexChar( b[i] div $10);
567 tmp[1] := HexChar( b[i]);
568 Transport.Write( tmp, 0, 2);
572 Transport.Write( QUOTE);
576 procedure TJSONProtocolImpl.WriteJSONInteger( const num : Int64);
581 str := IntToStr(num);
583 escapeNum := FContext.EscapeNumbers;
585 then Transport.Write( QUOTE);
587 Transport.Write( SysUtils.TEncoding.UTF8.GetBytes( str));
590 then Transport.Write( QUOTE);
594 procedure TJSONProtocolImpl.WriteJSONDouble( const num : Double);
601 str := FloatToStr( num, INVARIANT_CULTURE);
604 case UpCase(str[1]) of
605 'N' : special := TRUE; // NaN
606 'I' : special := TRUE; // Infinity
607 '-' : special := (UpCase(str[2]) = 'I'); // -Infinity
610 escapeNum := special or FContext.EscapeNumbers;
614 then Transport.Write( QUOTE);
616 Transport.Write( SysUtils.TEncoding.UTF8.GetBytes( str));
619 then Transport.Write( QUOTE);
623 procedure TJSONProtocolImpl.WriteJSONBase64( const b : TBytes);
624 var len, off, cnt : Integer;
628 Transport.Write( QUOTE);
632 SetLength( tmpBuf, 4);
634 while len >= 3 do begin
635 // Encode 3 bytes at a time
636 Base64Utils.Encode( b, off, 3, tmpBuf, 0);
637 Transport.Write( tmpBuf, 0, 4);
642 // Encode remainder, if any
643 if len > 0 then begin
644 cnt := Base64Utils.Encode( b, off, len, tmpBuf, 0);
645 Transport.Write( tmpBuf, 0, cnt);
648 Transport.Write( QUOTE);
652 procedure TJSONProtocolImpl.WriteJSONObjectStart;
655 Transport.Write( LBRACE);
656 PushContext( TJSONPairContext.Create( Self));
660 procedure TJSONProtocolImpl.WriteJSONObjectEnd;
663 Transport.Write( RBRACE);
667 procedure TJSONProtocolImpl.WriteJSONArrayStart;
670 Transport.Write( LBRACKET);
671 PushContext( TJSONListContext.Create( Self));
675 procedure TJSONProtocolImpl.WriteJSONArrayEnd;
678 Transport.Write( RBRACKET);
682 procedure TJSONProtocolImpl.WriteMessageBegin( const aMsg : TThriftMessage);
684 ResetContextStack; // THRIFT-1473
687 WriteJSONInteger(VERSION);
689 WriteJSONString( SysUtils.TEncoding.UTF8.GetBytes( aMsg.Name));
691 WriteJSONInteger( LongInt( aMsg.Type_));
692 WriteJSONInteger( aMsg.SeqID);
695 procedure TJSONProtocolImpl.WriteMessageEnd;
701 procedure TJSONProtocolImpl.WriteStructBegin( const struc: TThriftStruct);
703 WriteJSONObjectStart;
707 procedure TJSONProtocolImpl.WriteStructEnd;
713 procedure TJSONProtocolImpl.WriteFieldBegin( const field : TThriftField);
715 WriteJSONInteger(field.ID);
716 WriteJSONObjectStart;
717 WriteJSONString( GetTypeNameForTypeID(field.Type_));
721 procedure TJSONProtocolImpl.WriteFieldEnd;
727 procedure TJSONProtocolImpl.WriteFieldStop;
732 procedure TJSONProtocolImpl.WriteMapBegin( const map: TThriftMap);
735 WriteJSONString( GetTypeNameForTypeID( map.KeyType));
736 WriteJSONString( GetTypeNameForTypeID( map.ValueType));
737 WriteJSONInteger( map.Count);
738 WriteJSONObjectStart;
742 procedure TJSONProtocolImpl.WriteMapEnd;
749 procedure TJSONProtocolImpl.WriteListBegin( const list: TThriftList);
752 WriteJSONString( GetTypeNameForTypeID( list.ElementType));
753 WriteJSONInteger(list.Count);
757 procedure TJSONProtocolImpl.WriteListEnd;
763 procedure TJSONProtocolImpl.WriteSetBegin( const set_: TThriftSet);
766 WriteJSONString( GetTypeNameForTypeID( set_.ElementType));
767 WriteJSONInteger( set_.Count);
771 procedure TJSONProtocolImpl.WriteSetEnd;
776 procedure TJSONProtocolImpl.WriteBool( b: Boolean);
779 then WriteJSONInteger( 1)
780 else WriteJSONInteger( 0);
783 procedure TJSONProtocolImpl.WriteByte( b: ShortInt);
785 WriteJSONInteger( b);
788 procedure TJSONProtocolImpl.WriteI16( i16: SmallInt);
790 WriteJSONInteger( i16);
793 procedure TJSONProtocolImpl.WriteI32( i32: Integer);
795 WriteJSONInteger( i32);
798 procedure TJSONProtocolImpl.WriteI64( const i64: Int64);
800 WriteJSONInteger(i64);
803 procedure TJSONProtocolImpl.WriteDouble( const d: Double);
808 procedure TJSONProtocolImpl.WriteString( const s: string );
810 WriteJSONString( SysUtils.TEncoding.UTF8.GetBytes( s));
813 procedure TJSONProtocolImpl.WriteBinary( const b: TBytes);
819 function TJSONProtocolImpl.ReadJSONString( skipContext : Boolean) : TBytes;
820 var buffer : TMemoryStream;
824 surrogatePairs: Array[0..1] of Char;
829 buffer := TMemoryStream.Create;
834 ReadJSONSyntaxChar( QUOTE[0]);
843 if (ch <> ESCSEQ[0]) then begin
844 buffer.Write( ch, 1);
848 // distuinguish between \uNNNN and \?
852 off := Pos( Char(ch), ESCAPE_CHARS);
854 then raise TProtocolExceptionInvalidData.Create('Expected control char');
855 ch := Byte( ESCAPE_CHAR_VALS[off]);
856 buffer.Write( ch, 1);
862 Transport.ReadAll( tmp, 0, 4);
863 wch := (HexVal(tmp[0]) shl 12)
864 + (HexVal(tmp[1]) shl 8)
865 + (HexVal(tmp[2]) shl 4)
868 // we need to make UTF8 bytes from it, to be decoded later
869 if CharUtils.IsHighSurrogate(char(wch)) then begin
870 if highSurogate <> #0
871 then raise TProtocolExceptionInvalidData.Create('Expected low surrogate char');
872 highSurogate := char(wch);
874 else if CharUtils.IsLowSurrogate(char(wch)) then begin
876 then TProtocolExceptionInvalidData.Create('Expected high surrogate char');
877 surrogatePairs[0] := highSurogate;
878 surrogatePairs[1] := char(wch);
879 tmp := TEncoding.UTF8.GetBytes(surrogatePairs);
880 buffer.Write( tmp[0], Length(tmp));
884 tmp := SysUtils.TEncoding.UTF8.GetBytes(Char(wch));
885 buffer.Write( tmp[0], Length(tmp));
889 if highSurogate <> #0
890 then raise TProtocolExceptionInvalidData.Create('Expected low surrogate char');
892 SetLength( result, buffer.Size);
893 if buffer.Size > 0 then Move( buffer.Memory^, result[0], Length(result));
901 function TJSONProtocolImpl.IsJSONNumeric( b : Byte) : Boolean;
902 const NUMCHARS = ['+','-','.','0','1','2','3','4','5','6','7','8','9','E','e'];
904 result := CharInSet( Char(b), NUMCHARS);
908 function TJSONProtocolImpl.ReadJSONNumericChars : string;
909 var strbld : TThriftStringBuilder;
912 strbld := TThriftStringBuilder.Create;
917 then strbld.Append( Char(FReader.Read))
920 result := strbld.ToString;
928 function TJSONProtocolImpl.ReadJSONInteger : Int64;
932 if FContext.EscapeNumbers
933 then ReadJSONSyntaxChar( QUOTE[0]);
935 str := ReadJSONNumericChars;
937 if FContext.EscapeNumbers
938 then ReadJSONSyntaxChar( QUOTE[0]);
941 result := StrToInt64(str);
943 on e:Exception do begin
944 raise TProtocolExceptionInvalidData.Create('Bad data encounted in numeric data ('+str+') ('+e.Message+')');
950 function TJSONProtocolImpl.ReadJSONDouble : Double;
956 if FReader.Peek = QUOTE[0]
958 str := SysUtils.TEncoding.UTF8.GetString( ReadJSONString( TRUE));
959 dub := StrToFloat( str, INVARIANT_CULTURE);
961 if not FContext.EscapeNumbers()
962 and not Math.IsNaN(dub)
963 and not Math.IsInfinite(dub)
965 // Throw exception -- we should not be in a string in Self case
966 raise TProtocolExceptionInvalidData.Create('Numeric data unexpectedly quoted');
972 // will throw - we should have had a quote if escapeNum == true
973 if FContext.EscapeNumbers
974 then ReadJSONSyntaxChar( QUOTE[0]);
977 str := ReadJSONNumericChars;
978 result := StrToFloat( str, INVARIANT_CULTURE);
981 do raise TProtocolExceptionInvalidData.Create('Bad data encounted in numeric data ('+str+') ('+e.Message+')');
986 function TJSONProtocolImpl.ReadJSONBase64 : TBytes;
988 len, off, size : Integer;
990 b := ReadJSONString(false);
996 // reduce len to ignore fill bytes
998 while (len >= 0) and (b[len] = Byte('=')) do Dec(len);
1001 // read & decode full byte triplets = 4 source bytes
1002 while (len >= 4) do begin
1003 // Decode 4 bytes at a time
1004 Inc( size, Base64Utils.Decode( b, off, 4, b, size)); // decoded in place
1009 // Don't decode if we hit the end or got a single leftover byte (invalid
1010 // base64 but legal for skip of regular string type)
1011 if len > 1 then begin
1013 Inc( size, Base64Utils.Decode( b, off, len, b, size)); // decoded in place
1016 // resize to final size and return the data
1017 SetLength( b, size);
1022 procedure TJSONProtocolImpl.ReadJSONObjectStart;
1025 ReadJSONSyntaxChar( LBRACE[0]);
1026 PushContext( TJSONPairContext.Create( Self));
1030 procedure TJSONProtocolImpl.ReadJSONObjectEnd;
1032 ReadJSONSyntaxChar( RBRACE[0]);
1037 procedure TJSONProtocolImpl.ReadJSONArrayStart;
1040 ReadJSONSyntaxChar( LBRACKET[0]);
1041 PushContext( TJSONListContext.Create( Self));
1045 procedure TJSONProtocolImpl.ReadJSONArrayEnd;
1047 ReadJSONSyntaxChar( RBRACKET[0]);
1052 function TJSONProtocolImpl.ReadMessageBegin: TThriftMessage;
1054 ResetContextStack; // THRIFT-1473
1059 if ReadJSONInteger <> VERSION
1060 then raise TProtocolExceptionBadVersion.Create('Message contained bad version.');
1062 result.Name := SysUtils.TEncoding.UTF8.GetString( ReadJSONString( FALSE));
1063 result.Type_ := TMessageType( ReadJSONInteger);
1064 result.SeqID := ReadJSONInteger;
1068 procedure TJSONProtocolImpl.ReadMessageEnd;
1074 function TJSONProtocolImpl.ReadStructBegin : TThriftStruct ;
1076 ReadJSONObjectStart;
1081 procedure TJSONProtocolImpl.ReadStructEnd;
1087 function TJSONProtocolImpl.ReadFieldBegin : TThriftField;
1094 then result.Type_ := TType.Stop
1096 result.ID := ReadJSONInteger;
1097 ReadJSONObjectStart;
1099 str := SysUtils.TEncoding.UTF8.GetString( ReadJSONString( FALSE));
1100 result.Type_ := GetTypeIDForTypeName( str);
1105 procedure TJSONProtocolImpl.ReadFieldEnd;
1111 function TJSONProtocolImpl.ReadMapBegin : TThriftMap;
1117 str := SysUtils.TEncoding.UTF8.GetString( ReadJSONString(FALSE));
1118 result.KeyType := GetTypeIDForTypeName( str);
1120 str := SysUtils.TEncoding.UTF8.GetString( ReadJSONString(FALSE));
1121 result.ValueType := GetTypeIDForTypeName( str);
1123 result.Count := ReadJSONInteger;
1124 ReadJSONObjectStart;
1128 procedure TJSONProtocolImpl.ReadMapEnd;
1135 function TJSONProtocolImpl.ReadListBegin : TThriftList;
1141 str := SysUtils.TEncoding.UTF8.GetString( ReadJSONString(FALSE));
1142 result.ElementType := GetTypeIDForTypeName( str);
1143 result.Count := ReadJSONInteger;
1147 procedure TJSONProtocolImpl.ReadListEnd;
1153 function TJSONProtocolImpl.ReadSetBegin : TThriftSet;
1159 str := SysUtils.TEncoding.UTF8.GetString( ReadJSONString(FALSE));
1160 result.ElementType := GetTypeIDForTypeName( str);
1161 result.Count := ReadJSONInteger;
1165 procedure TJSONProtocolImpl.ReadSetEnd;
1171 function TJSONProtocolImpl.ReadBool : Boolean;
1173 result := (ReadJSONInteger <> 0);
1177 function TJSONProtocolImpl.ReadByte : ShortInt;
1179 result := ReadJSONInteger;
1183 function TJSONProtocolImpl.ReadI16 : SmallInt;
1185 result := ReadJSONInteger;
1189 function TJSONProtocolImpl.ReadI32 : LongInt;
1191 result := ReadJSONInteger;
1195 function TJSONProtocolImpl.ReadI64 : Int64;
1197 result := ReadJSONInteger;
1201 function TJSONProtocolImpl.ReadDouble : Double;
1203 result := ReadJSONDouble;
1207 function TJSONProtocolImpl.ReadString : string;
1209 result := SysUtils.TEncoding.UTF8.GetString( ReadJSONString( FALSE));
1213 function TJSONProtocolImpl.ReadBinary : TBytes;
1215 result := ReadJSONBase64;
1221 procedure InitBytes( var b : TBytes; aData : array of Byte);
1223 SetLength( b, Length(aData));
1224 Move( aData, b[0], Length(b));
1228 InitBytes( COMMA, [Byte(',')]);
1229 InitBytes( COLON, [Byte(':')]);
1230 InitBytes( LBRACE, [Byte('{')]);
1231 InitBytes( RBRACE, [Byte('}')]);
1232 InitBytes( LBRACKET, [Byte('[')]);
1233 InitBytes( RBRACKET, [Byte(']')]);
1234 InitBytes( QUOTE, [Byte('"')]);
1235 InitBytes( BACKSLASH, [Byte('\')]);
1236 InitBytes( ESCSEQ, [Byte('\'),Byte('u'),Byte('0'),Byte('0')]);