blob: e72a81dcf90f8af4bfc2d9082cfabe98c27f9788 [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,
32 Thrift.Transport,
Jens Geyerd8bddbc2014-12-14 00:41:33 +010033 Thrift.Protocol,
34 Thrift.Utils;
Jake Farrell27274222011-11-10 20:32:44 +000035
36type
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);
41 end;
42
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)
48 public
49 type
50 TFactory = class( TInterfacedObject, IProtocolFactory)
51 public
Roger Meier333bbf32012-01-08 21:51:08 +000052 function GetProtocol( const trans: ITransport): IProtocol;
Jake Farrell27274222011-11-10 20:32:44 +000053 end;
54
Jens Geyerfad7fd32019-11-09 23:24:52 +010055 strict private
Jake Farrell27274222011-11-10 20:32:44 +000056 class function GetTypeNameForTypeID(typeID : TType) : string;
57 class function GetTypeIDForTypeName( const name : string) : TType;
58
Jens Geyerfad7fd32019-11-09 23:24:52 +010059 strict protected
Jake Farrell27274222011-11-10 20:32:44 +000060 type
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
Jens Geyerfad7fd32019-11-09 23:24:52 +010065 strict protected
Roger Meierfebe8452012-06-06 10:32:24 +000066 FProto : Pointer; // weak IJSONProtocol;
Jake Farrell27274222011-11-10 20:32:44 +000067 public
68 constructor Create( const aProto : IJSONProtocol);
69 procedure Write; virtual;
70 procedure Read; virtual;
71 function EscapeNumbers : Boolean; virtual;
72 end;
73
74 // Context for JSON lists.
75 // Will insert/Read commas before each item except for the first one.
76 TJSONListContext = class( TJSONBaseContext)
Jens Geyerfad7fd32019-11-09 23:24:52 +010077 strict private
Jake Farrell27274222011-11-10 20:32:44 +000078 FFirst : Boolean;
79 public
80 constructor Create( const aProto : IJSONProtocol);
81 procedure Write; override;
82 procedure Read; override;
83 end;
84
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)
Jens Geyerfad7fd32019-11-09 23:24:52 +010089 strict private
Jake Farrell27274222011-11-10 20:32:44 +000090 FFirst, FColon : Boolean;
91 public
92 constructor Create( const aProto : IJSONProtocol);
93 procedure Write; override;
94 procedure Read; override;
95 function EscapeNumbers : Boolean; override;
96 end;
97
98 // Holds up to one byte from the transport
99 TLookaheadReader = class
Jens Geyerfad7fd32019-11-09 23:24:52 +0100100 strict protected
Roger Meierfebe8452012-06-06 10:32:24 +0000101 FProto : Pointer; // weak IJSONProtocol;
Jens Geyerfad7fd32019-11-09 23:24:52 +0100102
103 protected
Jake Farrell27274222011-11-10 20:32:44 +0000104 constructor Create( const aProto : IJSONProtocol);
105
Jens Geyerfad7fd32019-11-09 23:24:52 +0100106 strict private
Jake Farrell27274222011-11-10 20:32:44 +0000107 FHasData : Boolean;
Jens Geyer17c3ad92017-09-05 20:31:27 +0200108 FData : Byte;
Jake Farrell27274222011-11-10 20:32:44 +0000109
110 public
111 // Return and consume the next byte to be Read, either taking it from the
112 // data buffer if present or getting it from the transport otherwise.
113 function Read : Byte;
114
115 // Return the next byte to be Read without consuming, filling the data
116 // buffer if it has not been filled alReady.
117 function Peek : Byte;
118 end;
119
Jens Geyerfad7fd32019-11-09 23:24:52 +0100120 strict protected
Jake Farrell27274222011-11-10 20:32:44 +0000121 // Stack of nested contexts that we may be in
122 FContextStack : TStack<TJSONBaseContext>;
123
124 // Current context that we are in
125 FContext : TJSONBaseContext;
126
127 // Reader that manages a 1-byte buffer
128 FReader : TLookaheadReader;
129
130 // Push/pop a new JSON context onto/from the stack.
Roger Meier45a37262012-01-08 21:44:44 +0000131 procedure ResetContextStack;
Roger Meier333bbf32012-01-08 21:51:08 +0000132 procedure PushContext( const aCtx : TJSONBaseContext);
Jake Farrell27274222011-11-10 20:32:44 +0000133 procedure PopContext;
134
Jens Geyer41f47af2019-11-09 23:24:52 +0100135 strict protected
136 function GetMinSerializedSize( const aType : TType) : Integer; override;
137 procedure Reset; override;
138
Jake Farrell27274222011-11-10 20:32:44 +0000139 public
140 // TJSONProtocolImpl Constructor
Roger Meier333bbf32012-01-08 21:51:08 +0000141 constructor Create( const aTrans : ITransport);
Jake Farrell27274222011-11-10 20:32:44 +0000142 destructor Destroy; override;
143
Jens Geyerfad7fd32019-11-09 23:24:52 +0100144 strict protected
Jake Farrell27274222011-11-10 20:32:44 +0000145 // IJSONProtocol
146 // Read a byte that must match b; otherwise an exception is thrown.
147 procedure ReadJSONSyntaxChar( b : Byte);
148
Jens Geyerfad7fd32019-11-09 23:24:52 +0100149 strict private
Jake Farrell27274222011-11-10 20:32:44 +0000150 // Convert a byte containing a hex char ('0'-'9' or 'a'-'f') into its corresponding hex value
151 class function HexVal( ch : Byte) : Byte;
152
153 // Convert a byte containing a hex value to its corresponding hex character
154 class function HexChar( val : Byte) : Byte;
155
156 // Write the bytes in array buf as a JSON characters, escaping as needed
157 procedure WriteJSONString( const b : TBytes); overload;
Roger Meier333bbf32012-01-08 21:51:08 +0000158 procedure WriteJSONString( const str : string); overload;
Jake Farrell27274222011-11-10 20:32:44 +0000159
160 // Write out number as a JSON value. If the context dictates so, it will be
161 // wrapped in quotes to output as a JSON string.
Roger Meier333bbf32012-01-08 21:51:08 +0000162 procedure WriteJSONInteger( const num : Int64);
Jake Farrell27274222011-11-10 20:32:44 +0000163
164 // Write out a double as a JSON value. If it is NaN or infinity or if the
165 // context dictates escaping, Write out as JSON string.
166 procedure WriteJSONDouble( const num : Double);
167
168 // Write out contents of byte array b as a JSON string with base-64 encoded data
169 procedure WriteJSONBase64( const b : TBytes);
170
171 procedure WriteJSONObjectStart;
172 procedure WriteJSONObjectEnd;
173 procedure WriteJSONArrayStart;
174 procedure WriteJSONArrayEnd;
175
176 public
177 // IProtocol
Jens Geyer17c3ad92017-09-05 20:31:27 +0200178 procedure WriteMessageBegin( const aMsg : TThriftMessage); override;
Jake Farrell27274222011-11-10 20:32:44 +0000179 procedure WriteMessageEnd; override;
Jens Geyer17c3ad92017-09-05 20:31:27 +0200180 procedure WriteStructBegin( const struc: TThriftStruct); override;
Jake Farrell27274222011-11-10 20:32:44 +0000181 procedure WriteStructEnd; override;
Jens Geyer17c3ad92017-09-05 20:31:27 +0200182 procedure WriteFieldBegin( const field: TThriftField); override;
Jake Farrell27274222011-11-10 20:32:44 +0000183 procedure WriteFieldEnd; override;
184 procedure WriteFieldStop; override;
Jens Geyer17c3ad92017-09-05 20:31:27 +0200185 procedure WriteMapBegin( const map: TThriftMap); override;
Jake Farrell27274222011-11-10 20:32:44 +0000186 procedure WriteMapEnd; override;
Jens Geyer17c3ad92017-09-05 20:31:27 +0200187 procedure WriteListBegin( const list: TThriftList); override;
Jake Farrell27274222011-11-10 20:32:44 +0000188 procedure WriteListEnd(); override;
Jens Geyer17c3ad92017-09-05 20:31:27 +0200189 procedure WriteSetBegin( const set_: TThriftSet ); override;
Jake Farrell27274222011-11-10 20:32:44 +0000190 procedure WriteSetEnd(); override;
191 procedure WriteBool( b: Boolean); override;
192 procedure WriteByte( b: ShortInt); override;
193 procedure WriteI16( i16: SmallInt); override;
194 procedure WriteI32( i32: Integer); override;
Roger Meier333bbf32012-01-08 21:51:08 +0000195 procedure WriteI64( const i64: Int64); override;
196 procedure WriteDouble( const d: Double); override;
Jake Farrell27274222011-11-10 20:32:44 +0000197 procedure WriteString( const s: string ); override;
198 procedure WriteBinary( const b: TBytes); override;
199 //
Jens Geyer17c3ad92017-09-05 20:31:27 +0200200 function ReadMessageBegin: TThriftMessage; override;
Jake Farrell27274222011-11-10 20:32:44 +0000201 procedure ReadMessageEnd(); override;
Jens Geyer17c3ad92017-09-05 20:31:27 +0200202 function ReadStructBegin: TThriftStruct; override;
Jake Farrell27274222011-11-10 20:32:44 +0000203 procedure ReadStructEnd; override;
Jens Geyer17c3ad92017-09-05 20:31:27 +0200204 function ReadFieldBegin: TThriftField; override;
Jake Farrell27274222011-11-10 20:32:44 +0000205 procedure ReadFieldEnd(); override;
Jens Geyer17c3ad92017-09-05 20:31:27 +0200206 function ReadMapBegin: TThriftMap; override;
Jake Farrell27274222011-11-10 20:32:44 +0000207 procedure ReadMapEnd(); override;
Jens Geyer17c3ad92017-09-05 20:31:27 +0200208 function ReadListBegin: TThriftList; override;
Jake Farrell27274222011-11-10 20:32:44 +0000209 procedure ReadListEnd(); override;
Jens Geyer17c3ad92017-09-05 20:31:27 +0200210 function ReadSetBegin: TThriftSet; override;
Jake Farrell27274222011-11-10 20:32:44 +0000211 procedure ReadSetEnd(); override;
212 function ReadBool: Boolean; override;
213 function ReadByte: ShortInt; override;
214 function ReadI16: SmallInt; override;
215 function ReadI32: Integer; override;
216 function ReadI64: Int64; override;
217 function ReadDouble:Double; override;
218 function ReadString : string; override;
219 function ReadBinary: TBytes; override;
220
221
Jens Geyerfad7fd32019-11-09 23:24:52 +0100222 strict private
Jake Farrell27274222011-11-10 20:32:44 +0000223 // Reading methods.
224
225 // Read in a JSON string, unescaping as appropriate.
226 // Skip Reading from the context if skipContext is true.
227 function ReadJSONString( skipContext : Boolean) : TBytes;
228
229 // Return true if the given byte could be a valid part of a JSON number.
230 function IsJSONNumeric( b : Byte) : Boolean;
231
232 // Read in a sequence of characters that are all valid in JSON numbers. Does
233 // not do a complete regex check to validate that this is actually a number.
234 function ReadJSONNumericChars : String;
235
236 // Read in a JSON number. If the context dictates, Read in enclosing quotes.
237 function ReadJSONInteger : Int64;
238
239 // Read in a JSON double value. Throw if the value is not wrapped in quotes
240 // when expected or if wrapped in quotes when not expected.
241 function ReadJSONDouble : Double;
242
243 // Read in a JSON string containing base-64 encoded data and decode it.
244 function ReadJSONBase64 : TBytes;
245
246 procedure ReadJSONObjectStart;
247 procedure ReadJSONObjectEnd;
248 procedure ReadJSONArrayStart;
249 procedure ReadJSONArrayEnd;
250 end;
251
252
253implementation
254
255var
256 COMMA : TBytes;
257 COLON : TBytes;
258 LBRACE : TBytes;
259 RBRACE : TBytes;
260 LBRACKET : TBytes;
261 RBRACKET : TBytes;
262 QUOTE : TBytes;
263 BACKSLASH : TBytes;
Jake Farrell27274222011-11-10 20:32:44 +0000264 ESCSEQ : TBytes;
265
266const
267 VERSION = 1;
268 JSON_CHAR_TABLE : array[0..$2F] of Byte
269 = (0,0,0,0, 0,0,0,0, Byte('b'),Byte('t'),Byte('n'),0, Byte('f'),Byte('r'),0,0,
270 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
271 1,1,Byte('"'),1, 1,1,1,1, 1,1,1,1, 1,1,1,1);
272
Jens Geyer21366942013-12-30 22:04:51 +0100273 ESCAPE_CHARS = '"\/btnfr';
274 ESCAPE_CHAR_VALS = '"\/'#8#9#10#12#13;
Jake Farrell27274222011-11-10 20:32:44 +0000275
276 DEF_STRING_SIZE = 16;
277
278 NAME_BOOL = 'tf';
279 NAME_BYTE = 'i8';
280 NAME_I16 = 'i16';
281 NAME_I32 = 'i32';
282 NAME_I64 = 'i64';
283 NAME_DOUBLE = 'dbl';
284 NAME_STRUCT = 'rec';
285 NAME_STRING = 'str';
286 NAME_MAP = 'map';
287 NAME_LIST = 'lst';
288 NAME_SET = 'set';
289
290 INVARIANT_CULTURE : TFormatSettings
291 = ( ThousandSeparator: ',';
292 DecimalSeparator: '.');
293
294
295
296//--- TJSONProtocolImpl ----------------------
297
298
Roger Meier333bbf32012-01-08 21:51:08 +0000299function TJSONProtocolImpl.TFactory.GetProtocol( const trans: ITransport): IProtocol;
Jake Farrell27274222011-11-10 20:32:44 +0000300begin
301 result := TJSONProtocolImpl.Create(trans);
302end;
303
304class function TJSONProtocolImpl.GetTypeNameForTypeID(typeID : TType) : string;
305begin
306 case typeID of
307 TType.Bool_: result := NAME_BOOL;
308 TType.Byte_: result := NAME_BYTE;
309 TType.I16: result := NAME_I16;
310 TType.I32: result := NAME_I32;
311 TType.I64: result := NAME_I64;
312 TType.Double_: result := NAME_DOUBLE;
313 TType.String_: result := NAME_STRING;
314 TType.Struct: result := NAME_STRUCT;
315 TType.Map: result := NAME_MAP;
316 TType.Set_: result := NAME_SET;
317 TType.List: result := NAME_LIST;
318 else
Jens Geyere0e32402016-04-20 21:50:48 +0200319 raise TProtocolExceptionNotImplemented.Create('Unrecognized type ('+IntToStr(Ord(typeID))+')');
Jake Farrell27274222011-11-10 20:32:44 +0000320 end;
321end;
322
323
324class function TJSONProtocolImpl.GetTypeIDForTypeName( const name : string) : TType;
325begin
326 if name = NAME_BOOL then result := TType.Bool_
327 else if name = NAME_BYTE then result := TType.Byte_
328 else if name = NAME_I16 then result := TType.I16
329 else if name = NAME_I32 then result := TType.I32
330 else if name = NAME_I64 then result := TType.I64
331 else if name = NAME_DOUBLE then result := TType.Double_
332 else if name = NAME_STRUCT then result := TType.Struct
333 else if name = NAME_STRING then result := TType.String_
334 else if name = NAME_MAP then result := TType.Map
335 else if name = NAME_LIST then result := TType.List
336 else if name = NAME_SET then result := TType.Set_
Jens Geyere0e32402016-04-20 21:50:48 +0200337 else raise TProtocolExceptionNotImplemented.Create('Unrecognized type ('+name+')');
Jake Farrell27274222011-11-10 20:32:44 +0000338end;
339
340
341constructor TJSONProtocolImpl.TJSONBaseContext.Create( const aProto : IJSONProtocol);
342begin
343 inherited Create;
Roger Meierfebe8452012-06-06 10:32:24 +0000344 FProto := Pointer(aProto);
Jake Farrell27274222011-11-10 20:32:44 +0000345end;
346
347
348procedure TJSONProtocolImpl.TJSONBaseContext.Write;
349begin
350 // nothing
351end;
352
353
354procedure TJSONProtocolImpl.TJSONBaseContext.Read;
355begin
356 // nothing
357end;
358
359
360function TJSONProtocolImpl.TJSONBaseContext.EscapeNumbers : Boolean;
361begin
362 result := FALSE;
363end;
364
365
366constructor TJSONProtocolImpl.TJSONListContext.Create( const aProto : IJSONProtocol);
367begin
368 inherited Create( aProto);
369 FFirst := TRUE;
370end;
371
372
373procedure TJSONProtocolImpl.TJSONListContext.Write;
374begin
375 if FFirst
376 then FFirst := FALSE
Roger Meierfebe8452012-06-06 10:32:24 +0000377 else IJSONProtocol(FProto).Transport.Write( COMMA);
Jake Farrell27274222011-11-10 20:32:44 +0000378end;
379
380
381procedure TJSONProtocolImpl.TJSONListContext.Read;
382begin
383 if FFirst
384 then FFirst := FALSE
Roger Meierfebe8452012-06-06 10:32:24 +0000385 else IJSONProtocol(FProto).ReadJSONSyntaxChar( COMMA[0]);
Jake Farrell27274222011-11-10 20:32:44 +0000386end;
387
388
389constructor TJSONProtocolImpl.TJSONPairContext.Create( const aProto : IJSONProtocol);
390begin
391 inherited Create( aProto);
392 FFirst := TRUE;
393 FColon := TRUE;
394end;
395
396
397procedure TJSONProtocolImpl.TJSONPairContext.Write;
398begin
399 if FFirst then begin
400 FFirst := FALSE;
401 FColon := TRUE;
402 end
403 else begin
404 if FColon
Roger Meierfebe8452012-06-06 10:32:24 +0000405 then IJSONProtocol(FProto).Transport.Write( COLON)
406 else IJSONProtocol(FProto).Transport.Write( COMMA);
Jake Farrell27274222011-11-10 20:32:44 +0000407 FColon := not FColon;
408 end;
409end;
410
411
412procedure TJSONProtocolImpl.TJSONPairContext.Read;
413begin
414 if FFirst then begin
415 FFirst := FALSE;
416 FColon := TRUE;
417 end
418 else begin
419 if FColon
Roger Meierfebe8452012-06-06 10:32:24 +0000420 then IJSONProtocol(FProto).ReadJSONSyntaxChar( COLON[0])
421 else IJSONProtocol(FProto).ReadJSONSyntaxChar( COMMA[0]);
Jake Farrell27274222011-11-10 20:32:44 +0000422 FColon := not FColon;
423 end;
424end;
425
426
427function TJSONProtocolImpl.TJSONPairContext.EscapeNumbers : Boolean;
428begin
429 result := FColon;
430end;
431
432
433constructor TJSONProtocolImpl.TLookaheadReader.Create( const aProto : IJSONProtocol);
434begin
435 inherited Create;
Roger Meierfebe8452012-06-06 10:32:24 +0000436 FProto := Pointer(aProto);
Jake Farrell27274222011-11-10 20:32:44 +0000437 FHasData := FALSE;
438end;
439
440
441function TJSONProtocolImpl.TLookaheadReader.Read : Byte;
442begin
443 if FHasData
444 then FHasData := FALSE
445 else begin
Jens Geyer17c3ad92017-09-05 20:31:27 +0200446 IJSONProtocol(FProto).Transport.ReadAll( @FData, SizeOf(FData), 0, 1);
Jake Farrell27274222011-11-10 20:32:44 +0000447 end;
Jens Geyer17c3ad92017-09-05 20:31:27 +0200448 result := FData;
Jake Farrell27274222011-11-10 20:32:44 +0000449end;
450
451
452function TJSONProtocolImpl.TLookaheadReader.Peek : Byte;
453begin
454 if not FHasData then begin
Jens Geyer17c3ad92017-09-05 20:31:27 +0200455 IJSONProtocol(FProto).Transport.ReadAll( @FData, SizeOf(FData), 0, 1);
Jake Farrell27274222011-11-10 20:32:44 +0000456 FHasData := TRUE;
457 end;
Jens Geyer17c3ad92017-09-05 20:31:27 +0200458 result := FData;
Jake Farrell27274222011-11-10 20:32:44 +0000459end;
460
461
Roger Meier333bbf32012-01-08 21:51:08 +0000462constructor TJSONProtocolImpl.Create( const aTrans : ITransport);
Jake Farrell27274222011-11-10 20:32:44 +0000463begin
464 inherited Create( aTrans);
465
466 // Stack of nested contexts that we may be in
467 FContextStack := TStack<TJSONBaseContext>.Create;
468
469 FContext := TJSONBaseContext.Create( Self);
470 FReader := TLookaheadReader.Create( Self);
471end;
472
473
474destructor TJSONProtocolImpl.Destroy;
475begin
476 try
Roger Meier45a37262012-01-08 21:44:44 +0000477 ResetContextStack; // free any contents
Jake Farrell27274222011-11-10 20:32:44 +0000478 FreeAndNil( FReader);
479 FreeAndNil( FContext);
480 FreeAndNil( FContextStack);
481 finally
482 inherited Destroy;
483 end;
484end;
485
486
Jens Geyer41f47af2019-11-09 23:24:52 +0100487procedure TJSONProtocolImpl.Reset;
488begin
489 inherited Reset;
490 ResetContextStack;
491end;
492
493
Roger Meier45a37262012-01-08 21:44:44 +0000494procedure TJSONProtocolImpl.ResetContextStack;
495begin
496 while FContextStack.Count > 0
497 do PopContext;
498end;
499
500
Roger Meier333bbf32012-01-08 21:51:08 +0000501procedure TJSONProtocolImpl.PushContext( const aCtx : TJSONBaseContext);
Roger Meier45a37262012-01-08 21:44:44 +0000502begin
503 FContextStack.Push( FContext);
504 FContext := aCtx;
505end;
506
507
508procedure TJSONProtocolImpl.PopContext;
509begin
510 FreeAndNil(FContext);
511 FContext := FContextStack.Pop;
512end;
513
514
Jake Farrell27274222011-11-10 20:32:44 +0000515procedure TJSONProtocolImpl.ReadJSONSyntaxChar( b : Byte);
516var ch : Byte;
517begin
518 ch := FReader.Read;
519 if (ch <> b)
Jens Geyere0e32402016-04-20 21:50:48 +0200520 then raise TProtocolExceptionInvalidData.Create('Unexpected character ('+Char(ch)+')');
Jake Farrell27274222011-11-10 20:32:44 +0000521end;
522
523
524class function TJSONProtocolImpl.HexVal( ch : Byte) : Byte;
525var i : Integer;
526begin
527 i := StrToIntDef( '$0'+Char(ch), -1);
528 if (0 <= i) and (i < $10)
529 then result := i
Jens Geyere0e32402016-04-20 21:50:48 +0200530 else raise TProtocolExceptionInvalidData.Create('Expected hex character ('+Char(ch)+')');
Jake Farrell27274222011-11-10 20:32:44 +0000531end;
532
533
534class function TJSONProtocolImpl.HexChar( val : Byte) : Byte;
535const HEXCHARS = '0123456789ABCDEF';
536begin
537 result := Byte( PChar(HEXCHARS)[val and $0F]);
538 ASSERT( Pos( Char(result), HEXCHARS) > 0);
539end;
540
541
Roger Meier333bbf32012-01-08 21:51:08 +0000542procedure TJSONProtocolImpl.WriteJSONString( const str : string);
Jake Farrell27274222011-11-10 20:32:44 +0000543begin
544 WriteJSONString( SysUtils.TEncoding.UTF8.GetBytes( str));
545end;
546
547
548procedure TJSONProtocolImpl.WriteJSONString( const b : TBytes);
549var i : Integer;
550 tmp : TBytes;
551begin
552 FContext.Write;
553 Transport.Write( QUOTE);
554 for i := 0 to Length(b)-1 do begin
555
556 if (b[i] and $00FF) >= $30 then begin
557
558 if (b[i] = BACKSLASH[0]) then begin
559 Transport.Write( BACKSLASH);
560 Transport.Write( BACKSLASH);
561 end
562 else begin
563 Transport.Write( b, i, 1);
564 end;
565
566 end
567 else begin
568 SetLength( tmp, 2);
569 tmp[0] := JSON_CHAR_TABLE[b[i]];
570 if (tmp[0] = 1) then begin
571 Transport.Write( b, i, 1)
572 end
573 else if (tmp[0] > 1) then begin
574 Transport.Write( BACKSLASH);
575 Transport.Write( tmp, 0, 1);
576 end
577 else begin
578 Transport.Write( ESCSEQ);
579 tmp[0] := HexChar( b[i] div $10);
580 tmp[1] := HexChar( b[i]);
581 Transport.Write( tmp, 0, 2);
582 end;
583 end;
584 end;
585 Transport.Write( QUOTE);
586end;
587
588
Roger Meier333bbf32012-01-08 21:51:08 +0000589procedure TJSONProtocolImpl.WriteJSONInteger( const num : Int64);
Jake Farrell27274222011-11-10 20:32:44 +0000590var str : String;
591 escapeNum : Boolean;
592begin
593 FContext.Write;
594 str := IntToStr(num);
595
596 escapeNum := FContext.EscapeNumbers;
597 if escapeNum
598 then Transport.Write( QUOTE);
599
600 Transport.Write( SysUtils.TEncoding.UTF8.GetBytes( str));
601
602 if escapeNum
603 then Transport.Write( QUOTE);
604end;
605
606
607procedure TJSONProtocolImpl.WriteJSONDouble( const num : Double);
608var str : string;
609 special : Boolean;
610 escapeNum : Boolean;
611begin
612 FContext.Write;
613
614 str := FloatToStr( num, INVARIANT_CULTURE);
615 special := FALSE;
616
617 case UpCase(str[1]) of
618 'N' : special := TRUE; // NaN
619 'I' : special := TRUE; // Infinity
620 '-' : special := (UpCase(str[2]) = 'I'); // -Infinity
621 end;
622
623 escapeNum := special or FContext.EscapeNumbers;
624
625
626 if escapeNum
627 then Transport.Write( QUOTE);
628
629 Transport.Write( SysUtils.TEncoding.UTF8.GetBytes( str));
630
631 if escapeNum
632 then Transport.Write( QUOTE);
633end;
634
635
636procedure TJSONProtocolImpl.WriteJSONBase64( const b : TBytes);
Jens Geyerd8bddbc2014-12-14 00:41:33 +0100637var len, off, cnt : Integer;
638 tmpBuf : TBytes;
Jake Farrell27274222011-11-10 20:32:44 +0000639begin
640 FContext.Write;
641 Transport.Write( QUOTE);
642
Jens Geyerd8bddbc2014-12-14 00:41:33 +0100643 len := Length(b);
644 off := 0;
645 SetLength( tmpBuf, 4);
646
647 while len >= 3 do begin
648 // Encode 3 bytes at a time
649 Base64Utils.Encode( b, off, 3, tmpBuf, 0);
650 Transport.Write( tmpBuf, 0, 4);
651 Inc( off, 3);
652 Dec( len, 3);
Jake Farrell27274222011-11-10 20:32:44 +0000653 end;
Jens Geyerd8bddbc2014-12-14 00:41:33 +0100654
655 // Encode remainder, if any
656 if len > 0 then begin
657 cnt := Base64Utils.Encode( b, off, len, tmpBuf, 0);
658 Transport.Write( tmpBuf, 0, cnt);
659 end;
Jake Farrell27274222011-11-10 20:32:44 +0000660
661 Transport.Write( QUOTE);
662end;
663
664
665procedure TJSONProtocolImpl.WriteJSONObjectStart;
666begin
667 FContext.Write;
668 Transport.Write( LBRACE);
669 PushContext( TJSONPairContext.Create( Self));
670end;
671
672
673procedure TJSONProtocolImpl.WriteJSONObjectEnd;
674begin
675 PopContext;
676 Transport.Write( RBRACE);
677end;
678
679
680procedure TJSONProtocolImpl.WriteJSONArrayStart;
681begin
682 FContext.Write;
683 Transport.Write( LBRACKET);
684 PushContext( TJSONListContext.Create( Self));
685end;
686
687
688procedure TJSONProtocolImpl.WriteJSONArrayEnd;
689begin
690 PopContext;
691 Transport.Write( RBRACKET);
692end;
693
694
Jens Geyer17c3ad92017-09-05 20:31:27 +0200695procedure TJSONProtocolImpl.WriteMessageBegin( const aMsg : TThriftMessage);
Jake Farrell27274222011-11-10 20:32:44 +0000696begin
Jens Geyer41f47af2019-11-09 23:24:52 +0100697 Reset;
Roger Meier45a37262012-01-08 21:44:44 +0000698 ResetContextStack; // THRIFT-1473
699
Jake Farrell27274222011-11-10 20:32:44 +0000700 WriteJSONArrayStart;
701 WriteJSONInteger(VERSION);
702
703 WriteJSONString( SysUtils.TEncoding.UTF8.GetBytes( aMsg.Name));
704
705 WriteJSONInteger( LongInt( aMsg.Type_));
706 WriteJSONInteger( aMsg.SeqID);
707end;
708
709procedure TJSONProtocolImpl.WriteMessageEnd;
710begin
711 WriteJSONArrayEnd;
712end;
713
714
Jens Geyer17c3ad92017-09-05 20:31:27 +0200715procedure TJSONProtocolImpl.WriteStructBegin( const struc: TThriftStruct);
Jake Farrell27274222011-11-10 20:32:44 +0000716begin
717 WriteJSONObjectStart;
718end;
719
720
721procedure TJSONProtocolImpl.WriteStructEnd;
722begin
723 WriteJSONObjectEnd;
724end;
725
726
Jens Geyer17c3ad92017-09-05 20:31:27 +0200727procedure TJSONProtocolImpl.WriteFieldBegin( const field : TThriftField);
Jake Farrell27274222011-11-10 20:32:44 +0000728begin
729 WriteJSONInteger(field.ID);
730 WriteJSONObjectStart;
731 WriteJSONString( GetTypeNameForTypeID(field.Type_));
732end;
733
734
735procedure TJSONProtocolImpl.WriteFieldEnd;
736begin
737 WriteJSONObjectEnd;
738end;
739
740
741procedure TJSONProtocolImpl.WriteFieldStop;
742begin
743 // nothing to do
744end;
745
Jens Geyer17c3ad92017-09-05 20:31:27 +0200746procedure TJSONProtocolImpl.WriteMapBegin( const map: TThriftMap);
Jake Farrell27274222011-11-10 20:32:44 +0000747begin
748 WriteJSONArrayStart;
749 WriteJSONString( GetTypeNameForTypeID( map.KeyType));
750 WriteJSONString( GetTypeNameForTypeID( map.ValueType));
751 WriteJSONInteger( map.Count);
752 WriteJSONObjectStart;
753end;
754
755
756procedure TJSONProtocolImpl.WriteMapEnd;
757begin
758 WriteJSONObjectEnd;
759 WriteJSONArrayEnd;
760end;
761
762
Jens Geyer17c3ad92017-09-05 20:31:27 +0200763procedure TJSONProtocolImpl.WriteListBegin( const list: TThriftList);
Jake Farrell27274222011-11-10 20:32:44 +0000764begin
765 WriteJSONArrayStart;
766 WriteJSONString( GetTypeNameForTypeID( list.ElementType));
767 WriteJSONInteger(list.Count);
768end;
769
770
771procedure TJSONProtocolImpl.WriteListEnd;
772begin
773 WriteJSONArrayEnd;
774end;
775
776
Jens Geyer17c3ad92017-09-05 20:31:27 +0200777procedure TJSONProtocolImpl.WriteSetBegin( const set_: TThriftSet);
Jake Farrell27274222011-11-10 20:32:44 +0000778begin
779 WriteJSONArrayStart;
780 WriteJSONString( GetTypeNameForTypeID( set_.ElementType));
781 WriteJSONInteger( set_.Count);
782end;
783
784
785procedure TJSONProtocolImpl.WriteSetEnd;
786begin
787 WriteJSONArrayEnd;
788end;
789
790procedure TJSONProtocolImpl.WriteBool( b: Boolean);
791begin
792 if b
793 then WriteJSONInteger( 1)
794 else WriteJSONInteger( 0);
795end;
796
797procedure TJSONProtocolImpl.WriteByte( b: ShortInt);
798begin
799 WriteJSONInteger( b);
800end;
801
802procedure TJSONProtocolImpl.WriteI16( i16: SmallInt);
803begin
804 WriteJSONInteger( i16);
805end;
806
807procedure TJSONProtocolImpl.WriteI32( i32: Integer);
808begin
809 WriteJSONInteger( i32);
810end;
811
Roger Meier333bbf32012-01-08 21:51:08 +0000812procedure TJSONProtocolImpl.WriteI64( const i64: Int64);
Jake Farrell27274222011-11-10 20:32:44 +0000813begin
814 WriteJSONInteger(i64);
815end;
816
Roger Meier333bbf32012-01-08 21:51:08 +0000817procedure TJSONProtocolImpl.WriteDouble( const d: Double);
Jake Farrell27274222011-11-10 20:32:44 +0000818begin
819 WriteJSONDouble( d);
820end;
821
822procedure TJSONProtocolImpl.WriteString( const s: string );
823begin
824 WriteJSONString( SysUtils.TEncoding.UTF8.GetBytes( s));
825end;
826
827procedure TJSONProtocolImpl.WriteBinary( const b: TBytes);
828begin
829 WriteJSONBase64( b);
830end;
831
832
833function TJSONProtocolImpl.ReadJSONString( skipContext : Boolean) : TBytes;
834var buffer : TMemoryStream;
Jens Geyer7bb44a32014-02-07 22:24:37 +0100835 ch : Byte;
836 wch : Word;
Phongphan Phutthaa6509f72015-10-31 01:09:47 +0700837 highSurogate: Char;
838 surrogatePairs: Array[0..1] of Char;
Jake Farrell27274222011-11-10 20:32:44 +0000839 off : Integer;
840 tmp : TBytes;
841begin
Phongphan Phutthaa6509f72015-10-31 01:09:47 +0700842 highSurogate := #0;
Jake Farrell27274222011-11-10 20:32:44 +0000843 buffer := TMemoryStream.Create;
844 try
845 if not skipContext
846 then FContext.Read;
847
848 ReadJSONSyntaxChar( QUOTE[0]);
849
850 while TRUE do begin
851 ch := FReader.Read;
852
853 if (ch = QUOTE[0])
854 then Break;
855
Jens Geyer7bb44a32014-02-07 22:24:37 +0100856 // check for escapes
857 if (ch <> ESCSEQ[0]) then begin
858 buffer.Write( ch, 1);
859 Continue;
Jake Farrell27274222011-11-10 20:32:44 +0000860 end;
Jens Geyer7bb44a32014-02-07 22:24:37 +0100861
862 // distuinguish between \uNNNN and \?
863 ch := FReader.Read;
864 if (ch <> ESCSEQ[1])
865 then begin
866 off := Pos( Char(ch), ESCAPE_CHARS);
867 if off < 1
Jens Geyere0e32402016-04-20 21:50:48 +0200868 then raise TProtocolExceptionInvalidData.Create('Expected control char');
Jens Geyer7bb44a32014-02-07 22:24:37 +0100869 ch := Byte( ESCAPE_CHAR_VALS[off]);
870 buffer.Write( ch, 1);
871 Continue;
872 end;
873
874 // it is \uXXXX
875 SetLength( tmp, 4);
876 Transport.ReadAll( tmp, 0, 4);
877 wch := (HexVal(tmp[0]) shl 12)
878 + (HexVal(tmp[1]) shl 8)
879 + (HexVal(tmp[2]) shl 4)
880 + HexVal(tmp[3]);
Phongphan Phutthaa6509f72015-10-31 01:09:47 +0700881
Jens Geyer7bb44a32014-02-07 22:24:37 +0100882 // we need to make UTF8 bytes from it, to be decoded later
Jens Geyer71070432016-01-29 10:08:39 +0100883 if CharUtils.IsHighSurrogate(char(wch)) then begin
Phongphan Phutthaa6509f72015-10-31 01:09:47 +0700884 if highSurogate <> #0
Jens Geyere0e32402016-04-20 21:50:48 +0200885 then raise TProtocolExceptionInvalidData.Create('Expected low surrogate char');
Phongphan Phutthaa6509f72015-10-31 01:09:47 +0700886 highSurogate := char(wch);
887 end
Jens Geyer71070432016-01-29 10:08:39 +0100888 else if CharUtils.IsLowSurrogate(char(wch)) then begin
Phongphan Phutthaa6509f72015-10-31 01:09:47 +0700889 if highSurogate = #0
Jens Geyere0e32402016-04-20 21:50:48 +0200890 then TProtocolExceptionInvalidData.Create('Expected high surrogate char');
Phongphan Phutthaa6509f72015-10-31 01:09:47 +0700891 surrogatePairs[0] := highSurogate;
892 surrogatePairs[1] := char(wch);
893 tmp := TEncoding.UTF8.GetBytes(surrogatePairs);
894 buffer.Write( tmp[0], Length(tmp));
895 highSurogate := #0;
896 end
897 else begin
898 tmp := SysUtils.TEncoding.UTF8.GetBytes(Char(wch));
899 buffer.Write( tmp[0], Length(tmp));
900 end;
Jake Farrell27274222011-11-10 20:32:44 +0000901 end;
902
Phongphan Phutthaa6509f72015-10-31 01:09:47 +0700903 if highSurogate <> #0
Jens Geyere0e32402016-04-20 21:50:48 +0200904 then raise TProtocolExceptionInvalidData.Create('Expected low surrogate char');
Phongphan Phutthaa6509f72015-10-31 01:09:47 +0700905
Jake Farrell27274222011-11-10 20:32:44 +0000906 SetLength( result, buffer.Size);
Jake Farrella2a9ee92011-12-15 20:50:31 +0000907 if buffer.Size > 0 then Move( buffer.Memory^, result[0], Length(result));
Jake Farrell27274222011-11-10 20:32:44 +0000908
909 finally
910 buffer.Free;
911 end;
912end;
913
914
915function TJSONProtocolImpl.IsJSONNumeric( b : Byte) : Boolean;
916const NUMCHARS = ['+','-','.','0','1','2','3','4','5','6','7','8','9','E','e'];
917begin
918 result := CharInSet( Char(b), NUMCHARS);
919end;
920
921
922function TJSONProtocolImpl.ReadJSONNumericChars : string;
923var strbld : TThriftStringBuilder;
924 ch : Byte;
925begin
926 strbld := TThriftStringBuilder.Create;
927 try
928 while TRUE do begin
929 ch := FReader.Peek;
930 if IsJSONNumeric(ch)
931 then strbld.Append( Char(FReader.Read))
932 else Break;
933 end;
934 result := strbld.ToString;
935
936 finally
937 strbld.Free;
938 end;
939end;
940
941
942function TJSONProtocolImpl.ReadJSONInteger : Int64;
943var str : string;
944begin
945 FContext.Read;
946 if FContext.EscapeNumbers
947 then ReadJSONSyntaxChar( QUOTE[0]);
948
949 str := ReadJSONNumericChars;
950
951 if FContext.EscapeNumbers
952 then ReadJSONSyntaxChar( QUOTE[0]);
953
954 try
955 result := StrToInt64(str);
956 except
957 on e:Exception do begin
Jens Geyere0e32402016-04-20 21:50:48 +0200958 raise TProtocolExceptionInvalidData.Create('Bad data encounted in numeric data ('+str+') ('+e.Message+')');
Jake Farrell27274222011-11-10 20:32:44 +0000959 end;
960 end;
961end;
962
963
964function TJSONProtocolImpl.ReadJSONDouble : Double;
965var dub : Double;
966 str : string;
967begin
968 FContext.Read;
969
970 if FReader.Peek = QUOTE[0]
971 then begin
972 str := SysUtils.TEncoding.UTF8.GetString( ReadJSONString( TRUE));
973 dub := StrToFloat( str, INVARIANT_CULTURE);
974
975 if not FContext.EscapeNumbers()
976 and not Math.IsNaN(dub)
977 and not Math.IsInfinite(dub)
978 then begin
979 // Throw exception -- we should not be in a string in Self case
Jens Geyere0e32402016-04-20 21:50:48 +0200980 raise TProtocolExceptionInvalidData.Create('Numeric data unexpectedly quoted');
Jake Farrell27274222011-11-10 20:32:44 +0000981 end;
982 result := dub;
983 Exit;
984 end;
985
986 // will throw - we should have had a quote if escapeNum == true
987 if FContext.EscapeNumbers
988 then ReadJSONSyntaxChar( QUOTE[0]);
989
990 try
991 str := ReadJSONNumericChars;
992 result := StrToFloat( str, INVARIANT_CULTURE);
993 except
994 on e:Exception
Jens Geyere0e32402016-04-20 21:50:48 +0200995 do raise TProtocolExceptionInvalidData.Create('Bad data encounted in numeric data ('+str+') ('+e.Message+')');
Jake Farrell27274222011-11-10 20:32:44 +0000996 end;
997end;
998
999
1000function TJSONProtocolImpl.ReadJSONBase64 : TBytes;
1001var b : TBytes;
Jens Geyer9f9535c2014-12-14 04:16:05 +01001002 len, off, size : Integer;
Jake Farrell27274222011-11-10 20:32:44 +00001003begin
1004 b := ReadJSONString(false);
1005
Jens Geyerd8bddbc2014-12-14 00:41:33 +01001006 len := Length(b);
1007 off := 0;
1008 size := 0;
1009
1010 // reduce len to ignore fill bytes
1011 Dec(len);
1012 while (len >= 0) and (b[len] = Byte('=')) do Dec(len);
1013 Inc(len);
1014
1015 // read & decode full byte triplets = 4 source bytes
1016 while (len >= 4) do begin
1017 // Decode 4 bytes at a time
1018 Inc( size, Base64Utils.Decode( b, off, 4, b, size)); // decoded in place
1019 Inc( off, 4);
1020 Dec( len, 4);
1021 end;
1022
1023 // Don't decode if we hit the end or got a single leftover byte (invalid
1024 // base64 but legal for skip of regular string type)
1025 if len > 1 then begin
1026 // Decode remainder
1027 Inc( size, Base64Utils.Decode( b, off, len, b, size)); // decoded in place
1028 end;
1029
1030 // resize to final size and return the data
1031 SetLength( b, size);
1032 result := b;
Jake Farrell27274222011-11-10 20:32:44 +00001033end;
1034
1035
1036procedure TJSONProtocolImpl.ReadJSONObjectStart;
1037begin
1038 FContext.Read;
1039 ReadJSONSyntaxChar( LBRACE[0]);
1040 PushContext( TJSONPairContext.Create( Self));
1041end;
1042
1043
1044procedure TJSONProtocolImpl.ReadJSONObjectEnd;
1045begin
1046 ReadJSONSyntaxChar( RBRACE[0]);
1047 PopContext;
1048end;
1049
1050
1051procedure TJSONProtocolImpl.ReadJSONArrayStart;
1052begin
1053 FContext.Read;
1054 ReadJSONSyntaxChar( LBRACKET[0]);
1055 PushContext( TJSONListContext.Create( Self));
1056end;
1057
1058
1059procedure TJSONProtocolImpl.ReadJSONArrayEnd;
1060begin
1061 ReadJSONSyntaxChar( RBRACKET[0]);
1062 PopContext;
1063end;
1064
1065
Jens Geyer17c3ad92017-09-05 20:31:27 +02001066function TJSONProtocolImpl.ReadMessageBegin: TThriftMessage;
Jake Farrell27274222011-11-10 20:32:44 +00001067begin
Jens Geyer41f47af2019-11-09 23:24:52 +01001068 Reset;
Roger Meier45a37262012-01-08 21:44:44 +00001069 ResetContextStack; // THRIFT-1473
1070
Jens Geyer17c3ad92017-09-05 20:31:27 +02001071 Init( result);
Jake Farrell27274222011-11-10 20:32:44 +00001072 ReadJSONArrayStart;
1073
1074 if ReadJSONInteger <> VERSION
Jens Geyere0e32402016-04-20 21:50:48 +02001075 then raise TProtocolExceptionBadVersion.Create('Message contained bad version.');
Jake Farrell27274222011-11-10 20:32:44 +00001076
1077 result.Name := SysUtils.TEncoding.UTF8.GetString( ReadJSONString( FALSE));
1078 result.Type_ := TMessageType( ReadJSONInteger);
1079 result.SeqID := ReadJSONInteger;
1080end;
1081
1082
1083procedure TJSONProtocolImpl.ReadMessageEnd;
1084begin
1085 ReadJSONArrayEnd;
1086end;
1087
1088
Jens Geyer17c3ad92017-09-05 20:31:27 +02001089function TJSONProtocolImpl.ReadStructBegin : TThriftStruct ;
Jake Farrell27274222011-11-10 20:32:44 +00001090begin
1091 ReadJSONObjectStart;
Jens Geyer17c3ad92017-09-05 20:31:27 +02001092 Init( result);
Jake Farrell27274222011-11-10 20:32:44 +00001093end;
1094
1095
1096procedure TJSONProtocolImpl.ReadStructEnd;
1097begin
1098 ReadJSONObjectEnd;
1099end;
1100
1101
Jens Geyer17c3ad92017-09-05 20:31:27 +02001102function TJSONProtocolImpl.ReadFieldBegin : TThriftField;
Jake Farrell27274222011-11-10 20:32:44 +00001103var ch : Byte;
1104 str : string;
1105begin
Jens Geyer17c3ad92017-09-05 20:31:27 +02001106 Init( result);
Jake Farrell27274222011-11-10 20:32:44 +00001107 ch := FReader.Peek;
1108 if ch = RBRACE[0]
1109 then result.Type_ := TType.Stop
1110 else begin
1111 result.ID := ReadJSONInteger;
1112 ReadJSONObjectStart;
1113
1114 str := SysUtils.TEncoding.UTF8.GetString( ReadJSONString( FALSE));
1115 result.Type_ := GetTypeIDForTypeName( str);
1116 end;
1117end;
1118
1119
1120procedure TJSONProtocolImpl.ReadFieldEnd;
1121begin
1122 ReadJSONObjectEnd;
1123end;
1124
1125
Jens Geyer17c3ad92017-09-05 20:31:27 +02001126function TJSONProtocolImpl.ReadMapBegin : TThriftMap;
Jake Farrell27274222011-11-10 20:32:44 +00001127var str : string;
1128begin
Jens Geyer17c3ad92017-09-05 20:31:27 +02001129 Init( result);
Jake Farrell27274222011-11-10 20:32:44 +00001130 ReadJSONArrayStart;
1131
1132 str := SysUtils.TEncoding.UTF8.GetString( ReadJSONString(FALSE));
1133 result.KeyType := GetTypeIDForTypeName( str);
1134
1135 str := SysUtils.TEncoding.UTF8.GetString( ReadJSONString(FALSE));
1136 result.ValueType := GetTypeIDForTypeName( str);
1137
1138 result.Count := ReadJSONInteger;
Jens Geyer41f47af2019-11-09 23:24:52 +01001139 CheckReadBytesAvailable(result);
1140
Jake Farrell27274222011-11-10 20:32:44 +00001141 ReadJSONObjectStart;
1142end;
1143
1144
1145procedure TJSONProtocolImpl.ReadMapEnd;
1146begin
1147 ReadJSONObjectEnd;
1148 ReadJSONArrayEnd;
1149end;
1150
1151
Jens Geyer17c3ad92017-09-05 20:31:27 +02001152function TJSONProtocolImpl.ReadListBegin : TThriftList;
Jake Farrell27274222011-11-10 20:32:44 +00001153var str : string;
1154begin
Jens Geyer17c3ad92017-09-05 20:31:27 +02001155 Init( result);
Jake Farrell27274222011-11-10 20:32:44 +00001156 ReadJSONArrayStart;
1157
1158 str := SysUtils.TEncoding.UTF8.GetString( ReadJSONString(FALSE));
1159 result.ElementType := GetTypeIDForTypeName( str);
1160 result.Count := ReadJSONInteger;
Jens Geyer41f47af2019-11-09 23:24:52 +01001161 CheckReadBytesAvailable(result);
Jake Farrell27274222011-11-10 20:32:44 +00001162end;
1163
1164
1165procedure TJSONProtocolImpl.ReadListEnd;
1166begin
1167 ReadJSONArrayEnd;
1168end;
1169
1170
Jens Geyer17c3ad92017-09-05 20:31:27 +02001171function TJSONProtocolImpl.ReadSetBegin : TThriftSet;
Jake Farrell27274222011-11-10 20:32:44 +00001172var str : string;
1173begin
Jens Geyer17c3ad92017-09-05 20:31:27 +02001174 Init( result);
Jake Farrell27274222011-11-10 20:32:44 +00001175 ReadJSONArrayStart;
1176
1177 str := SysUtils.TEncoding.UTF8.GetString( ReadJSONString(FALSE));
1178 result.ElementType := GetTypeIDForTypeName( str);
1179 result.Count := ReadJSONInteger;
Jens Geyer41f47af2019-11-09 23:24:52 +01001180 CheckReadBytesAvailable(result);
Jake Farrell27274222011-11-10 20:32:44 +00001181end;
1182
1183
1184procedure TJSONProtocolImpl.ReadSetEnd;
1185begin
1186 ReadJSONArrayEnd;
1187end;
1188
1189
1190function TJSONProtocolImpl.ReadBool : Boolean;
1191begin
1192 result := (ReadJSONInteger <> 0);
1193end;
1194
1195
1196function TJSONProtocolImpl.ReadByte : ShortInt;
1197begin
1198 result := ReadJSONInteger;
1199end;
1200
1201
1202function TJSONProtocolImpl.ReadI16 : SmallInt;
1203begin
1204 result := ReadJSONInteger;
1205end;
1206
1207
1208function TJSONProtocolImpl.ReadI32 : LongInt;
1209begin
1210 result := ReadJSONInteger;
1211end;
1212
1213
1214function TJSONProtocolImpl.ReadI64 : Int64;
1215begin
1216 result := ReadJSONInteger;
1217end;
1218
1219
1220function TJSONProtocolImpl.ReadDouble : Double;
1221begin
1222 result := ReadJSONDouble;
1223end;
1224
1225
1226function TJSONProtocolImpl.ReadString : string;
1227begin
1228 result := SysUtils.TEncoding.UTF8.GetString( ReadJSONString( FALSE));
1229end;
1230
1231
1232function TJSONProtocolImpl.ReadBinary : TBytes;
1233begin
1234 result := ReadJSONBase64;
1235end;
1236
1237
Jens Geyer41f47af2019-11-09 23:24:52 +01001238function TJSONProtocolImpl.GetMinSerializedSize( const aType : TType) : Integer;
1239// Return the minimum number of bytes a type will consume on the wire
1240begin
1241 case aType of
1242 TType.Stop: result := 0;
1243 TType.Void: result := 0;
1244 TType.Bool_: result := 1;
1245 TType.Byte_: result := 1;
1246 TType.Double_: result := 1;
1247 TType.I16: result := 1;
1248 TType.I32: result := 1;
1249 TType.I64: result := 1;
1250 TType.String_: result := 2; // empty string
1251 TType.Struct: result := 2; // empty struct
1252 TType.Map: result := 2; // empty map
1253 TType.Set_: result := 2; // empty set
1254 TType.List: result := 2; // empty list
1255 else
1256 raise TTransportExceptionBadArgs.Create('Unhandled type code');
1257 end;
1258end;
1259
1260
1261
Jake Farrell27274222011-11-10 20:32:44 +00001262//--- init code ---
1263
1264procedure InitBytes( var b : TBytes; aData : array of Byte);
1265begin
1266 SetLength( b, Length(aData));
1267 Move( aData, b[0], Length(b));
1268end;
1269
1270initialization
1271 InitBytes( COMMA, [Byte(',')]);
1272 InitBytes( COLON, [Byte(':')]);
1273 InitBytes( LBRACE, [Byte('{')]);
1274 InitBytes( RBRACE, [Byte('}')]);
1275 InitBytes( LBRACKET, [Byte('[')]);
1276 InitBytes( RBRACKET, [Byte(']')]);
1277 InitBytes( QUOTE, [Byte('"')]);
1278 InitBytes( BACKSLASH, [Byte('\')]);
Jake Farrell27274222011-11-10 20:32:44 +00001279 InitBytes( ESCSEQ, [Byte('\'),Byte('u'),Byte('0'),Byte('0')]);
1280end.