blob: 61cad8b627c197cf4616087957baae8aea82feb7 [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,
35 Thrift.Utils;
Jake Farrell27274222011-11-10 20:32:44 +000036
37type
38 IJSONProtocol = interface( IProtocol)
39 ['{F0DAFDBD-692A-4B71-9736-F5D485A2178F}']
40 // Read a byte that must match b; otherwise an exception is thrown.
41 procedure ReadJSONSyntaxChar( b : Byte);
42 end;
43
44 // JSON protocol implementation for thrift.
45 // This is a full-featured protocol supporting Write and Read.
46 // Please see the C++ class header for a detailed description of the protocol's wire format.
47 // Adapted from the C# version.
48 TJSONProtocolImpl = class( TProtocolImpl, IJSONProtocol)
49 public
50 type
51 TFactory = class( TInterfacedObject, IProtocolFactory)
52 public
Roger Meier333bbf32012-01-08 21:51:08 +000053 function GetProtocol( const trans: ITransport): IProtocol;
Jake Farrell27274222011-11-10 20:32:44 +000054 end;
55
Jens Geyerfad7fd32019-11-09 23:24:52 +010056 strict private
Jake Farrell27274222011-11-10 20:32:44 +000057 class function GetTypeNameForTypeID(typeID : TType) : string;
58 class function GetTypeIDForTypeName( const name : string) : TType;
59
Jens Geyerfad7fd32019-11-09 23:24:52 +010060 strict protected
Jake Farrell27274222011-11-10 20:32:44 +000061 type
62 // Base class for tracking JSON contexts that may require
63 // inserting/Reading additional JSON syntax characters.
64 // This base context does nothing.
65 TJSONBaseContext = class
Jens Geyerfad7fd32019-11-09 23:24:52 +010066 strict protected
Roger Meierfebe8452012-06-06 10:32:24 +000067 FProto : Pointer; // weak IJSONProtocol;
Jake Farrell27274222011-11-10 20:32:44 +000068 public
69 constructor Create( const aProto : IJSONProtocol);
70 procedure Write; virtual;
71 procedure Read; virtual;
72 function EscapeNumbers : Boolean; virtual;
73 end;
74
75 // Context for JSON lists.
76 // Will insert/Read commas before each item except for the first one.
77 TJSONListContext = class( TJSONBaseContext)
Jens Geyerfad7fd32019-11-09 23:24:52 +010078 strict private
Jake Farrell27274222011-11-10 20:32:44 +000079 FFirst : Boolean;
80 public
81 constructor Create( const aProto : IJSONProtocol);
82 procedure Write; override;
83 procedure Read; override;
84 end;
85
86 // Context for JSON records. Will insert/Read colons before the value portion of each record
87 // pair, and commas before each key except the first. In addition, will indicate that numbers
88 // in the key position need to be escaped in quotes (since JSON keys must be strings).
89 TJSONPairContext = class( TJSONBaseContext)
Jens Geyerfad7fd32019-11-09 23:24:52 +010090 strict private
Jake Farrell27274222011-11-10 20:32:44 +000091 FFirst, FColon : Boolean;
92 public
93 constructor Create( const aProto : IJSONProtocol);
94 procedure Write; override;
95 procedure Read; override;
96 function EscapeNumbers : Boolean; override;
97 end;
98
99 // Holds up to one byte from the transport
100 TLookaheadReader = class
Jens Geyerfad7fd32019-11-09 23:24:52 +0100101 strict protected
Roger Meierfebe8452012-06-06 10:32:24 +0000102 FProto : Pointer; // weak IJSONProtocol;
Jens Geyerfad7fd32019-11-09 23:24:52 +0100103
104 protected
Jake Farrell27274222011-11-10 20:32:44 +0000105 constructor Create( const aProto : IJSONProtocol);
106
Jens Geyerfad7fd32019-11-09 23:24:52 +0100107 strict private
Jake Farrell27274222011-11-10 20:32:44 +0000108 FHasData : Boolean;
Jens Geyer17c3ad92017-09-05 20:31:27 +0200109 FData : Byte;
Jake Farrell27274222011-11-10 20:32:44 +0000110
111 public
112 // Return and consume the next byte to be Read, either taking it from the
113 // data buffer if present or getting it from the transport otherwise.
114 function Read : Byte;
115
116 // Return the next byte to be Read without consuming, filling the data
117 // buffer if it has not been filled alReady.
118 function Peek : Byte;
119 end;
120
Jens Geyerfad7fd32019-11-09 23:24:52 +0100121 strict protected
Jake Farrell27274222011-11-10 20:32:44 +0000122 // Stack of nested contexts that we may be in
123 FContextStack : TStack<TJSONBaseContext>;
124
125 // Current context that we are in
126 FContext : TJSONBaseContext;
127
128 // Reader that manages a 1-byte buffer
129 FReader : TLookaheadReader;
130
131 // Push/pop a new JSON context onto/from the stack.
Roger Meier45a37262012-01-08 21:44:44 +0000132 procedure ResetContextStack;
Roger Meier333bbf32012-01-08 21:51:08 +0000133 procedure PushContext( const aCtx : TJSONBaseContext);
Jake Farrell27274222011-11-10 20:32:44 +0000134 procedure PopContext;
135
Jens Geyer41f47af2019-11-09 23:24:52 +0100136 strict protected
137 function GetMinSerializedSize( const aType : TType) : Integer; override;
138 procedure Reset; override;
139
Jake Farrell27274222011-11-10 20:32:44 +0000140 public
141 // TJSONProtocolImpl Constructor
Roger Meier333bbf32012-01-08 21:51:08 +0000142 constructor Create( const aTrans : ITransport);
Jake Farrell27274222011-11-10 20:32:44 +0000143 destructor Destroy; override;
144
Jens Geyerfad7fd32019-11-09 23:24:52 +0100145 strict protected
Jake Farrell27274222011-11-10 20:32:44 +0000146 // IJSONProtocol
147 // Read a byte that must match b; otherwise an exception is thrown.
148 procedure ReadJSONSyntaxChar( b : Byte);
149
Jens Geyerfad7fd32019-11-09 23:24:52 +0100150 strict private
Jake Farrell27274222011-11-10 20:32:44 +0000151 // Convert a byte containing a hex char ('0'-'9' or 'a'-'f') into its corresponding hex value
152 class function HexVal( ch : Byte) : Byte;
153
154 // Convert a byte containing a hex value to its corresponding hex character
155 class function HexChar( val : Byte) : Byte;
156
157 // Write the bytes in array buf as a JSON characters, escaping as needed
158 procedure WriteJSONString( const b : TBytes); overload;
Roger Meier333bbf32012-01-08 21:51:08 +0000159 procedure WriteJSONString( const str : string); overload;
Jake Farrell27274222011-11-10 20:32:44 +0000160
161 // Write out number as a JSON value. If the context dictates so, it will be
162 // wrapped in quotes to output as a JSON string.
Roger Meier333bbf32012-01-08 21:51:08 +0000163 procedure WriteJSONInteger( const num : Int64);
Jake Farrell27274222011-11-10 20:32:44 +0000164
165 // Write out a double as a JSON value. If it is NaN or infinity or if the
166 // context dictates escaping, Write out as JSON string.
167 procedure WriteJSONDouble( const num : Double);
168
169 // Write out contents of byte array b as a JSON string with base-64 encoded data
170 procedure WriteJSONBase64( const b : TBytes);
171
172 procedure WriteJSONObjectStart;
173 procedure WriteJSONObjectEnd;
174 procedure WriteJSONArrayStart;
175 procedure WriteJSONArrayEnd;
176
177 public
178 // IProtocol
Jens Geyer17c3ad92017-09-05 20:31:27 +0200179 procedure WriteMessageBegin( const aMsg : TThriftMessage); override;
Jake Farrell27274222011-11-10 20:32:44 +0000180 procedure WriteMessageEnd; override;
Jens Geyer17c3ad92017-09-05 20:31:27 +0200181 procedure WriteStructBegin( const struc: TThriftStruct); override;
Jake Farrell27274222011-11-10 20:32:44 +0000182 procedure WriteStructEnd; override;
Jens Geyer17c3ad92017-09-05 20:31:27 +0200183 procedure WriteFieldBegin( const field: TThriftField); override;
Jake Farrell27274222011-11-10 20:32:44 +0000184 procedure WriteFieldEnd; override;
185 procedure WriteFieldStop; override;
Jens Geyer17c3ad92017-09-05 20:31:27 +0200186 procedure WriteMapBegin( const map: TThriftMap); override;
Jake Farrell27274222011-11-10 20:32:44 +0000187 procedure WriteMapEnd; override;
Jens Geyer17c3ad92017-09-05 20:31:27 +0200188 procedure WriteListBegin( const list: TThriftList); override;
Jake Farrell27274222011-11-10 20:32:44 +0000189 procedure WriteListEnd(); override;
Jens Geyer17c3ad92017-09-05 20:31:27 +0200190 procedure WriteSetBegin( const set_: TThriftSet ); override;
Jake Farrell27274222011-11-10 20:32:44 +0000191 procedure WriteSetEnd(); override;
192 procedure WriteBool( b: Boolean); override;
193 procedure WriteByte( b: ShortInt); override;
194 procedure WriteI16( i16: SmallInt); override;
195 procedure WriteI32( i32: Integer); override;
Roger Meier333bbf32012-01-08 21:51:08 +0000196 procedure WriteI64( const i64: Int64); override;
197 procedure WriteDouble( const d: Double); override;
Jake Farrell27274222011-11-10 20:32:44 +0000198 procedure WriteString( const s: string ); override;
199 procedure WriteBinary( const b: TBytes); override;
200 //
Jens Geyer17c3ad92017-09-05 20:31:27 +0200201 function ReadMessageBegin: TThriftMessage; override;
Jake Farrell27274222011-11-10 20:32:44 +0000202 procedure ReadMessageEnd(); override;
Jens Geyer17c3ad92017-09-05 20:31:27 +0200203 function ReadStructBegin: TThriftStruct; override;
Jake Farrell27274222011-11-10 20:32:44 +0000204 procedure ReadStructEnd; override;
Jens Geyer17c3ad92017-09-05 20:31:27 +0200205 function ReadFieldBegin: TThriftField; override;
Jake Farrell27274222011-11-10 20:32:44 +0000206 procedure ReadFieldEnd(); override;
Jens Geyer17c3ad92017-09-05 20:31:27 +0200207 function ReadMapBegin: TThriftMap; override;
Jake Farrell27274222011-11-10 20:32:44 +0000208 procedure ReadMapEnd(); override;
Jens Geyer17c3ad92017-09-05 20:31:27 +0200209 function ReadListBegin: TThriftList; override;
Jake Farrell27274222011-11-10 20:32:44 +0000210 procedure ReadListEnd(); override;
Jens Geyer17c3ad92017-09-05 20:31:27 +0200211 function ReadSetBegin: TThriftSet; override;
Jake Farrell27274222011-11-10 20:32:44 +0000212 procedure ReadSetEnd(); override;
213 function ReadBool: Boolean; override;
214 function ReadByte: ShortInt; override;
215 function ReadI16: SmallInt; override;
216 function ReadI32: Integer; override;
217 function ReadI64: Int64; override;
218 function ReadDouble:Double; override;
219 function ReadString : string; override;
220 function ReadBinary: TBytes; override;
221
222
Jens Geyerfad7fd32019-11-09 23:24:52 +0100223 strict private
Jake Farrell27274222011-11-10 20:32:44 +0000224 // Reading methods.
225
226 // Read in a JSON string, unescaping as appropriate.
227 // Skip Reading from the context if skipContext is true.
228 function ReadJSONString( skipContext : Boolean) : TBytes;
229
230 // Return true if the given byte could be a valid part of a JSON number.
231 function IsJSONNumeric( b : Byte) : Boolean;
232
233 // Read in a sequence of characters that are all valid in JSON numbers. Does
234 // not do a complete regex check to validate that this is actually a number.
235 function ReadJSONNumericChars : String;
236
237 // Read in a JSON number. If the context dictates, Read in enclosing quotes.
238 function ReadJSONInteger : Int64;
239
240 // Read in a JSON double value. Throw if the value is not wrapped in quotes
241 // when expected or if wrapped in quotes when not expected.
242 function ReadJSONDouble : Double;
243
244 // Read in a JSON string containing base-64 encoded data and decode it.
245 function ReadJSONBase64 : TBytes;
246
247 procedure ReadJSONObjectStart;
248 procedure ReadJSONObjectEnd;
249 procedure ReadJSONArrayStart;
250 procedure ReadJSONArrayEnd;
251 end;
252
253
254implementation
255
256var
257 COMMA : TBytes;
258 COLON : TBytes;
259 LBRACE : TBytes;
260 RBRACE : TBytes;
261 LBRACKET : TBytes;
262 RBRACKET : TBytes;
263 QUOTE : TBytes;
264 BACKSLASH : TBytes;
Jake Farrell27274222011-11-10 20:32:44 +0000265 ESCSEQ : TBytes;
266
267const
268 VERSION = 1;
269 JSON_CHAR_TABLE : array[0..$2F] of Byte
270 = (0,0,0,0, 0,0,0,0, Byte('b'),Byte('t'),Byte('n'),0, Byte('f'),Byte('r'),0,0,
271 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
272 1,1,Byte('"'),1, 1,1,1,1, 1,1,1,1, 1,1,1,1);
273
Jens Geyer21366942013-12-30 22:04:51 +0100274 ESCAPE_CHARS = '"\/btnfr';
275 ESCAPE_CHAR_VALS = '"\/'#8#9#10#12#13;
Jake Farrell27274222011-11-10 20:32:44 +0000276
277 DEF_STRING_SIZE = 16;
278
279 NAME_BOOL = 'tf';
280 NAME_BYTE = 'i8';
281 NAME_I16 = 'i16';
282 NAME_I32 = 'i32';
283 NAME_I64 = 'i64';
284 NAME_DOUBLE = 'dbl';
285 NAME_STRUCT = 'rec';
286 NAME_STRING = 'str';
287 NAME_MAP = 'map';
288 NAME_LIST = 'lst';
289 NAME_SET = 'set';
290
291 INVARIANT_CULTURE : TFormatSettings
292 = ( ThousandSeparator: ',';
293 DecimalSeparator: '.');
294
295
296
297//--- TJSONProtocolImpl ----------------------
298
299
Roger Meier333bbf32012-01-08 21:51:08 +0000300function TJSONProtocolImpl.TFactory.GetProtocol( const trans: ITransport): IProtocol;
Jake Farrell27274222011-11-10 20:32:44 +0000301begin
Jens Geyera019cda2019-11-09 23:24:52 +0100302 result := TJSONProtocolImpl.Create( trans);
Jake Farrell27274222011-11-10 20:32:44 +0000303end;
304
305class function TJSONProtocolImpl.GetTypeNameForTypeID(typeID : TType) : string;
306begin
307 case typeID of
308 TType.Bool_: result := NAME_BOOL;
309 TType.Byte_: result := NAME_BYTE;
310 TType.I16: result := NAME_I16;
311 TType.I32: result := NAME_I32;
312 TType.I64: result := NAME_I64;
313 TType.Double_: result := NAME_DOUBLE;
314 TType.String_: result := NAME_STRING;
315 TType.Struct: result := NAME_STRUCT;
316 TType.Map: result := NAME_MAP;
317 TType.Set_: result := NAME_SET;
318 TType.List: result := NAME_LIST;
319 else
Jens Geyere0e32402016-04-20 21:50:48 +0200320 raise TProtocolExceptionNotImplemented.Create('Unrecognized type ('+IntToStr(Ord(typeID))+')');
Jake Farrell27274222011-11-10 20:32:44 +0000321 end;
322end;
323
324
325class function TJSONProtocolImpl.GetTypeIDForTypeName( const name : string) : TType;
326begin
327 if name = NAME_BOOL then result := TType.Bool_
328 else if name = NAME_BYTE then result := TType.Byte_
329 else if name = NAME_I16 then result := TType.I16
330 else if name = NAME_I32 then result := TType.I32
331 else if name = NAME_I64 then result := TType.I64
332 else if name = NAME_DOUBLE then result := TType.Double_
333 else if name = NAME_STRUCT then result := TType.Struct
334 else if name = NAME_STRING then result := TType.String_
335 else if name = NAME_MAP then result := TType.Map
336 else if name = NAME_LIST then result := TType.List
337 else if name = NAME_SET then result := TType.Set_
Jens Geyere0e32402016-04-20 21:50:48 +0200338 else raise TProtocolExceptionNotImplemented.Create('Unrecognized type ('+name+')');
Jake Farrell27274222011-11-10 20:32:44 +0000339end;
340
341
342constructor TJSONProtocolImpl.TJSONBaseContext.Create( const aProto : IJSONProtocol);
343begin
344 inherited Create;
Roger Meierfebe8452012-06-06 10:32:24 +0000345 FProto := Pointer(aProto);
Jake Farrell27274222011-11-10 20:32:44 +0000346end;
347
348
349procedure TJSONProtocolImpl.TJSONBaseContext.Write;
350begin
351 // nothing
352end;
353
354
355procedure TJSONProtocolImpl.TJSONBaseContext.Read;
356begin
357 // nothing
358end;
359
360
361function TJSONProtocolImpl.TJSONBaseContext.EscapeNumbers : Boolean;
362begin
363 result := FALSE;
364end;
365
366
367constructor TJSONProtocolImpl.TJSONListContext.Create( const aProto : IJSONProtocol);
368begin
369 inherited Create( aProto);
370 FFirst := TRUE;
371end;
372
373
374procedure TJSONProtocolImpl.TJSONListContext.Write;
375begin
376 if FFirst
377 then FFirst := FALSE
Roger Meierfebe8452012-06-06 10:32:24 +0000378 else IJSONProtocol(FProto).Transport.Write( COMMA);
Jake Farrell27274222011-11-10 20:32:44 +0000379end;
380
381
382procedure TJSONProtocolImpl.TJSONListContext.Read;
383begin
384 if FFirst
385 then FFirst := FALSE
Roger Meierfebe8452012-06-06 10:32:24 +0000386 else IJSONProtocol(FProto).ReadJSONSyntaxChar( COMMA[0]);
Jake Farrell27274222011-11-10 20:32:44 +0000387end;
388
389
390constructor TJSONProtocolImpl.TJSONPairContext.Create( const aProto : IJSONProtocol);
391begin
392 inherited Create( aProto);
393 FFirst := TRUE;
394 FColon := TRUE;
395end;
396
397
398procedure TJSONProtocolImpl.TJSONPairContext.Write;
399begin
400 if FFirst then begin
401 FFirst := FALSE;
402 FColon := TRUE;
403 end
404 else begin
405 if FColon
Roger Meierfebe8452012-06-06 10:32:24 +0000406 then IJSONProtocol(FProto).Transport.Write( COLON)
407 else IJSONProtocol(FProto).Transport.Write( COMMA);
Jake Farrell27274222011-11-10 20:32:44 +0000408 FColon := not FColon;
409 end;
410end;
411
412
413procedure TJSONProtocolImpl.TJSONPairContext.Read;
414begin
415 if FFirst then begin
416 FFirst := FALSE;
417 FColon := TRUE;
418 end
419 else begin
420 if FColon
Roger Meierfebe8452012-06-06 10:32:24 +0000421 then IJSONProtocol(FProto).ReadJSONSyntaxChar( COLON[0])
422 else IJSONProtocol(FProto).ReadJSONSyntaxChar( COMMA[0]);
Jake Farrell27274222011-11-10 20:32:44 +0000423 FColon := not FColon;
424 end;
425end;
426
427
428function TJSONProtocolImpl.TJSONPairContext.EscapeNumbers : Boolean;
429begin
430 result := FColon;
431end;
432
433
434constructor TJSONProtocolImpl.TLookaheadReader.Create( const aProto : IJSONProtocol);
435begin
436 inherited Create;
Roger Meierfebe8452012-06-06 10:32:24 +0000437 FProto := Pointer(aProto);
Jake Farrell27274222011-11-10 20:32:44 +0000438 FHasData := FALSE;
439end;
440
441
442function TJSONProtocolImpl.TLookaheadReader.Read : Byte;
443begin
444 if FHasData
445 then FHasData := FALSE
446 else begin
Jens Geyer17c3ad92017-09-05 20:31:27 +0200447 IJSONProtocol(FProto).Transport.ReadAll( @FData, SizeOf(FData), 0, 1);
Jake Farrell27274222011-11-10 20:32:44 +0000448 end;
Jens Geyer17c3ad92017-09-05 20:31:27 +0200449 result := FData;
Jake Farrell27274222011-11-10 20:32:44 +0000450end;
451
452
453function TJSONProtocolImpl.TLookaheadReader.Peek : Byte;
454begin
455 if not FHasData then begin
Jens Geyer17c3ad92017-09-05 20:31:27 +0200456 IJSONProtocol(FProto).Transport.ReadAll( @FData, SizeOf(FData), 0, 1);
Jake Farrell27274222011-11-10 20:32:44 +0000457 FHasData := TRUE;
458 end;
Jens Geyer17c3ad92017-09-05 20:31:27 +0200459 result := FData;
Jake Farrell27274222011-11-10 20:32:44 +0000460end;
461
462
Roger Meier333bbf32012-01-08 21:51:08 +0000463constructor TJSONProtocolImpl.Create( const aTrans : ITransport);
Jake Farrell27274222011-11-10 20:32:44 +0000464begin
465 inherited Create( aTrans);
466
467 // Stack of nested contexts that we may be in
468 FContextStack := TStack<TJSONBaseContext>.Create;
469
470 FContext := TJSONBaseContext.Create( Self);
471 FReader := TLookaheadReader.Create( Self);
472end;
473
474
475destructor TJSONProtocolImpl.Destroy;
476begin
477 try
Roger Meier45a37262012-01-08 21:44:44 +0000478 ResetContextStack; // free any contents
Jake Farrell27274222011-11-10 20:32:44 +0000479 FreeAndNil( FReader);
480 FreeAndNil( FContext);
481 FreeAndNil( FContextStack);
482 finally
483 inherited Destroy;
484 end;
485end;
486
487
Jens Geyer41f47af2019-11-09 23:24:52 +0100488procedure TJSONProtocolImpl.Reset;
489begin
490 inherited Reset;
491 ResetContextStack;
492end;
493
494
Roger Meier45a37262012-01-08 21:44:44 +0000495procedure TJSONProtocolImpl.ResetContextStack;
496begin
497 while FContextStack.Count > 0
498 do PopContext;
499end;
500
501
Roger Meier333bbf32012-01-08 21:51:08 +0000502procedure TJSONProtocolImpl.PushContext( const aCtx : TJSONBaseContext);
Roger Meier45a37262012-01-08 21:44:44 +0000503begin
504 FContextStack.Push( FContext);
505 FContext := aCtx;
506end;
507
508
509procedure TJSONProtocolImpl.PopContext;
510begin
511 FreeAndNil(FContext);
512 FContext := FContextStack.Pop;
513end;
514
515
Jake Farrell27274222011-11-10 20:32:44 +0000516procedure TJSONProtocolImpl.ReadJSONSyntaxChar( b : Byte);
517var ch : Byte;
518begin
519 ch := FReader.Read;
520 if (ch <> b)
Jens Geyere0e32402016-04-20 21:50:48 +0200521 then raise TProtocolExceptionInvalidData.Create('Unexpected character ('+Char(ch)+')');
Jake Farrell27274222011-11-10 20:32:44 +0000522end;
523
524
525class function TJSONProtocolImpl.HexVal( ch : Byte) : Byte;
526var i : Integer;
527begin
528 i := StrToIntDef( '$0'+Char(ch), -1);
529 if (0 <= i) and (i < $10)
530 then result := i
Jens Geyere0e32402016-04-20 21:50:48 +0200531 else raise TProtocolExceptionInvalidData.Create('Expected hex character ('+Char(ch)+')');
Jake Farrell27274222011-11-10 20:32:44 +0000532end;
533
534
535class function TJSONProtocolImpl.HexChar( val : Byte) : Byte;
536const HEXCHARS = '0123456789ABCDEF';
537begin
538 result := Byte( PChar(HEXCHARS)[val and $0F]);
539 ASSERT( Pos( Char(result), HEXCHARS) > 0);
540end;
541
542
Roger Meier333bbf32012-01-08 21:51:08 +0000543procedure TJSONProtocolImpl.WriteJSONString( const str : string);
Jake Farrell27274222011-11-10 20:32:44 +0000544begin
545 WriteJSONString( SysUtils.TEncoding.UTF8.GetBytes( str));
546end;
547
548
549procedure TJSONProtocolImpl.WriteJSONString( const b : TBytes);
550var i : Integer;
551 tmp : TBytes;
552begin
553 FContext.Write;
554 Transport.Write( QUOTE);
555 for i := 0 to Length(b)-1 do begin
556
557 if (b[i] and $00FF) >= $30 then begin
558
559 if (b[i] = BACKSLASH[0]) then begin
560 Transport.Write( BACKSLASH);
561 Transport.Write( BACKSLASH);
562 end
563 else begin
564 Transport.Write( b, i, 1);
565 end;
566
567 end
568 else begin
569 SetLength( tmp, 2);
570 tmp[0] := JSON_CHAR_TABLE[b[i]];
571 if (tmp[0] = 1) then begin
572 Transport.Write( b, i, 1)
573 end
574 else if (tmp[0] > 1) then begin
575 Transport.Write( BACKSLASH);
576 Transport.Write( tmp, 0, 1);
577 end
578 else begin
579 Transport.Write( ESCSEQ);
580 tmp[0] := HexChar( b[i] div $10);
581 tmp[1] := HexChar( b[i]);
582 Transport.Write( tmp, 0, 2);
583 end;
584 end;
585 end;
586 Transport.Write( QUOTE);
587end;
588
589
Roger Meier333bbf32012-01-08 21:51:08 +0000590procedure TJSONProtocolImpl.WriteJSONInteger( const num : Int64);
Jake Farrell27274222011-11-10 20:32:44 +0000591var str : String;
592 escapeNum : Boolean;
593begin
594 FContext.Write;
595 str := IntToStr(num);
596
597 escapeNum := FContext.EscapeNumbers;
598 if escapeNum
599 then Transport.Write( QUOTE);
600
601 Transport.Write( SysUtils.TEncoding.UTF8.GetBytes( str));
602
603 if escapeNum
604 then Transport.Write( QUOTE);
605end;
606
607
608procedure TJSONProtocolImpl.WriteJSONDouble( const num : Double);
609var str : string;
610 special : Boolean;
611 escapeNum : Boolean;
612begin
613 FContext.Write;
614
615 str := FloatToStr( num, INVARIANT_CULTURE);
616 special := FALSE;
617
618 case UpCase(str[1]) of
619 'N' : special := TRUE; // NaN
620 'I' : special := TRUE; // Infinity
621 '-' : special := (UpCase(str[2]) = 'I'); // -Infinity
622 end;
623
624 escapeNum := special or FContext.EscapeNumbers;
625
626
627 if escapeNum
628 then Transport.Write( QUOTE);
629
630 Transport.Write( SysUtils.TEncoding.UTF8.GetBytes( str));
631
632 if escapeNum
633 then Transport.Write( QUOTE);
634end;
635
636
637procedure TJSONProtocolImpl.WriteJSONBase64( const b : TBytes);
Jens Geyerd8bddbc2014-12-14 00:41:33 +0100638var len, off, cnt : Integer;
639 tmpBuf : TBytes;
Jake Farrell27274222011-11-10 20:32:44 +0000640begin
641 FContext.Write;
642 Transport.Write( QUOTE);
643
Jens Geyerd8bddbc2014-12-14 00:41:33 +0100644 len := Length(b);
645 off := 0;
646 SetLength( tmpBuf, 4);
647
648 while len >= 3 do begin
649 // Encode 3 bytes at a time
650 Base64Utils.Encode( b, off, 3, tmpBuf, 0);
651 Transport.Write( tmpBuf, 0, 4);
652 Inc( off, 3);
653 Dec( len, 3);
Jake Farrell27274222011-11-10 20:32:44 +0000654 end;
Jens Geyerd8bddbc2014-12-14 00:41:33 +0100655
656 // Encode remainder, if any
657 if len > 0 then begin
658 cnt := Base64Utils.Encode( b, off, len, tmpBuf, 0);
659 Transport.Write( tmpBuf, 0, cnt);
660 end;
Jake Farrell27274222011-11-10 20:32:44 +0000661
662 Transport.Write( QUOTE);
663end;
664
665
666procedure TJSONProtocolImpl.WriteJSONObjectStart;
667begin
668 FContext.Write;
669 Transport.Write( LBRACE);
670 PushContext( TJSONPairContext.Create( Self));
671end;
672
673
674procedure TJSONProtocolImpl.WriteJSONObjectEnd;
675begin
676 PopContext;
677 Transport.Write( RBRACE);
678end;
679
680
681procedure TJSONProtocolImpl.WriteJSONArrayStart;
682begin
683 FContext.Write;
684 Transport.Write( LBRACKET);
685 PushContext( TJSONListContext.Create( Self));
686end;
687
688
689procedure TJSONProtocolImpl.WriteJSONArrayEnd;
690begin
691 PopContext;
692 Transport.Write( RBRACKET);
693end;
694
695
Jens Geyer17c3ad92017-09-05 20:31:27 +0200696procedure TJSONProtocolImpl.WriteMessageBegin( const aMsg : TThriftMessage);
Jake Farrell27274222011-11-10 20:32:44 +0000697begin
Jens Geyer41f47af2019-11-09 23:24:52 +0100698 Reset;
Roger Meier45a37262012-01-08 21:44:44 +0000699 ResetContextStack; // THRIFT-1473
700
Jake Farrell27274222011-11-10 20:32:44 +0000701 WriteJSONArrayStart;
702 WriteJSONInteger(VERSION);
703
704 WriteJSONString( SysUtils.TEncoding.UTF8.GetBytes( aMsg.Name));
705
706 WriteJSONInteger( LongInt( aMsg.Type_));
707 WriteJSONInteger( aMsg.SeqID);
708end;
709
710procedure TJSONProtocolImpl.WriteMessageEnd;
711begin
712 WriteJSONArrayEnd;
713end;
714
715
Jens Geyer17c3ad92017-09-05 20:31:27 +0200716procedure TJSONProtocolImpl.WriteStructBegin( const struc: TThriftStruct);
Jake Farrell27274222011-11-10 20:32:44 +0000717begin
718 WriteJSONObjectStart;
719end;
720
721
722procedure TJSONProtocolImpl.WriteStructEnd;
723begin
724 WriteJSONObjectEnd;
725end;
726
727
Jens Geyer17c3ad92017-09-05 20:31:27 +0200728procedure TJSONProtocolImpl.WriteFieldBegin( const field : TThriftField);
Jake Farrell27274222011-11-10 20:32:44 +0000729begin
730 WriteJSONInteger(field.ID);
731 WriteJSONObjectStart;
732 WriteJSONString( GetTypeNameForTypeID(field.Type_));
733end;
734
735
736procedure TJSONProtocolImpl.WriteFieldEnd;
737begin
738 WriteJSONObjectEnd;
739end;
740
741
742procedure TJSONProtocolImpl.WriteFieldStop;
743begin
744 // nothing to do
745end;
746
Jens Geyer17c3ad92017-09-05 20:31:27 +0200747procedure TJSONProtocolImpl.WriteMapBegin( const map: TThriftMap);
Jake Farrell27274222011-11-10 20:32:44 +0000748begin
749 WriteJSONArrayStart;
750 WriteJSONString( GetTypeNameForTypeID( map.KeyType));
751 WriteJSONString( GetTypeNameForTypeID( map.ValueType));
752 WriteJSONInteger( map.Count);
753 WriteJSONObjectStart;
754end;
755
756
757procedure TJSONProtocolImpl.WriteMapEnd;
758begin
759 WriteJSONObjectEnd;
760 WriteJSONArrayEnd;
761end;
762
763
Jens Geyer17c3ad92017-09-05 20:31:27 +0200764procedure TJSONProtocolImpl.WriteListBegin( const list: TThriftList);
Jake Farrell27274222011-11-10 20:32:44 +0000765begin
766 WriteJSONArrayStart;
767 WriteJSONString( GetTypeNameForTypeID( list.ElementType));
768 WriteJSONInteger(list.Count);
769end;
770
771
772procedure TJSONProtocolImpl.WriteListEnd;
773begin
774 WriteJSONArrayEnd;
775end;
776
777
Jens Geyer17c3ad92017-09-05 20:31:27 +0200778procedure TJSONProtocolImpl.WriteSetBegin( const set_: TThriftSet);
Jake Farrell27274222011-11-10 20:32:44 +0000779begin
780 WriteJSONArrayStart;
781 WriteJSONString( GetTypeNameForTypeID( set_.ElementType));
782 WriteJSONInteger( set_.Count);
783end;
784
785
786procedure TJSONProtocolImpl.WriteSetEnd;
787begin
788 WriteJSONArrayEnd;
789end;
790
791procedure TJSONProtocolImpl.WriteBool( b: Boolean);
792begin
793 if b
794 then WriteJSONInteger( 1)
795 else WriteJSONInteger( 0);
796end;
797
798procedure TJSONProtocolImpl.WriteByte( b: ShortInt);
799begin
800 WriteJSONInteger( b);
801end;
802
803procedure TJSONProtocolImpl.WriteI16( i16: SmallInt);
804begin
805 WriteJSONInteger( i16);
806end;
807
808procedure TJSONProtocolImpl.WriteI32( i32: Integer);
809begin
810 WriteJSONInteger( i32);
811end;
812
Roger Meier333bbf32012-01-08 21:51:08 +0000813procedure TJSONProtocolImpl.WriteI64( const i64: Int64);
Jake Farrell27274222011-11-10 20:32:44 +0000814begin
815 WriteJSONInteger(i64);
816end;
817
Roger Meier333bbf32012-01-08 21:51:08 +0000818procedure TJSONProtocolImpl.WriteDouble( const d: Double);
Jake Farrell27274222011-11-10 20:32:44 +0000819begin
820 WriteJSONDouble( d);
821end;
822
823procedure TJSONProtocolImpl.WriteString( const s: string );
824begin
825 WriteJSONString( SysUtils.TEncoding.UTF8.GetBytes( s));
826end;
827
828procedure TJSONProtocolImpl.WriteBinary( const b: TBytes);
829begin
830 WriteJSONBase64( b);
831end;
832
833
834function TJSONProtocolImpl.ReadJSONString( skipContext : Boolean) : TBytes;
835var buffer : TMemoryStream;
Jens Geyer7bb44a32014-02-07 22:24:37 +0100836 ch : Byte;
837 wch : Word;
Phongphan Phutthaa6509f72015-10-31 01:09:47 +0700838 highSurogate: Char;
839 surrogatePairs: Array[0..1] of Char;
Jake Farrell27274222011-11-10 20:32:44 +0000840 off : Integer;
841 tmp : TBytes;
842begin
Phongphan Phutthaa6509f72015-10-31 01:09:47 +0700843 highSurogate := #0;
Jake Farrell27274222011-11-10 20:32:44 +0000844 buffer := TMemoryStream.Create;
845 try
846 if not skipContext
847 then FContext.Read;
848
849 ReadJSONSyntaxChar( QUOTE[0]);
850
851 while TRUE do begin
852 ch := FReader.Read;
853
854 if (ch = QUOTE[0])
855 then Break;
856
Jens Geyer7bb44a32014-02-07 22:24:37 +0100857 // check for escapes
858 if (ch <> ESCSEQ[0]) then begin
859 buffer.Write( ch, 1);
860 Continue;
Jake Farrell27274222011-11-10 20:32:44 +0000861 end;
Jens Geyer7bb44a32014-02-07 22:24:37 +0100862
863 // distuinguish between \uNNNN and \?
864 ch := FReader.Read;
865 if (ch <> ESCSEQ[1])
866 then begin
867 off := Pos( Char(ch), ESCAPE_CHARS);
868 if off < 1
Jens Geyere0e32402016-04-20 21:50:48 +0200869 then raise TProtocolExceptionInvalidData.Create('Expected control char');
Jens Geyer7bb44a32014-02-07 22:24:37 +0100870 ch := Byte( ESCAPE_CHAR_VALS[off]);
871 buffer.Write( ch, 1);
872 Continue;
873 end;
874
875 // it is \uXXXX
876 SetLength( tmp, 4);
877 Transport.ReadAll( tmp, 0, 4);
878 wch := (HexVal(tmp[0]) shl 12)
879 + (HexVal(tmp[1]) shl 8)
880 + (HexVal(tmp[2]) shl 4)
881 + HexVal(tmp[3]);
Phongphan Phutthaa6509f72015-10-31 01:09:47 +0700882
Jens Geyer7bb44a32014-02-07 22:24:37 +0100883 // we need to make UTF8 bytes from it, to be decoded later
Jens Geyer71070432016-01-29 10:08:39 +0100884 if CharUtils.IsHighSurrogate(char(wch)) then begin
Phongphan Phutthaa6509f72015-10-31 01:09:47 +0700885 if highSurogate <> #0
Jens Geyere0e32402016-04-20 21:50:48 +0200886 then raise TProtocolExceptionInvalidData.Create('Expected low surrogate char');
Phongphan Phutthaa6509f72015-10-31 01:09:47 +0700887 highSurogate := char(wch);
888 end
Jens Geyer71070432016-01-29 10:08:39 +0100889 else if CharUtils.IsLowSurrogate(char(wch)) then begin
Phongphan Phutthaa6509f72015-10-31 01:09:47 +0700890 if highSurogate = #0
Jens Geyere0e32402016-04-20 21:50:48 +0200891 then TProtocolExceptionInvalidData.Create('Expected high surrogate char');
Phongphan Phutthaa6509f72015-10-31 01:09:47 +0700892 surrogatePairs[0] := highSurogate;
893 surrogatePairs[1] := char(wch);
894 tmp := TEncoding.UTF8.GetBytes(surrogatePairs);
895 buffer.Write( tmp[0], Length(tmp));
896 highSurogate := #0;
897 end
898 else begin
899 tmp := SysUtils.TEncoding.UTF8.GetBytes(Char(wch));
900 buffer.Write( tmp[0], Length(tmp));
901 end;
Jake Farrell27274222011-11-10 20:32:44 +0000902 end;
903
Phongphan Phutthaa6509f72015-10-31 01:09:47 +0700904 if highSurogate <> #0
Jens Geyere0e32402016-04-20 21:50:48 +0200905 then raise TProtocolExceptionInvalidData.Create('Expected low surrogate char');
Phongphan Phutthaa6509f72015-10-31 01:09:47 +0700906
Jake Farrell27274222011-11-10 20:32:44 +0000907 SetLength( result, buffer.Size);
Jake Farrella2a9ee92011-12-15 20:50:31 +0000908 if buffer.Size > 0 then Move( buffer.Memory^, result[0], Length(result));
Jake Farrell27274222011-11-10 20:32:44 +0000909
910 finally
911 buffer.Free;
912 end;
913end;
914
915
916function TJSONProtocolImpl.IsJSONNumeric( b : Byte) : Boolean;
917const NUMCHARS = ['+','-','.','0','1','2','3','4','5','6','7','8','9','E','e'];
918begin
919 result := CharInSet( Char(b), NUMCHARS);
920end;
921
922
923function TJSONProtocolImpl.ReadJSONNumericChars : string;
924var strbld : TThriftStringBuilder;
925 ch : Byte;
926begin
927 strbld := TThriftStringBuilder.Create;
928 try
929 while TRUE do begin
930 ch := FReader.Peek;
931 if IsJSONNumeric(ch)
932 then strbld.Append( Char(FReader.Read))
933 else Break;
934 end;
935 result := strbld.ToString;
936
937 finally
938 strbld.Free;
939 end;
940end;
941
942
943function TJSONProtocolImpl.ReadJSONInteger : Int64;
944var str : string;
945begin
946 FContext.Read;
947 if FContext.EscapeNumbers
948 then ReadJSONSyntaxChar( QUOTE[0]);
949
950 str := ReadJSONNumericChars;
951
952 if FContext.EscapeNumbers
953 then ReadJSONSyntaxChar( QUOTE[0]);
954
955 try
956 result := StrToInt64(str);
957 except
958 on e:Exception do begin
Jens Geyere0e32402016-04-20 21:50:48 +0200959 raise TProtocolExceptionInvalidData.Create('Bad data encounted in numeric data ('+str+') ('+e.Message+')');
Jake Farrell27274222011-11-10 20:32:44 +0000960 end;
961 end;
962end;
963
964
965function TJSONProtocolImpl.ReadJSONDouble : Double;
966var dub : Double;
967 str : string;
968begin
969 FContext.Read;
970
971 if FReader.Peek = QUOTE[0]
972 then begin
973 str := SysUtils.TEncoding.UTF8.GetString( ReadJSONString( TRUE));
974 dub := StrToFloat( str, INVARIANT_CULTURE);
975
976 if not FContext.EscapeNumbers()
977 and not Math.IsNaN(dub)
978 and not Math.IsInfinite(dub)
979 then begin
980 // Throw exception -- we should not be in a string in Self case
Jens Geyere0e32402016-04-20 21:50:48 +0200981 raise TProtocolExceptionInvalidData.Create('Numeric data unexpectedly quoted');
Jake Farrell27274222011-11-10 20:32:44 +0000982 end;
983 result := dub;
984 Exit;
985 end;
986
987 // will throw - we should have had a quote if escapeNum == true
988 if FContext.EscapeNumbers
989 then ReadJSONSyntaxChar( QUOTE[0]);
990
991 try
992 str := ReadJSONNumericChars;
993 result := StrToFloat( str, INVARIANT_CULTURE);
994 except
995 on e:Exception
Jens Geyere0e32402016-04-20 21:50:48 +0200996 do raise TProtocolExceptionInvalidData.Create('Bad data encounted in numeric data ('+str+') ('+e.Message+')');
Jake Farrell27274222011-11-10 20:32:44 +0000997 end;
998end;
999
1000
1001function TJSONProtocolImpl.ReadJSONBase64 : TBytes;
1002var b : TBytes;
Jens Geyer9f9535c2014-12-14 04:16:05 +01001003 len, off, size : Integer;
Jake Farrell27274222011-11-10 20:32:44 +00001004begin
1005 b := ReadJSONString(false);
1006
Jens Geyerd8bddbc2014-12-14 00:41:33 +01001007 len := Length(b);
1008 off := 0;
1009 size := 0;
1010
1011 // reduce len to ignore fill bytes
1012 Dec(len);
1013 while (len >= 0) and (b[len] = Byte('=')) do Dec(len);
1014 Inc(len);
1015
1016 // read & decode full byte triplets = 4 source bytes
1017 while (len >= 4) do begin
1018 // Decode 4 bytes at a time
1019 Inc( size, Base64Utils.Decode( b, off, 4, b, size)); // decoded in place
1020 Inc( off, 4);
1021 Dec( len, 4);
1022 end;
1023
1024 // Don't decode if we hit the end or got a single leftover byte (invalid
1025 // base64 but legal for skip of regular string type)
1026 if len > 1 then begin
1027 // Decode remainder
1028 Inc( size, Base64Utils.Decode( b, off, len, b, size)); // decoded in place
1029 end;
1030
1031 // resize to final size and return the data
1032 SetLength( b, size);
1033 result := b;
Jake Farrell27274222011-11-10 20:32:44 +00001034end;
1035
1036
1037procedure TJSONProtocolImpl.ReadJSONObjectStart;
1038begin
1039 FContext.Read;
1040 ReadJSONSyntaxChar( LBRACE[0]);
1041 PushContext( TJSONPairContext.Create( Self));
1042end;
1043
1044
1045procedure TJSONProtocolImpl.ReadJSONObjectEnd;
1046begin
1047 ReadJSONSyntaxChar( RBRACE[0]);
1048 PopContext;
1049end;
1050
1051
1052procedure TJSONProtocolImpl.ReadJSONArrayStart;
1053begin
1054 FContext.Read;
1055 ReadJSONSyntaxChar( LBRACKET[0]);
1056 PushContext( TJSONListContext.Create( Self));
1057end;
1058
1059
1060procedure TJSONProtocolImpl.ReadJSONArrayEnd;
1061begin
1062 ReadJSONSyntaxChar( RBRACKET[0]);
1063 PopContext;
1064end;
1065
1066
Jens Geyer17c3ad92017-09-05 20:31:27 +02001067function TJSONProtocolImpl.ReadMessageBegin: TThriftMessage;
Jake Farrell27274222011-11-10 20:32:44 +00001068begin
Jens Geyer41f47af2019-11-09 23:24:52 +01001069 Reset;
Roger Meier45a37262012-01-08 21:44:44 +00001070 ResetContextStack; // THRIFT-1473
1071
Jens Geyer17c3ad92017-09-05 20:31:27 +02001072 Init( result);
Jake Farrell27274222011-11-10 20:32:44 +00001073 ReadJSONArrayStart;
1074
1075 if ReadJSONInteger <> VERSION
Jens Geyere0e32402016-04-20 21:50:48 +02001076 then raise TProtocolExceptionBadVersion.Create('Message contained bad version.');
Jake Farrell27274222011-11-10 20:32:44 +00001077
1078 result.Name := SysUtils.TEncoding.UTF8.GetString( ReadJSONString( FALSE));
1079 result.Type_ := TMessageType( ReadJSONInteger);
1080 result.SeqID := ReadJSONInteger;
1081end;
1082
1083
1084procedure TJSONProtocolImpl.ReadMessageEnd;
1085begin
1086 ReadJSONArrayEnd;
1087end;
1088
1089
Jens Geyer17c3ad92017-09-05 20:31:27 +02001090function TJSONProtocolImpl.ReadStructBegin : TThriftStruct ;
Jake Farrell27274222011-11-10 20:32:44 +00001091begin
1092 ReadJSONObjectStart;
Jens Geyer17c3ad92017-09-05 20:31:27 +02001093 Init( result);
Jake Farrell27274222011-11-10 20:32:44 +00001094end;
1095
1096
1097procedure TJSONProtocolImpl.ReadStructEnd;
1098begin
1099 ReadJSONObjectEnd;
1100end;
1101
1102
Jens Geyer17c3ad92017-09-05 20:31:27 +02001103function TJSONProtocolImpl.ReadFieldBegin : TThriftField;
Jake Farrell27274222011-11-10 20:32:44 +00001104var ch : Byte;
1105 str : string;
1106begin
Jens Geyer17c3ad92017-09-05 20:31:27 +02001107 Init( result);
Jake Farrell27274222011-11-10 20:32:44 +00001108 ch := FReader.Peek;
1109 if ch = RBRACE[0]
1110 then result.Type_ := TType.Stop
1111 else begin
1112 result.ID := ReadJSONInteger;
1113 ReadJSONObjectStart;
1114
1115 str := SysUtils.TEncoding.UTF8.GetString( ReadJSONString( FALSE));
1116 result.Type_ := GetTypeIDForTypeName( str);
1117 end;
1118end;
1119
1120
1121procedure TJSONProtocolImpl.ReadFieldEnd;
1122begin
1123 ReadJSONObjectEnd;
1124end;
1125
1126
Jens Geyer17c3ad92017-09-05 20:31:27 +02001127function TJSONProtocolImpl.ReadMapBegin : TThriftMap;
Jake Farrell27274222011-11-10 20:32:44 +00001128var str : string;
1129begin
Jens Geyer17c3ad92017-09-05 20:31:27 +02001130 Init( result);
Jake Farrell27274222011-11-10 20:32:44 +00001131 ReadJSONArrayStart;
1132
1133 str := SysUtils.TEncoding.UTF8.GetString( ReadJSONString(FALSE));
1134 result.KeyType := GetTypeIDForTypeName( str);
1135
1136 str := SysUtils.TEncoding.UTF8.GetString( ReadJSONString(FALSE));
1137 result.ValueType := GetTypeIDForTypeName( str);
1138
1139 result.Count := ReadJSONInteger;
Jens Geyer41f47af2019-11-09 23:24:52 +01001140 CheckReadBytesAvailable(result);
1141
Jake Farrell27274222011-11-10 20:32:44 +00001142 ReadJSONObjectStart;
1143end;
1144
1145
1146procedure TJSONProtocolImpl.ReadMapEnd;
1147begin
1148 ReadJSONObjectEnd;
1149 ReadJSONArrayEnd;
1150end;
1151
1152
Jens Geyer17c3ad92017-09-05 20:31:27 +02001153function TJSONProtocolImpl.ReadListBegin : TThriftList;
Jake Farrell27274222011-11-10 20:32:44 +00001154var str : string;
1155begin
Jens Geyer17c3ad92017-09-05 20:31:27 +02001156 Init( result);
Jake Farrell27274222011-11-10 20:32:44 +00001157 ReadJSONArrayStart;
1158
1159 str := SysUtils.TEncoding.UTF8.GetString( ReadJSONString(FALSE));
1160 result.ElementType := GetTypeIDForTypeName( str);
1161 result.Count := ReadJSONInteger;
Jens Geyer41f47af2019-11-09 23:24:52 +01001162 CheckReadBytesAvailable(result);
Jake Farrell27274222011-11-10 20:32:44 +00001163end;
1164
1165
1166procedure TJSONProtocolImpl.ReadListEnd;
1167begin
1168 ReadJSONArrayEnd;
1169end;
1170
1171
Jens Geyer17c3ad92017-09-05 20:31:27 +02001172function TJSONProtocolImpl.ReadSetBegin : TThriftSet;
Jake Farrell27274222011-11-10 20:32:44 +00001173var str : string;
1174begin
Jens Geyer17c3ad92017-09-05 20:31:27 +02001175 Init( result);
Jake Farrell27274222011-11-10 20:32:44 +00001176 ReadJSONArrayStart;
1177
1178 str := SysUtils.TEncoding.UTF8.GetString( ReadJSONString(FALSE));
1179 result.ElementType := GetTypeIDForTypeName( str);
1180 result.Count := ReadJSONInteger;
Jens Geyer41f47af2019-11-09 23:24:52 +01001181 CheckReadBytesAvailable(result);
Jake Farrell27274222011-11-10 20:32:44 +00001182end;
1183
1184
1185procedure TJSONProtocolImpl.ReadSetEnd;
1186begin
1187 ReadJSONArrayEnd;
1188end;
1189
1190
1191function TJSONProtocolImpl.ReadBool : Boolean;
1192begin
1193 result := (ReadJSONInteger <> 0);
1194end;
1195
1196
1197function TJSONProtocolImpl.ReadByte : ShortInt;
1198begin
1199 result := ReadJSONInteger;
1200end;
1201
1202
1203function TJSONProtocolImpl.ReadI16 : SmallInt;
1204begin
1205 result := ReadJSONInteger;
1206end;
1207
1208
1209function TJSONProtocolImpl.ReadI32 : LongInt;
1210begin
1211 result := ReadJSONInteger;
1212end;
1213
1214
1215function TJSONProtocolImpl.ReadI64 : Int64;
1216begin
1217 result := ReadJSONInteger;
1218end;
1219
1220
1221function TJSONProtocolImpl.ReadDouble : Double;
1222begin
1223 result := ReadJSONDouble;
1224end;
1225
1226
1227function TJSONProtocolImpl.ReadString : string;
1228begin
1229 result := SysUtils.TEncoding.UTF8.GetString( ReadJSONString( FALSE));
1230end;
1231
1232
1233function TJSONProtocolImpl.ReadBinary : TBytes;
1234begin
1235 result := ReadJSONBase64;
1236end;
1237
1238
Jens Geyer41f47af2019-11-09 23:24:52 +01001239function TJSONProtocolImpl.GetMinSerializedSize( const aType : TType) : Integer;
1240// Return the minimum number of bytes a type will consume on the wire
1241begin
1242 case aType of
1243 TType.Stop: result := 0;
1244 TType.Void: result := 0;
1245 TType.Bool_: result := 1;
1246 TType.Byte_: result := 1;
1247 TType.Double_: result := 1;
1248 TType.I16: result := 1;
1249 TType.I32: result := 1;
1250 TType.I64: result := 1;
1251 TType.String_: result := 2; // empty string
1252 TType.Struct: result := 2; // empty struct
1253 TType.Map: result := 2; // empty map
1254 TType.Set_: result := 2; // empty set
1255 TType.List: result := 2; // empty list
1256 else
1257 raise TTransportExceptionBadArgs.Create('Unhandled type code');
1258 end;
1259end;
1260
1261
1262
Jake Farrell27274222011-11-10 20:32:44 +00001263//--- init code ---
1264
1265procedure InitBytes( var b : TBytes; aData : array of Byte);
1266begin
1267 SetLength( b, Length(aData));
1268 Move( aData, b[0], Length(b));
1269end;
1270
1271initialization
1272 InitBytes( COMMA, [Byte(',')]);
1273 InitBytes( COLON, [Byte(':')]);
1274 InitBytes( LBRACE, [Byte('{')]);
1275 InitBytes( RBRACE, [Byte('}')]);
1276 InitBytes( LBRACKET, [Byte('[')]);
1277 InitBytes( RBRACKET, [Byte(']')]);
1278 InitBytes( QUOTE, [Byte('"')]);
1279 InitBytes( BACKSLASH, [Byte('\')]);
Jake Farrell27274222011-11-10 20:32:44 +00001280 InitBytes( ESCSEQ, [Byte('\'),Byte('u'),Byte('0'),Byte('0')]);
1281end.