blob: 52909b778931045d167f099fd4227ee0f19fe00d [file] [log] [blame]
Jake Farrell27274222011-11-10 20:32:44 +00001(*
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
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
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
17 * under the License.
18 *)
19
20{$SCOPEDENUMS ON}
21
22unit Thrift.Protocol.JSON;
23
24interface
25
26uses
Phongphan Phutthaa6509f72015-10-31 01:09:47 +070027 Character,
Jake Farrell27274222011-11-10 20:32:44 +000028 Classes,
29 SysUtils,
30 Math,
Jake Farrell27274222011-11-10 20:32:44 +000031 Generics.Collections,
Jens Geyera019cda2019-11-09 23:24:52 +010032 Thrift.Configuration,
Jake Farrell27274222011-11-10 20:32:44 +000033 Thrift.Transport,
Jens Geyerd8bddbc2014-12-14 00:41:33 +010034 Thrift.Protocol,
Jens Geyerf726ae32021-06-04 11:17:26 +020035 Thrift.Stream,
Jens Geyerd8bddbc2014-12-14 00:41:33 +010036 Thrift.Utils;
Jake Farrell27274222011-11-10 20:32:44 +000037
38type
39 IJSONProtocol = interface( IProtocol)
40 ['{F0DAFDBD-692A-4B71-9736-F5D485A2178F}']
41 // Read a byte that must match b; otherwise an exception is thrown.
42 procedure ReadJSONSyntaxChar( b : Byte);
43 end;
44
45 // JSON protocol implementation for thrift.
46 // This is a full-featured protocol supporting Write and Read.
47 // Please see the C++ class header for a detailed description of the protocol's wire format.
48 // Adapted from the C# version.
49 TJSONProtocolImpl = class( TProtocolImpl, IJSONProtocol)
50 public
51 type
52 TFactory = class( TInterfacedObject, IProtocolFactory)
53 public
Roger Meier333bbf32012-01-08 21:51:08 +000054 function GetProtocol( const trans: ITransport): IProtocol;
Jake Farrell27274222011-11-10 20:32:44 +000055 end;
56
Jens Geyerfad7fd32019-11-09 23:24:52 +010057 strict private
Jake Farrell27274222011-11-10 20:32:44 +000058 class function GetTypeNameForTypeID(typeID : TType) : string;
59 class function GetTypeIDForTypeName( const name : string) : TType;
60
Jens Geyerfad7fd32019-11-09 23:24:52 +010061 strict protected
Jake Farrell27274222011-11-10 20:32:44 +000062 type
63 // Base class for tracking JSON contexts that may require
64 // inserting/Reading additional JSON syntax characters.
65 // This base context does nothing.
66 TJSONBaseContext = class
Jens Geyerfad7fd32019-11-09 23:24:52 +010067 strict protected
Roger Meierfebe8452012-06-06 10:32:24 +000068 FProto : Pointer; // weak IJSONProtocol;
Jake Farrell27274222011-11-10 20:32:44 +000069 public
70 constructor Create( const aProto : IJSONProtocol);
71 procedure Write; virtual;
72 procedure Read; virtual;
73 function EscapeNumbers : Boolean; virtual;
74 end;
75
76 // Context for JSON lists.
77 // Will insert/Read commas before each item except for the first one.
78 TJSONListContext = class( TJSONBaseContext)
Jens Geyerfad7fd32019-11-09 23:24:52 +010079 strict private
Jake Farrell27274222011-11-10 20:32:44 +000080 FFirst : Boolean;
81 public
82 constructor Create( const aProto : IJSONProtocol);
83 procedure Write; override;
84 procedure Read; override;
85 end;
86
87 // Context for JSON records. Will insert/Read colons before the value portion of each record
88 // pair, and commas before each key except the first. In addition, will indicate that numbers
89 // in the key position need to be escaped in quotes (since JSON keys must be strings).
90 TJSONPairContext = class( TJSONBaseContext)
Jens Geyerfad7fd32019-11-09 23:24:52 +010091 strict private
Jake Farrell27274222011-11-10 20:32:44 +000092 FFirst, FColon : Boolean;
93 public
94 constructor Create( const aProto : IJSONProtocol);
95 procedure Write; override;
96 procedure Read; override;
97 function EscapeNumbers : Boolean; override;
98 end;
99
100 // Holds up to one byte from the transport
101 TLookaheadReader = class
Jens Geyerfad7fd32019-11-09 23:24:52 +0100102 strict protected
Roger Meierfebe8452012-06-06 10:32:24 +0000103 FProto : Pointer; // weak IJSONProtocol;
Jens Geyerfad7fd32019-11-09 23:24:52 +0100104
105 protected
Jake Farrell27274222011-11-10 20:32:44 +0000106 constructor Create( const aProto : IJSONProtocol);
107
Jens Geyerfad7fd32019-11-09 23:24:52 +0100108 strict private
Jake Farrell27274222011-11-10 20:32:44 +0000109 FHasData : Boolean;
Jens Geyer17c3ad92017-09-05 20:31:27 +0200110 FData : Byte;
Jake Farrell27274222011-11-10 20:32:44 +0000111
112 public
113 // Return and consume the next byte to be Read, either taking it from the
114 // data buffer if present or getting it from the transport otherwise.
115 function Read : Byte;
116
117 // Return the next byte to be Read without consuming, filling the data
118 // buffer if it has not been filled alReady.
119 function Peek : Byte;
120 end;
121
Jens Geyerfad7fd32019-11-09 23:24:52 +0100122 strict protected
Jake Farrell27274222011-11-10 20:32:44 +0000123 // Stack of nested contexts that we may be in
124 FContextStack : TStack<TJSONBaseContext>;
125
126 // Current context that we are in
127 FContext : TJSONBaseContext;
128
129 // Reader that manages a 1-byte buffer
130 FReader : TLookaheadReader;
131
132 // Push/pop a new JSON context onto/from the stack.
Roger Meier45a37262012-01-08 21:44:44 +0000133 procedure ResetContextStack;
Roger Meier333bbf32012-01-08 21:51:08 +0000134 procedure PushContext( const aCtx : TJSONBaseContext);
Jake Farrell27274222011-11-10 20:32:44 +0000135 procedure PopContext;
136
Jens Geyer41f47af2019-11-09 23:24:52 +0100137 strict protected
138 function GetMinSerializedSize( const aType : TType) : Integer; override;
139 procedure Reset; override;
140
Jake Farrell27274222011-11-10 20:32:44 +0000141 public
142 // TJSONProtocolImpl Constructor
Jens Geyer3b686532021-07-01 23:04:08 +0200143 constructor Create( const aTrans : ITransport); override;
Jake Farrell27274222011-11-10 20:32:44 +0000144 destructor Destroy; override;
145
Jens Geyerfad7fd32019-11-09 23:24:52 +0100146 strict protected
Jake Farrell27274222011-11-10 20:32:44 +0000147 // IJSONProtocol
148 // Read a byte that must match b; otherwise an exception is thrown.
149 procedure ReadJSONSyntaxChar( b : Byte);
150
Jens Geyerfad7fd32019-11-09 23:24:52 +0100151 strict private
Jake Farrell27274222011-11-10 20:32:44 +0000152 // Convert a byte containing a hex char ('0'-'9' or 'a'-'f') into its corresponding hex value
153 class function HexVal( ch : Byte) : Byte;
154
155 // Convert a byte containing a hex value to its corresponding hex character
156 class function HexChar( val : Byte) : Byte;
157
158 // Write the bytes in array buf as a JSON characters, escaping as needed
159 procedure WriteJSONString( const b : TBytes); overload;
Roger Meier333bbf32012-01-08 21:51:08 +0000160 procedure WriteJSONString( const str : string); overload;
Jake Farrell27274222011-11-10 20:32:44 +0000161
162 // Write out number as a JSON value. If the context dictates so, it will be
163 // wrapped in quotes to output as a JSON string.
Roger Meier333bbf32012-01-08 21:51:08 +0000164 procedure WriteJSONInteger( const num : Int64);
Jake Farrell27274222011-11-10 20:32:44 +0000165
166 // Write out a double as a JSON value. If it is NaN or infinity or if the
167 // context dictates escaping, Write out as JSON string.
168 procedure WriteJSONDouble( const num : Double);
169
170 // Write out contents of byte array b as a JSON string with base-64 encoded data
171 procedure WriteJSONBase64( const b : TBytes);
172
173 procedure WriteJSONObjectStart;
174 procedure WriteJSONObjectEnd;
175 procedure WriteJSONArrayStart;
176 procedure WriteJSONArrayEnd;
177
178 public
179 // IProtocol
Jens Geyer17c3ad92017-09-05 20:31:27 +0200180 procedure WriteMessageBegin( const aMsg : TThriftMessage); override;
Jake Farrell27274222011-11-10 20:32:44 +0000181 procedure WriteMessageEnd; override;
Jens Geyer17c3ad92017-09-05 20:31:27 +0200182 procedure WriteStructBegin( const struc: TThriftStruct); override;
Jake Farrell27274222011-11-10 20:32:44 +0000183 procedure WriteStructEnd; override;
Jens Geyer17c3ad92017-09-05 20:31:27 +0200184 procedure WriteFieldBegin( const field: TThriftField); override;
Jake Farrell27274222011-11-10 20:32:44 +0000185 procedure WriteFieldEnd; override;
186 procedure WriteFieldStop; override;
Jens Geyer17c3ad92017-09-05 20:31:27 +0200187 procedure WriteMapBegin( const map: TThriftMap); override;
Jake Farrell27274222011-11-10 20:32:44 +0000188 procedure WriteMapEnd; override;
Jens Geyer17c3ad92017-09-05 20:31:27 +0200189 procedure WriteListBegin( const list: TThriftList); override;
Jake Farrell27274222011-11-10 20:32:44 +0000190 procedure WriteListEnd(); override;
Jens Geyer17c3ad92017-09-05 20:31:27 +0200191 procedure WriteSetBegin( const set_: TThriftSet ); override;
Jake Farrell27274222011-11-10 20:32:44 +0000192 procedure WriteSetEnd(); override;
193 procedure WriteBool( b: Boolean); override;
194 procedure WriteByte( b: ShortInt); override;
195 procedure WriteI16( i16: SmallInt); override;
196 procedure WriteI32( i32: Integer); override;
Roger Meier333bbf32012-01-08 21:51:08 +0000197 procedure WriteI64( const i64: Int64); override;
198 procedure WriteDouble( const d: Double); override;
Jake Farrell27274222011-11-10 20:32:44 +0000199 procedure WriteString( const s: string ); override;
200 procedure WriteBinary( const b: TBytes); override;
201 //
Jens Geyer17c3ad92017-09-05 20:31:27 +0200202 function ReadMessageBegin: TThriftMessage; override;
Jake Farrell27274222011-11-10 20:32:44 +0000203 procedure ReadMessageEnd(); override;
Jens Geyer17c3ad92017-09-05 20:31:27 +0200204 function ReadStructBegin: TThriftStruct; override;
Jake Farrell27274222011-11-10 20:32:44 +0000205 procedure ReadStructEnd; override;
Jens Geyer17c3ad92017-09-05 20:31:27 +0200206 function ReadFieldBegin: TThriftField; override;
Jake Farrell27274222011-11-10 20:32:44 +0000207 procedure ReadFieldEnd(); override;
Jens Geyer17c3ad92017-09-05 20:31:27 +0200208 function ReadMapBegin: TThriftMap; override;
Jake Farrell27274222011-11-10 20:32:44 +0000209 procedure ReadMapEnd(); override;
Jens Geyer17c3ad92017-09-05 20:31:27 +0200210 function ReadListBegin: TThriftList; override;
Jake Farrell27274222011-11-10 20:32:44 +0000211 procedure ReadListEnd(); override;
Jens Geyer17c3ad92017-09-05 20:31:27 +0200212 function ReadSetBegin: TThriftSet; override;
Jake Farrell27274222011-11-10 20:32:44 +0000213 procedure ReadSetEnd(); override;
214 function ReadBool: Boolean; override;
215 function ReadByte: ShortInt; override;
216 function ReadI16: SmallInt; override;
217 function ReadI32: Integer; override;
218 function ReadI64: Int64; override;
219 function ReadDouble:Double; override;
220 function ReadString : string; override;
221 function ReadBinary: TBytes; override;
222
223
Jens Geyerfad7fd32019-11-09 23:24:52 +0100224 strict private
Jake Farrell27274222011-11-10 20:32:44 +0000225 // Reading methods.
226
227 // Read in a JSON string, unescaping as appropriate.
228 // Skip Reading from the context if skipContext is true.
229 function ReadJSONString( skipContext : Boolean) : TBytes;
230
231 // Return true if the given byte could be a valid part of a JSON number.
232 function IsJSONNumeric( b : Byte) : Boolean;
233
234 // Read in a sequence of characters that are all valid in JSON numbers. Does
235 // not do a complete regex check to validate that this is actually a number.
236 function ReadJSONNumericChars : String;
237
238 // Read in a JSON number. If the context dictates, Read in enclosing quotes.
239 function ReadJSONInteger : Int64;
240
241 // Read in a JSON double value. Throw if the value is not wrapped in quotes
242 // when expected or if wrapped in quotes when not expected.
243 function ReadJSONDouble : Double;
244
245 // Read in a JSON string containing base-64 encoded data and decode it.
246 function ReadJSONBase64 : TBytes;
247
248 procedure ReadJSONObjectStart;
249 procedure ReadJSONObjectEnd;
250 procedure ReadJSONArrayStart;
251 procedure ReadJSONArrayEnd;
252 end;
253
254
255implementation
256
257var
258 COMMA : TBytes;
259 COLON : TBytes;
260 LBRACE : TBytes;
261 RBRACE : TBytes;
262 LBRACKET : TBytes;
263 RBRACKET : TBytes;
264 QUOTE : TBytes;
265 BACKSLASH : TBytes;
Jake Farrell27274222011-11-10 20:32:44 +0000266 ESCSEQ : TBytes;
267
268const
269 VERSION = 1;
270 JSON_CHAR_TABLE : array[0..$2F] of Byte
271 = (0,0,0,0, 0,0,0,0, Byte('b'),Byte('t'),Byte('n'),0, Byte('f'),Byte('r'),0,0,
272 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
273 1,1,Byte('"'),1, 1,1,1,1, 1,1,1,1, 1,1,1,1);
274
Jens Geyer21366942013-12-30 22:04:51 +0100275 ESCAPE_CHARS = '"\/btnfr';
276 ESCAPE_CHAR_VALS = '"\/'#8#9#10#12#13;
Jake Farrell27274222011-11-10 20:32:44 +0000277
278 DEF_STRING_SIZE = 16;
279
280 NAME_BOOL = 'tf';
281 NAME_BYTE = 'i8';
282 NAME_I16 = 'i16';
283 NAME_I32 = 'i32';
284 NAME_I64 = 'i64';
285 NAME_DOUBLE = 'dbl';
286 NAME_STRUCT = 'rec';
287 NAME_STRING = 'str';
288 NAME_MAP = 'map';
289 NAME_LIST = 'lst';
290 NAME_SET = 'set';
291
292 INVARIANT_CULTURE : TFormatSettings
293 = ( ThousandSeparator: ',';
294 DecimalSeparator: '.');
295
296
297
298//--- TJSONProtocolImpl ----------------------
299
300
Roger Meier333bbf32012-01-08 21:51:08 +0000301function TJSONProtocolImpl.TFactory.GetProtocol( const trans: ITransport): IProtocol;
Jake Farrell27274222011-11-10 20:32:44 +0000302begin
Jens Geyera019cda2019-11-09 23:24:52 +0100303 result := TJSONProtocolImpl.Create( trans);
Jake Farrell27274222011-11-10 20:32:44 +0000304end;
305
306class function TJSONProtocolImpl.GetTypeNameForTypeID(typeID : TType) : string;
307begin
308 case typeID of
309 TType.Bool_: result := NAME_BOOL;
310 TType.Byte_: result := NAME_BYTE;
311 TType.I16: result := NAME_I16;
312 TType.I32: result := NAME_I32;
313 TType.I64: result := NAME_I64;
314 TType.Double_: result := NAME_DOUBLE;
315 TType.String_: result := NAME_STRING;
316 TType.Struct: result := NAME_STRUCT;
317 TType.Map: result := NAME_MAP;
318 TType.Set_: result := NAME_SET;
319 TType.List: result := NAME_LIST;
320 else
Jens Geyere0e32402016-04-20 21:50:48 +0200321 raise TProtocolExceptionNotImplemented.Create('Unrecognized type ('+IntToStr(Ord(typeID))+')');
Jake Farrell27274222011-11-10 20:32:44 +0000322 end;
323end;
324
325
326class function TJSONProtocolImpl.GetTypeIDForTypeName( const name : string) : TType;
327begin
328 if name = NAME_BOOL then result := TType.Bool_
329 else if name = NAME_BYTE then result := TType.Byte_
330 else if name = NAME_I16 then result := TType.I16
331 else if name = NAME_I32 then result := TType.I32
332 else if name = NAME_I64 then result := TType.I64
333 else if name = NAME_DOUBLE then result := TType.Double_
334 else if name = NAME_STRUCT then result := TType.Struct
335 else if name = NAME_STRING then result := TType.String_
336 else if name = NAME_MAP then result := TType.Map
337 else if name = NAME_LIST then result := TType.List
338 else if name = NAME_SET then result := TType.Set_
Jens Geyere0e32402016-04-20 21:50:48 +0200339 else raise TProtocolExceptionNotImplemented.Create('Unrecognized type ('+name+')');
Jake Farrell27274222011-11-10 20:32:44 +0000340end;
341
342
343constructor TJSONProtocolImpl.TJSONBaseContext.Create( const aProto : IJSONProtocol);
344begin
345 inherited Create;
Roger Meierfebe8452012-06-06 10:32:24 +0000346 FProto := Pointer(aProto);
Jake Farrell27274222011-11-10 20:32:44 +0000347end;
348
349
350procedure TJSONProtocolImpl.TJSONBaseContext.Write;
351begin
352 // nothing
353end;
354
355
356procedure TJSONProtocolImpl.TJSONBaseContext.Read;
357begin
358 // nothing
359end;
360
361
362function TJSONProtocolImpl.TJSONBaseContext.EscapeNumbers : Boolean;
363begin
364 result := FALSE;
365end;
366
367
368constructor TJSONProtocolImpl.TJSONListContext.Create( const aProto : IJSONProtocol);
369begin
370 inherited Create( aProto);
371 FFirst := TRUE;
372end;
373
374
375procedure TJSONProtocolImpl.TJSONListContext.Write;
376begin
377 if FFirst
378 then FFirst := FALSE
Roger Meierfebe8452012-06-06 10:32:24 +0000379 else IJSONProtocol(FProto).Transport.Write( COMMA);
Jake Farrell27274222011-11-10 20:32:44 +0000380end;
381
382
383procedure TJSONProtocolImpl.TJSONListContext.Read;
384begin
385 if FFirst
386 then FFirst := FALSE
Roger Meierfebe8452012-06-06 10:32:24 +0000387 else IJSONProtocol(FProto).ReadJSONSyntaxChar( COMMA[0]);
Jake Farrell27274222011-11-10 20:32:44 +0000388end;
389
390
391constructor TJSONProtocolImpl.TJSONPairContext.Create( const aProto : IJSONProtocol);
392begin
393 inherited Create( aProto);
394 FFirst := TRUE;
395 FColon := TRUE;
396end;
397
398
399procedure TJSONProtocolImpl.TJSONPairContext.Write;
400begin
401 if FFirst then begin
402 FFirst := FALSE;
403 FColon := TRUE;
404 end
405 else begin
406 if FColon
Roger Meierfebe8452012-06-06 10:32:24 +0000407 then IJSONProtocol(FProto).Transport.Write( COLON)
408 else IJSONProtocol(FProto).Transport.Write( COMMA);
Jake Farrell27274222011-11-10 20:32:44 +0000409 FColon := not FColon;
410 end;
411end;
412
413
414procedure TJSONProtocolImpl.TJSONPairContext.Read;
415begin
416 if FFirst then begin
417 FFirst := FALSE;
418 FColon := TRUE;
419 end
420 else begin
421 if FColon
Roger Meierfebe8452012-06-06 10:32:24 +0000422 then IJSONProtocol(FProto).ReadJSONSyntaxChar( COLON[0])
423 else IJSONProtocol(FProto).ReadJSONSyntaxChar( COMMA[0]);
Jake Farrell27274222011-11-10 20:32:44 +0000424 FColon := not FColon;
425 end;
426end;
427
428
429function TJSONProtocolImpl.TJSONPairContext.EscapeNumbers : Boolean;
430begin
431 result := FColon;
432end;
433
434
435constructor TJSONProtocolImpl.TLookaheadReader.Create( const aProto : IJSONProtocol);
436begin
437 inherited Create;
Roger Meierfebe8452012-06-06 10:32:24 +0000438 FProto := Pointer(aProto);
Jake Farrell27274222011-11-10 20:32:44 +0000439 FHasData := FALSE;
440end;
441
442
443function TJSONProtocolImpl.TLookaheadReader.Read : Byte;
444begin
445 if FHasData
446 then FHasData := FALSE
447 else begin
Jens Geyer17c3ad92017-09-05 20:31:27 +0200448 IJSONProtocol(FProto).Transport.ReadAll( @FData, SizeOf(FData), 0, 1);
Jake Farrell27274222011-11-10 20:32:44 +0000449 end;
Jens Geyer17c3ad92017-09-05 20:31:27 +0200450 result := FData;
Jake Farrell27274222011-11-10 20:32:44 +0000451end;
452
453
454function TJSONProtocolImpl.TLookaheadReader.Peek : Byte;
455begin
456 if not FHasData then begin
Jens Geyer17c3ad92017-09-05 20:31:27 +0200457 IJSONProtocol(FProto).Transport.ReadAll( @FData, SizeOf(FData), 0, 1);
Jake Farrell27274222011-11-10 20:32:44 +0000458 FHasData := TRUE;
459 end;
Jens Geyer17c3ad92017-09-05 20:31:27 +0200460 result := FData;
Jake Farrell27274222011-11-10 20:32:44 +0000461end;
462
463
Roger Meier333bbf32012-01-08 21:51:08 +0000464constructor TJSONProtocolImpl.Create( const aTrans : ITransport);
Jake Farrell27274222011-11-10 20:32:44 +0000465begin
466 inherited Create( aTrans);
467
468 // Stack of nested contexts that we may be in
469 FContextStack := TStack<TJSONBaseContext>.Create;
470
471 FContext := TJSONBaseContext.Create( Self);
472 FReader := TLookaheadReader.Create( Self);
473end;
474
475
476destructor TJSONProtocolImpl.Destroy;
477begin
478 try
Roger Meier45a37262012-01-08 21:44:44 +0000479 ResetContextStack; // free any contents
Jake Farrell27274222011-11-10 20:32:44 +0000480 FreeAndNil( FReader);
481 FreeAndNil( FContext);
482 FreeAndNil( FContextStack);
483 finally
484 inherited Destroy;
485 end;
486end;
487
488
Jens Geyer41f47af2019-11-09 23:24:52 +0100489procedure TJSONProtocolImpl.Reset;
490begin
491 inherited Reset;
492 ResetContextStack;
493end;
494
495
Roger Meier45a37262012-01-08 21:44:44 +0000496procedure TJSONProtocolImpl.ResetContextStack;
497begin
498 while FContextStack.Count > 0
499 do PopContext;
500end;
501
502
Roger Meier333bbf32012-01-08 21:51:08 +0000503procedure TJSONProtocolImpl.PushContext( const aCtx : TJSONBaseContext);
Roger Meier45a37262012-01-08 21:44:44 +0000504begin
505 FContextStack.Push( FContext);
506 FContext := aCtx;
507end;
508
509
510procedure TJSONProtocolImpl.PopContext;
511begin
512 FreeAndNil(FContext);
513 FContext := FContextStack.Pop;
514end;
515
516
Jake Farrell27274222011-11-10 20:32:44 +0000517procedure TJSONProtocolImpl.ReadJSONSyntaxChar( b : Byte);
518var ch : Byte;
519begin
520 ch := FReader.Read;
521 if (ch <> b)
Jens Geyere0e32402016-04-20 21:50:48 +0200522 then raise TProtocolExceptionInvalidData.Create('Unexpected character ('+Char(ch)+')');
Jake Farrell27274222011-11-10 20:32:44 +0000523end;
524
525
526class function TJSONProtocolImpl.HexVal( ch : Byte) : Byte;
527var i : Integer;
528begin
529 i := StrToIntDef( '$0'+Char(ch), -1);
530 if (0 <= i) and (i < $10)
531 then result := i
Jens Geyere0e32402016-04-20 21:50:48 +0200532 else raise TProtocolExceptionInvalidData.Create('Expected hex character ('+Char(ch)+')');
Jake Farrell27274222011-11-10 20:32:44 +0000533end;
534
535
536class function TJSONProtocolImpl.HexChar( val : Byte) : Byte;
537const HEXCHARS = '0123456789ABCDEF';
538begin
539 result := Byte( PChar(HEXCHARS)[val and $0F]);
540 ASSERT( Pos( Char(result), HEXCHARS) > 0);
541end;
542
543
Roger Meier333bbf32012-01-08 21:51:08 +0000544procedure TJSONProtocolImpl.WriteJSONString( const str : string);
Jake Farrell27274222011-11-10 20:32:44 +0000545begin
546 WriteJSONString( SysUtils.TEncoding.UTF8.GetBytes( str));
547end;
548
549
550procedure TJSONProtocolImpl.WriteJSONString( const b : TBytes);
551var i : Integer;
552 tmp : TBytes;
553begin
554 FContext.Write;
555 Transport.Write( QUOTE);
556 for i := 0 to Length(b)-1 do begin
557
558 if (b[i] and $00FF) >= $30 then begin
559
560 if (b[i] = BACKSLASH[0]) then begin
561 Transport.Write( BACKSLASH);
562 Transport.Write( BACKSLASH);
563 end
564 else begin
565 Transport.Write( b, i, 1);
566 end;
567
568 end
569 else begin
570 SetLength( tmp, 2);
571 tmp[0] := JSON_CHAR_TABLE[b[i]];
572 if (tmp[0] = 1) then begin
573 Transport.Write( b, i, 1)
574 end
575 else if (tmp[0] > 1) then begin
576 Transport.Write( BACKSLASH);
577 Transport.Write( tmp, 0, 1);
578 end
579 else begin
580 Transport.Write( ESCSEQ);
581 tmp[0] := HexChar( b[i] div $10);
582 tmp[1] := HexChar( b[i]);
583 Transport.Write( tmp, 0, 2);
584 end;
585 end;
586 end;
587 Transport.Write( QUOTE);
588end;
589
590
Roger Meier333bbf32012-01-08 21:51:08 +0000591procedure TJSONProtocolImpl.WriteJSONInteger( const num : Int64);
Jake Farrell27274222011-11-10 20:32:44 +0000592var str : String;
593 escapeNum : Boolean;
594begin
595 FContext.Write;
596 str := IntToStr(num);
597
598 escapeNum := FContext.EscapeNumbers;
599 if escapeNum
600 then Transport.Write( QUOTE);
601
602 Transport.Write( SysUtils.TEncoding.UTF8.GetBytes( str));
603
604 if escapeNum
605 then Transport.Write( QUOTE);
606end;
607
608
609procedure TJSONProtocolImpl.WriteJSONDouble( const num : Double);
610var str : string;
611 special : Boolean;
612 escapeNum : Boolean;
613begin
614 FContext.Write;
615
616 str := FloatToStr( num, INVARIANT_CULTURE);
617 special := FALSE;
618
619 case UpCase(str[1]) of
620 'N' : special := TRUE; // NaN
621 'I' : special := TRUE; // Infinity
622 '-' : special := (UpCase(str[2]) = 'I'); // -Infinity
623 end;
624
625 escapeNum := special or FContext.EscapeNumbers;
626
627
628 if escapeNum
629 then Transport.Write( QUOTE);
630
631 Transport.Write( SysUtils.TEncoding.UTF8.GetBytes( str));
632
633 if escapeNum
634 then Transport.Write( QUOTE);
635end;
636
637
638procedure TJSONProtocolImpl.WriteJSONBase64( const b : TBytes);
Jens Geyerd8bddbc2014-12-14 00:41:33 +0100639var len, off, cnt : Integer;
640 tmpBuf : TBytes;
Jake Farrell27274222011-11-10 20:32:44 +0000641begin
642 FContext.Write;
643 Transport.Write( QUOTE);
644
Jens Geyerd8bddbc2014-12-14 00:41:33 +0100645 len := Length(b);
646 off := 0;
647 SetLength( tmpBuf, 4);
648
649 while len >= 3 do begin
650 // Encode 3 bytes at a time
651 Base64Utils.Encode( b, off, 3, tmpBuf, 0);
652 Transport.Write( tmpBuf, 0, 4);
653 Inc( off, 3);
654 Dec( len, 3);
Jake Farrell27274222011-11-10 20:32:44 +0000655 end;
Jens Geyerd8bddbc2014-12-14 00:41:33 +0100656
657 // Encode remainder, if any
658 if len > 0 then begin
659 cnt := Base64Utils.Encode( b, off, len, tmpBuf, 0);
660 Transport.Write( tmpBuf, 0, cnt);
661 end;
Jake Farrell27274222011-11-10 20:32:44 +0000662
663 Transport.Write( QUOTE);
664end;
665
666
667procedure TJSONProtocolImpl.WriteJSONObjectStart;
668begin
669 FContext.Write;
670 Transport.Write( LBRACE);
671 PushContext( TJSONPairContext.Create( Self));
672end;
673
674
675procedure TJSONProtocolImpl.WriteJSONObjectEnd;
676begin
677 PopContext;
678 Transport.Write( RBRACE);
679end;
680
681
682procedure TJSONProtocolImpl.WriteJSONArrayStart;
683begin
684 FContext.Write;
685 Transport.Write( LBRACKET);
686 PushContext( TJSONListContext.Create( Self));
687end;
688
689
690procedure TJSONProtocolImpl.WriteJSONArrayEnd;
691begin
692 PopContext;
693 Transport.Write( RBRACKET);
694end;
695
696
Jens Geyer17c3ad92017-09-05 20:31:27 +0200697procedure TJSONProtocolImpl.WriteMessageBegin( const aMsg : TThriftMessage);
Jake Farrell27274222011-11-10 20:32:44 +0000698begin
Jens Geyer41f47af2019-11-09 23:24:52 +0100699 Reset;
Roger Meier45a37262012-01-08 21:44:44 +0000700 ResetContextStack; // THRIFT-1473
701
Jake Farrell27274222011-11-10 20:32:44 +0000702 WriteJSONArrayStart;
703 WriteJSONInteger(VERSION);
704
705 WriteJSONString( SysUtils.TEncoding.UTF8.GetBytes( aMsg.Name));
706
707 WriteJSONInteger( LongInt( aMsg.Type_));
708 WriteJSONInteger( aMsg.SeqID);
709end;
710
711procedure TJSONProtocolImpl.WriteMessageEnd;
712begin
713 WriteJSONArrayEnd;
714end;
715
716
Jens Geyer17c3ad92017-09-05 20:31:27 +0200717procedure TJSONProtocolImpl.WriteStructBegin( const struc: TThriftStruct);
Jake Farrell27274222011-11-10 20:32:44 +0000718begin
719 WriteJSONObjectStart;
720end;
721
722
723procedure TJSONProtocolImpl.WriteStructEnd;
724begin
725 WriteJSONObjectEnd;
726end;
727
728
Jens Geyer17c3ad92017-09-05 20:31:27 +0200729procedure TJSONProtocolImpl.WriteFieldBegin( const field : TThriftField);
Jake Farrell27274222011-11-10 20:32:44 +0000730begin
731 WriteJSONInteger(field.ID);
732 WriteJSONObjectStart;
733 WriteJSONString( GetTypeNameForTypeID(field.Type_));
734end;
735
736
737procedure TJSONProtocolImpl.WriteFieldEnd;
738begin
739 WriteJSONObjectEnd;
740end;
741
742
743procedure TJSONProtocolImpl.WriteFieldStop;
744begin
745 // nothing to do
746end;
747
Jens Geyer17c3ad92017-09-05 20:31:27 +0200748procedure TJSONProtocolImpl.WriteMapBegin( const map: TThriftMap);
Jake Farrell27274222011-11-10 20:32:44 +0000749begin
750 WriteJSONArrayStart;
751 WriteJSONString( GetTypeNameForTypeID( map.KeyType));
752 WriteJSONString( GetTypeNameForTypeID( map.ValueType));
753 WriteJSONInteger( map.Count);
754 WriteJSONObjectStart;
755end;
756
757
758procedure TJSONProtocolImpl.WriteMapEnd;
759begin
760 WriteJSONObjectEnd;
761 WriteJSONArrayEnd;
762end;
763
764
Jens Geyer17c3ad92017-09-05 20:31:27 +0200765procedure TJSONProtocolImpl.WriteListBegin( const list: TThriftList);
Jake Farrell27274222011-11-10 20:32:44 +0000766begin
767 WriteJSONArrayStart;
768 WriteJSONString( GetTypeNameForTypeID( list.ElementType));
769 WriteJSONInteger(list.Count);
770end;
771
772
773procedure TJSONProtocolImpl.WriteListEnd;
774begin
775 WriteJSONArrayEnd;
776end;
777
778
Jens Geyer17c3ad92017-09-05 20:31:27 +0200779procedure TJSONProtocolImpl.WriteSetBegin( const set_: TThriftSet);
Jake Farrell27274222011-11-10 20:32:44 +0000780begin
781 WriteJSONArrayStart;
782 WriteJSONString( GetTypeNameForTypeID( set_.ElementType));
783 WriteJSONInteger( set_.Count);
784end;
785
786
787procedure TJSONProtocolImpl.WriteSetEnd;
788begin
789 WriteJSONArrayEnd;
790end;
791
792procedure TJSONProtocolImpl.WriteBool( b: Boolean);
793begin
794 if b
795 then WriteJSONInteger( 1)
796 else WriteJSONInteger( 0);
797end;
798
799procedure TJSONProtocolImpl.WriteByte( b: ShortInt);
800begin
801 WriteJSONInteger( b);
802end;
803
804procedure TJSONProtocolImpl.WriteI16( i16: SmallInt);
805begin
806 WriteJSONInteger( i16);
807end;
808
809procedure TJSONProtocolImpl.WriteI32( i32: Integer);
810begin
811 WriteJSONInteger( i32);
812end;
813
Roger Meier333bbf32012-01-08 21:51:08 +0000814procedure TJSONProtocolImpl.WriteI64( const i64: Int64);
Jake Farrell27274222011-11-10 20:32:44 +0000815begin
816 WriteJSONInteger(i64);
817end;
818
Roger Meier333bbf32012-01-08 21:51:08 +0000819procedure TJSONProtocolImpl.WriteDouble( const d: Double);
Jake Farrell27274222011-11-10 20:32:44 +0000820begin
821 WriteJSONDouble( d);
822end;
823
824procedure TJSONProtocolImpl.WriteString( const s: string );
825begin
826 WriteJSONString( SysUtils.TEncoding.UTF8.GetBytes( s));
827end;
828
829procedure TJSONProtocolImpl.WriteBinary( const b: TBytes);
830begin
831 WriteJSONBase64( b);
832end;
833
834
835function TJSONProtocolImpl.ReadJSONString( skipContext : Boolean) : TBytes;
Jens Geyerf726ae32021-06-04 11:17:26 +0200836var buffer : TThriftMemoryStream;
Jens Geyer7bb44a32014-02-07 22:24:37 +0100837 ch : Byte;
838 wch : Word;
Phongphan Phutthaa6509f72015-10-31 01:09:47 +0700839 highSurogate: Char;
840 surrogatePairs: Array[0..1] of Char;
Jake Farrell27274222011-11-10 20:32:44 +0000841 off : Integer;
842 tmp : TBytes;
843begin
Phongphan Phutthaa6509f72015-10-31 01:09:47 +0700844 highSurogate := #0;
Jens Geyerf726ae32021-06-04 11:17:26 +0200845 buffer := TThriftMemoryStream.Create;
Jake Farrell27274222011-11-10 20:32:44 +0000846 try
847 if not skipContext
848 then FContext.Read;
849
850 ReadJSONSyntaxChar( QUOTE[0]);
851
852 while TRUE do begin
853 ch := FReader.Read;
854
855 if (ch = QUOTE[0])
856 then Break;
857
Jens Geyer7bb44a32014-02-07 22:24:37 +0100858 // check for escapes
859 if (ch <> ESCSEQ[0]) then begin
860 buffer.Write( ch, 1);
861 Continue;
Jake Farrell27274222011-11-10 20:32:44 +0000862 end;
Jens Geyer7bb44a32014-02-07 22:24:37 +0100863
864 // distuinguish between \uNNNN and \?
865 ch := FReader.Read;
866 if (ch <> ESCSEQ[1])
867 then begin
868 off := Pos( Char(ch), ESCAPE_CHARS);
869 if off < 1
Jens Geyere0e32402016-04-20 21:50:48 +0200870 then raise TProtocolExceptionInvalidData.Create('Expected control char');
Jens Geyer7bb44a32014-02-07 22:24:37 +0100871 ch := Byte( ESCAPE_CHAR_VALS[off]);
872 buffer.Write( ch, 1);
873 Continue;
874 end;
875
876 // it is \uXXXX
877 SetLength( tmp, 4);
878 Transport.ReadAll( tmp, 0, 4);
879 wch := (HexVal(tmp[0]) shl 12)
880 + (HexVal(tmp[1]) shl 8)
881 + (HexVal(tmp[2]) shl 4)
882 + HexVal(tmp[3]);
Phongphan Phutthaa6509f72015-10-31 01:09:47 +0700883
Jens Geyer7bb44a32014-02-07 22:24:37 +0100884 // we need to make UTF8 bytes from it, to be decoded later
Jens Geyer71070432016-01-29 10:08:39 +0100885 if CharUtils.IsHighSurrogate(char(wch)) then begin
Phongphan Phutthaa6509f72015-10-31 01:09:47 +0700886 if highSurogate <> #0
Jens Geyere0e32402016-04-20 21:50:48 +0200887 then raise TProtocolExceptionInvalidData.Create('Expected low surrogate char');
Phongphan Phutthaa6509f72015-10-31 01:09:47 +0700888 highSurogate := char(wch);
889 end
Jens Geyer71070432016-01-29 10:08:39 +0100890 else if CharUtils.IsLowSurrogate(char(wch)) then begin
Phongphan Phutthaa6509f72015-10-31 01:09:47 +0700891 if highSurogate = #0
Jens Geyere0e32402016-04-20 21:50:48 +0200892 then TProtocolExceptionInvalidData.Create('Expected high surrogate char');
Phongphan Phutthaa6509f72015-10-31 01:09:47 +0700893 surrogatePairs[0] := highSurogate;
894 surrogatePairs[1] := char(wch);
895 tmp := TEncoding.UTF8.GetBytes(surrogatePairs);
896 buffer.Write( tmp[0], Length(tmp));
897 highSurogate := #0;
898 end
899 else begin
900 tmp := SysUtils.TEncoding.UTF8.GetBytes(Char(wch));
901 buffer.Write( tmp[0], Length(tmp));
902 end;
Jake Farrell27274222011-11-10 20:32:44 +0000903 end;
904
Phongphan Phutthaa6509f72015-10-31 01:09:47 +0700905 if highSurogate <> #0
Jens Geyere0e32402016-04-20 21:50:48 +0200906 then raise TProtocolExceptionInvalidData.Create('Expected low surrogate char');
Phongphan Phutthaa6509f72015-10-31 01:09:47 +0700907
Jake Farrell27274222011-11-10 20:32:44 +0000908 SetLength( result, buffer.Size);
Jake Farrella2a9ee92011-12-15 20:50:31 +0000909 if buffer.Size > 0 then Move( buffer.Memory^, result[0], Length(result));
Jake Farrell27274222011-11-10 20:32:44 +0000910
911 finally
912 buffer.Free;
913 end;
914end;
915
916
917function TJSONProtocolImpl.IsJSONNumeric( b : Byte) : Boolean;
918const NUMCHARS = ['+','-','.','0','1','2','3','4','5','6','7','8','9','E','e'];
919begin
920 result := CharInSet( Char(b), NUMCHARS);
921end;
922
923
924function TJSONProtocolImpl.ReadJSONNumericChars : string;
925var strbld : TThriftStringBuilder;
926 ch : Byte;
927begin
928 strbld := TThriftStringBuilder.Create;
929 try
930 while TRUE do begin
931 ch := FReader.Peek;
932 if IsJSONNumeric(ch)
933 then strbld.Append( Char(FReader.Read))
934 else Break;
935 end;
936 result := strbld.ToString;
937
938 finally
939 strbld.Free;
940 end;
941end;
942
943
944function TJSONProtocolImpl.ReadJSONInteger : Int64;
945var str : string;
946begin
947 FContext.Read;
948 if FContext.EscapeNumbers
949 then ReadJSONSyntaxChar( QUOTE[0]);
950
951 str := ReadJSONNumericChars;
952
953 if FContext.EscapeNumbers
954 then ReadJSONSyntaxChar( QUOTE[0]);
955
956 try
957 result := StrToInt64(str);
958 except
959 on e:Exception do begin
Jens Geyere0e32402016-04-20 21:50:48 +0200960 raise TProtocolExceptionInvalidData.Create('Bad data encounted in numeric data ('+str+') ('+e.Message+')');
Jake Farrell27274222011-11-10 20:32:44 +0000961 end;
962 end;
963end;
964
965
966function TJSONProtocolImpl.ReadJSONDouble : Double;
967var dub : Double;
968 str : string;
969begin
970 FContext.Read;
971
972 if FReader.Peek = QUOTE[0]
973 then begin
974 str := SysUtils.TEncoding.UTF8.GetString( ReadJSONString( TRUE));
975 dub := StrToFloat( str, INVARIANT_CULTURE);
976
977 if not FContext.EscapeNumbers()
978 and not Math.IsNaN(dub)
979 and not Math.IsInfinite(dub)
980 then begin
981 // Throw exception -- we should not be in a string in Self case
Jens Geyere0e32402016-04-20 21:50:48 +0200982 raise TProtocolExceptionInvalidData.Create('Numeric data unexpectedly quoted');
Jake Farrell27274222011-11-10 20:32:44 +0000983 end;
984 result := dub;
985 Exit;
986 end;
987
988 // will throw - we should have had a quote if escapeNum == true
989 if FContext.EscapeNumbers
990 then ReadJSONSyntaxChar( QUOTE[0]);
991
992 try
993 str := ReadJSONNumericChars;
994 result := StrToFloat( str, INVARIANT_CULTURE);
995 except
996 on e:Exception
Jens Geyere0e32402016-04-20 21:50:48 +0200997 do raise TProtocolExceptionInvalidData.Create('Bad data encounted in numeric data ('+str+') ('+e.Message+')');
Jake Farrell27274222011-11-10 20:32:44 +0000998 end;
999end;
1000
1001
1002function TJSONProtocolImpl.ReadJSONBase64 : TBytes;
1003var b : TBytes;
Jens Geyer9f9535c2014-12-14 04:16:05 +01001004 len, off, size : Integer;
Jake Farrell27274222011-11-10 20:32:44 +00001005begin
1006 b := ReadJSONString(false);
1007
Jens Geyerd8bddbc2014-12-14 00:41:33 +01001008 len := Length(b);
1009 off := 0;
1010 size := 0;
1011
1012 // reduce len to ignore fill bytes
1013 Dec(len);
1014 while (len >= 0) and (b[len] = Byte('=')) do Dec(len);
1015 Inc(len);
1016
1017 // read & decode full byte triplets = 4 source bytes
1018 while (len >= 4) do begin
1019 // Decode 4 bytes at a time
1020 Inc( size, Base64Utils.Decode( b, off, 4, b, size)); // decoded in place
1021 Inc( off, 4);
1022 Dec( len, 4);
1023 end;
1024
1025 // Don't decode if we hit the end or got a single leftover byte (invalid
1026 // base64 but legal for skip of regular string type)
1027 if len > 1 then begin
1028 // Decode remainder
1029 Inc( size, Base64Utils.Decode( b, off, len, b, size)); // decoded in place
1030 end;
1031
1032 // resize to final size and return the data
1033 SetLength( b, size);
1034 result := b;
Jake Farrell27274222011-11-10 20:32:44 +00001035end;
1036
1037
1038procedure TJSONProtocolImpl.ReadJSONObjectStart;
1039begin
1040 FContext.Read;
1041 ReadJSONSyntaxChar( LBRACE[0]);
1042 PushContext( TJSONPairContext.Create( Self));
1043end;
1044
1045
1046procedure TJSONProtocolImpl.ReadJSONObjectEnd;
1047begin
1048 ReadJSONSyntaxChar( RBRACE[0]);
1049 PopContext;
1050end;
1051
1052
1053procedure TJSONProtocolImpl.ReadJSONArrayStart;
1054begin
1055 FContext.Read;
1056 ReadJSONSyntaxChar( LBRACKET[0]);
1057 PushContext( TJSONListContext.Create( Self));
1058end;
1059
1060
1061procedure TJSONProtocolImpl.ReadJSONArrayEnd;
1062begin
1063 ReadJSONSyntaxChar( RBRACKET[0]);
1064 PopContext;
1065end;
1066
1067
Jens Geyer17c3ad92017-09-05 20:31:27 +02001068function TJSONProtocolImpl.ReadMessageBegin: TThriftMessage;
Jake Farrell27274222011-11-10 20:32:44 +00001069begin
Jens Geyer41f47af2019-11-09 23:24:52 +01001070 Reset;
Roger Meier45a37262012-01-08 21:44:44 +00001071 ResetContextStack; // THRIFT-1473
1072
Jens Geyer17c3ad92017-09-05 20:31:27 +02001073 Init( result);
Jake Farrell27274222011-11-10 20:32:44 +00001074 ReadJSONArrayStart;
1075
1076 if ReadJSONInteger <> VERSION
Jens Geyere0e32402016-04-20 21:50:48 +02001077 then raise TProtocolExceptionBadVersion.Create('Message contained bad version.');
Jake Farrell27274222011-11-10 20:32:44 +00001078
1079 result.Name := SysUtils.TEncoding.UTF8.GetString( ReadJSONString( FALSE));
1080 result.Type_ := TMessageType( ReadJSONInteger);
1081 result.SeqID := ReadJSONInteger;
1082end;
1083
1084
1085procedure TJSONProtocolImpl.ReadMessageEnd;
1086begin
1087 ReadJSONArrayEnd;
1088end;
1089
1090
Jens Geyer17c3ad92017-09-05 20:31:27 +02001091function TJSONProtocolImpl.ReadStructBegin : TThriftStruct ;
Jake Farrell27274222011-11-10 20:32:44 +00001092begin
1093 ReadJSONObjectStart;
Jens Geyer17c3ad92017-09-05 20:31:27 +02001094 Init( result);
Jake Farrell27274222011-11-10 20:32:44 +00001095end;
1096
1097
1098procedure TJSONProtocolImpl.ReadStructEnd;
1099begin
1100 ReadJSONObjectEnd;
1101end;
1102
1103
Jens Geyer17c3ad92017-09-05 20:31:27 +02001104function TJSONProtocolImpl.ReadFieldBegin : TThriftField;
Jake Farrell27274222011-11-10 20:32:44 +00001105var ch : Byte;
1106 str : string;
1107begin
Jens Geyer17c3ad92017-09-05 20:31:27 +02001108 Init( result);
Jake Farrell27274222011-11-10 20:32:44 +00001109 ch := FReader.Peek;
1110 if ch = RBRACE[0]
1111 then result.Type_ := TType.Stop
1112 else begin
1113 result.ID := ReadJSONInteger;
1114 ReadJSONObjectStart;
1115
1116 str := SysUtils.TEncoding.UTF8.GetString( ReadJSONString( FALSE));
1117 result.Type_ := GetTypeIDForTypeName( str);
1118 end;
1119end;
1120
1121
1122procedure TJSONProtocolImpl.ReadFieldEnd;
1123begin
1124 ReadJSONObjectEnd;
1125end;
1126
1127
Jens Geyer17c3ad92017-09-05 20:31:27 +02001128function TJSONProtocolImpl.ReadMapBegin : TThriftMap;
Jake Farrell27274222011-11-10 20:32:44 +00001129var str : string;
1130begin
Jens Geyer17c3ad92017-09-05 20:31:27 +02001131 Init( result);
Jake Farrell27274222011-11-10 20:32:44 +00001132 ReadJSONArrayStart;
1133
1134 str := SysUtils.TEncoding.UTF8.GetString( ReadJSONString(FALSE));
1135 result.KeyType := GetTypeIDForTypeName( str);
1136
1137 str := SysUtils.TEncoding.UTF8.GetString( ReadJSONString(FALSE));
1138 result.ValueType := GetTypeIDForTypeName( str);
1139
1140 result.Count := ReadJSONInteger;
Jens Geyer41f47af2019-11-09 23:24:52 +01001141 CheckReadBytesAvailable(result);
1142
Jake Farrell27274222011-11-10 20:32:44 +00001143 ReadJSONObjectStart;
1144end;
1145
1146
1147procedure TJSONProtocolImpl.ReadMapEnd;
1148begin
1149 ReadJSONObjectEnd;
1150 ReadJSONArrayEnd;
1151end;
1152
1153
Jens Geyer17c3ad92017-09-05 20:31:27 +02001154function TJSONProtocolImpl.ReadListBegin : TThriftList;
Jake Farrell27274222011-11-10 20:32:44 +00001155var str : string;
1156begin
Jens Geyer17c3ad92017-09-05 20:31:27 +02001157 Init( result);
Jake Farrell27274222011-11-10 20:32:44 +00001158 ReadJSONArrayStart;
1159
1160 str := SysUtils.TEncoding.UTF8.GetString( ReadJSONString(FALSE));
1161 result.ElementType := GetTypeIDForTypeName( str);
1162 result.Count := ReadJSONInteger;
Jens Geyer41f47af2019-11-09 23:24:52 +01001163 CheckReadBytesAvailable(result);
Jake Farrell27274222011-11-10 20:32:44 +00001164end;
1165
1166
1167procedure TJSONProtocolImpl.ReadListEnd;
1168begin
1169 ReadJSONArrayEnd;
1170end;
1171
1172
Jens Geyer17c3ad92017-09-05 20:31:27 +02001173function TJSONProtocolImpl.ReadSetBegin : TThriftSet;
Jake Farrell27274222011-11-10 20:32:44 +00001174var str : string;
1175begin
Jens Geyer17c3ad92017-09-05 20:31:27 +02001176 Init( result);
Jake Farrell27274222011-11-10 20:32:44 +00001177 ReadJSONArrayStart;
1178
1179 str := SysUtils.TEncoding.UTF8.GetString( ReadJSONString(FALSE));
1180 result.ElementType := GetTypeIDForTypeName( str);
1181 result.Count := ReadJSONInteger;
Jens Geyer41f47af2019-11-09 23:24:52 +01001182 CheckReadBytesAvailable(result);
Jake Farrell27274222011-11-10 20:32:44 +00001183end;
1184
1185
1186procedure TJSONProtocolImpl.ReadSetEnd;
1187begin
1188 ReadJSONArrayEnd;
1189end;
1190
1191
1192function TJSONProtocolImpl.ReadBool : Boolean;
1193begin
1194 result := (ReadJSONInteger <> 0);
1195end;
1196
1197
1198function TJSONProtocolImpl.ReadByte : ShortInt;
1199begin
1200 result := ReadJSONInteger;
1201end;
1202
1203
1204function TJSONProtocolImpl.ReadI16 : SmallInt;
1205begin
1206 result := ReadJSONInteger;
1207end;
1208
1209
1210function TJSONProtocolImpl.ReadI32 : LongInt;
1211begin
1212 result := ReadJSONInteger;
1213end;
1214
1215
1216function TJSONProtocolImpl.ReadI64 : Int64;
1217begin
1218 result := ReadJSONInteger;
1219end;
1220
1221
1222function TJSONProtocolImpl.ReadDouble : Double;
1223begin
1224 result := ReadJSONDouble;
1225end;
1226
1227
1228function TJSONProtocolImpl.ReadString : string;
1229begin
1230 result := SysUtils.TEncoding.UTF8.GetString( ReadJSONString( FALSE));
1231end;
1232
1233
1234function TJSONProtocolImpl.ReadBinary : TBytes;
1235begin
1236 result := ReadJSONBase64;
1237end;
1238
1239
Jens Geyer41f47af2019-11-09 23:24:52 +01001240function TJSONProtocolImpl.GetMinSerializedSize( const aType : TType) : Integer;
1241// Return the minimum number of bytes a type will consume on the wire
1242begin
1243 case aType of
1244 TType.Stop: result := 0;
1245 TType.Void: result := 0;
1246 TType.Bool_: result := 1;
1247 TType.Byte_: result := 1;
1248 TType.Double_: result := 1;
1249 TType.I16: result := 1;
1250 TType.I32: result := 1;
1251 TType.I64: result := 1;
1252 TType.String_: result := 2; // empty string
1253 TType.Struct: result := 2; // empty struct
1254 TType.Map: result := 2; // empty map
1255 TType.Set_: result := 2; // empty set
1256 TType.List: result := 2; // empty list
1257 else
1258 raise TTransportExceptionBadArgs.Create('Unhandled type code');
1259 end;
1260end;
1261
1262
1263
Jake Farrell27274222011-11-10 20:32:44 +00001264//--- init code ---
1265
1266procedure InitBytes( var b : TBytes; aData : array of Byte);
1267begin
1268 SetLength( b, Length(aData));
1269 Move( aData, b[0], Length(b));
1270end;
1271
1272initialization
1273 InitBytes( COMMA, [Byte(',')]);
1274 InitBytes( COLON, [Byte(':')]);
1275 InitBytes( LBRACE, [Byte('{')]);
1276 InitBytes( RBRACE, [Byte('}')]);
1277 InitBytes( LBRACKET, [Byte('[')]);
1278 InitBytes( RBRACKET, [Byte(']')]);
1279 InitBytes( QUOTE, [Byte('"')]);
1280 InitBytes( BACKSLASH, [Byte('\')]);
Jake Farrell27274222011-11-10 20:32:44 +00001281 InitBytes( ESCSEQ, [Byte('\'),Byte('u'),Byte('0'),Byte('0')]);
1282end.