blob: 85cb973f9b6654de051d2565ba222659bfabb319 [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
135 public
136 // TJSONProtocolImpl Constructor
Roger Meier333bbf32012-01-08 21:51:08 +0000137 constructor Create( const aTrans : ITransport);
Jake Farrell27274222011-11-10 20:32:44 +0000138 destructor Destroy; override;
139
Jens Geyerfad7fd32019-11-09 23:24:52 +0100140 strict protected
Jake Farrell27274222011-11-10 20:32:44 +0000141 // IJSONProtocol
142 // Read a byte that must match b; otherwise an exception is thrown.
143 procedure ReadJSONSyntaxChar( b : Byte);
144
Jens Geyerfad7fd32019-11-09 23:24:52 +0100145 strict private
Jake Farrell27274222011-11-10 20:32:44 +0000146 // Convert a byte containing a hex char ('0'-'9' or 'a'-'f') into its corresponding hex value
147 class function HexVal( ch : Byte) : Byte;
148
149 // Convert a byte containing a hex value to its corresponding hex character
150 class function HexChar( val : Byte) : Byte;
151
152 // Write the bytes in array buf as a JSON characters, escaping as needed
153 procedure WriteJSONString( const b : TBytes); overload;
Roger Meier333bbf32012-01-08 21:51:08 +0000154 procedure WriteJSONString( const str : string); overload;
Jake Farrell27274222011-11-10 20:32:44 +0000155
156 // Write out number as a JSON value. If the context dictates so, it will be
157 // wrapped in quotes to output as a JSON string.
Roger Meier333bbf32012-01-08 21:51:08 +0000158 procedure WriteJSONInteger( const num : Int64);
Jake Farrell27274222011-11-10 20:32:44 +0000159
160 // Write out a double as a JSON value. If it is NaN or infinity or if the
161 // context dictates escaping, Write out as JSON string.
162 procedure WriteJSONDouble( const num : Double);
163
164 // Write out contents of byte array b as a JSON string with base-64 encoded data
165 procedure WriteJSONBase64( const b : TBytes);
166
167 procedure WriteJSONObjectStart;
168 procedure WriteJSONObjectEnd;
169 procedure WriteJSONArrayStart;
170 procedure WriteJSONArrayEnd;
171
172 public
173 // IProtocol
Jens Geyer17c3ad92017-09-05 20:31:27 +0200174 procedure WriteMessageBegin( const aMsg : TThriftMessage); override;
Jake Farrell27274222011-11-10 20:32:44 +0000175 procedure WriteMessageEnd; override;
Jens Geyer17c3ad92017-09-05 20:31:27 +0200176 procedure WriteStructBegin( const struc: TThriftStruct); override;
Jake Farrell27274222011-11-10 20:32:44 +0000177 procedure WriteStructEnd; override;
Jens Geyer17c3ad92017-09-05 20:31:27 +0200178 procedure WriteFieldBegin( const field: TThriftField); override;
Jake Farrell27274222011-11-10 20:32:44 +0000179 procedure WriteFieldEnd; override;
180 procedure WriteFieldStop; override;
Jens Geyer17c3ad92017-09-05 20:31:27 +0200181 procedure WriteMapBegin( const map: TThriftMap); override;
Jake Farrell27274222011-11-10 20:32:44 +0000182 procedure WriteMapEnd; override;
Jens Geyer17c3ad92017-09-05 20:31:27 +0200183 procedure WriteListBegin( const list: TThriftList); override;
Jake Farrell27274222011-11-10 20:32:44 +0000184 procedure WriteListEnd(); override;
Jens Geyer17c3ad92017-09-05 20:31:27 +0200185 procedure WriteSetBegin( const set_: TThriftSet ); override;
Jake Farrell27274222011-11-10 20:32:44 +0000186 procedure WriteSetEnd(); override;
187 procedure WriteBool( b: Boolean); override;
188 procedure WriteByte( b: ShortInt); override;
189 procedure WriteI16( i16: SmallInt); override;
190 procedure WriteI32( i32: Integer); override;
Roger Meier333bbf32012-01-08 21:51:08 +0000191 procedure WriteI64( const i64: Int64); override;
192 procedure WriteDouble( const d: Double); override;
Jake Farrell27274222011-11-10 20:32:44 +0000193 procedure WriteString( const s: string ); override;
194 procedure WriteBinary( const b: TBytes); override;
195 //
Jens Geyer17c3ad92017-09-05 20:31:27 +0200196 function ReadMessageBegin: TThriftMessage; override;
Jake Farrell27274222011-11-10 20:32:44 +0000197 procedure ReadMessageEnd(); override;
Jens Geyer17c3ad92017-09-05 20:31:27 +0200198 function ReadStructBegin: TThriftStruct; override;
Jake Farrell27274222011-11-10 20:32:44 +0000199 procedure ReadStructEnd; override;
Jens Geyer17c3ad92017-09-05 20:31:27 +0200200 function ReadFieldBegin: TThriftField; override;
Jake Farrell27274222011-11-10 20:32:44 +0000201 procedure ReadFieldEnd(); override;
Jens Geyer17c3ad92017-09-05 20:31:27 +0200202 function ReadMapBegin: TThriftMap; override;
Jake Farrell27274222011-11-10 20:32:44 +0000203 procedure ReadMapEnd(); override;
Jens Geyer17c3ad92017-09-05 20:31:27 +0200204 function ReadListBegin: TThriftList; override;
Jake Farrell27274222011-11-10 20:32:44 +0000205 procedure ReadListEnd(); override;
Jens Geyer17c3ad92017-09-05 20:31:27 +0200206 function ReadSetBegin: TThriftSet; override;
Jake Farrell27274222011-11-10 20:32:44 +0000207 procedure ReadSetEnd(); override;
208 function ReadBool: Boolean; override;
209 function ReadByte: ShortInt; override;
210 function ReadI16: SmallInt; override;
211 function ReadI32: Integer; override;
212 function ReadI64: Int64; override;
213 function ReadDouble:Double; override;
214 function ReadString : string; override;
215 function ReadBinary: TBytes; override;
216
217
Jens Geyerfad7fd32019-11-09 23:24:52 +0100218 strict private
Jake Farrell27274222011-11-10 20:32:44 +0000219 // Reading methods.
220
221 // Read in a JSON string, unescaping as appropriate.
222 // Skip Reading from the context if skipContext is true.
223 function ReadJSONString( skipContext : Boolean) : TBytes;
224
225 // Return true if the given byte could be a valid part of a JSON number.
226 function IsJSONNumeric( b : Byte) : Boolean;
227
228 // Read in a sequence of characters that are all valid in JSON numbers. Does
229 // not do a complete regex check to validate that this is actually a number.
230 function ReadJSONNumericChars : String;
231
232 // Read in a JSON number. If the context dictates, Read in enclosing quotes.
233 function ReadJSONInteger : Int64;
234
235 // Read in a JSON double value. Throw if the value is not wrapped in quotes
236 // when expected or if wrapped in quotes when not expected.
237 function ReadJSONDouble : Double;
238
239 // Read in a JSON string containing base-64 encoded data and decode it.
240 function ReadJSONBase64 : TBytes;
241
242 procedure ReadJSONObjectStart;
243 procedure ReadJSONObjectEnd;
244 procedure ReadJSONArrayStart;
245 procedure ReadJSONArrayEnd;
246 end;
247
248
249implementation
250
251var
252 COMMA : TBytes;
253 COLON : TBytes;
254 LBRACE : TBytes;
255 RBRACE : TBytes;
256 LBRACKET : TBytes;
257 RBRACKET : TBytes;
258 QUOTE : TBytes;
259 BACKSLASH : TBytes;
Jake Farrell27274222011-11-10 20:32:44 +0000260 ESCSEQ : TBytes;
261
262const
263 VERSION = 1;
264 JSON_CHAR_TABLE : array[0..$2F] of Byte
265 = (0,0,0,0, 0,0,0,0, Byte('b'),Byte('t'),Byte('n'),0, Byte('f'),Byte('r'),0,0,
266 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
267 1,1,Byte('"'),1, 1,1,1,1, 1,1,1,1, 1,1,1,1);
268
Jens Geyer21366942013-12-30 22:04:51 +0100269 ESCAPE_CHARS = '"\/btnfr';
270 ESCAPE_CHAR_VALS = '"\/'#8#9#10#12#13;
Jake Farrell27274222011-11-10 20:32:44 +0000271
272 DEF_STRING_SIZE = 16;
273
274 NAME_BOOL = 'tf';
275 NAME_BYTE = 'i8';
276 NAME_I16 = 'i16';
277 NAME_I32 = 'i32';
278 NAME_I64 = 'i64';
279 NAME_DOUBLE = 'dbl';
280 NAME_STRUCT = 'rec';
281 NAME_STRING = 'str';
282 NAME_MAP = 'map';
283 NAME_LIST = 'lst';
284 NAME_SET = 'set';
285
286 INVARIANT_CULTURE : TFormatSettings
287 = ( ThousandSeparator: ',';
288 DecimalSeparator: '.');
289
290
291
292//--- TJSONProtocolImpl ----------------------
293
294
Roger Meier333bbf32012-01-08 21:51:08 +0000295function TJSONProtocolImpl.TFactory.GetProtocol( const trans: ITransport): IProtocol;
Jake Farrell27274222011-11-10 20:32:44 +0000296begin
297 result := TJSONProtocolImpl.Create(trans);
298end;
299
300class function TJSONProtocolImpl.GetTypeNameForTypeID(typeID : TType) : string;
301begin
302 case typeID of
303 TType.Bool_: result := NAME_BOOL;
304 TType.Byte_: result := NAME_BYTE;
305 TType.I16: result := NAME_I16;
306 TType.I32: result := NAME_I32;
307 TType.I64: result := NAME_I64;
308 TType.Double_: result := NAME_DOUBLE;
309 TType.String_: result := NAME_STRING;
310 TType.Struct: result := NAME_STRUCT;
311 TType.Map: result := NAME_MAP;
312 TType.Set_: result := NAME_SET;
313 TType.List: result := NAME_LIST;
314 else
Jens Geyere0e32402016-04-20 21:50:48 +0200315 raise TProtocolExceptionNotImplemented.Create('Unrecognized type ('+IntToStr(Ord(typeID))+')');
Jake Farrell27274222011-11-10 20:32:44 +0000316 end;
317end;
318
319
320class function TJSONProtocolImpl.GetTypeIDForTypeName( const name : string) : TType;
321begin
322 if name = NAME_BOOL then result := TType.Bool_
323 else if name = NAME_BYTE then result := TType.Byte_
324 else if name = NAME_I16 then result := TType.I16
325 else if name = NAME_I32 then result := TType.I32
326 else if name = NAME_I64 then result := TType.I64
327 else if name = NAME_DOUBLE then result := TType.Double_
328 else if name = NAME_STRUCT then result := TType.Struct
329 else if name = NAME_STRING then result := TType.String_
330 else if name = NAME_MAP then result := TType.Map
331 else if name = NAME_LIST then result := TType.List
332 else if name = NAME_SET then result := TType.Set_
Jens Geyere0e32402016-04-20 21:50:48 +0200333 else raise TProtocolExceptionNotImplemented.Create('Unrecognized type ('+name+')');
Jake Farrell27274222011-11-10 20:32:44 +0000334end;
335
336
337constructor TJSONProtocolImpl.TJSONBaseContext.Create( const aProto : IJSONProtocol);
338begin
339 inherited Create;
Roger Meierfebe8452012-06-06 10:32:24 +0000340 FProto := Pointer(aProto);
Jake Farrell27274222011-11-10 20:32:44 +0000341end;
342
343
344procedure TJSONProtocolImpl.TJSONBaseContext.Write;
345begin
346 // nothing
347end;
348
349
350procedure TJSONProtocolImpl.TJSONBaseContext.Read;
351begin
352 // nothing
353end;
354
355
356function TJSONProtocolImpl.TJSONBaseContext.EscapeNumbers : Boolean;
357begin
358 result := FALSE;
359end;
360
361
362constructor TJSONProtocolImpl.TJSONListContext.Create( const aProto : IJSONProtocol);
363begin
364 inherited Create( aProto);
365 FFirst := TRUE;
366end;
367
368
369procedure TJSONProtocolImpl.TJSONListContext.Write;
370begin
371 if FFirst
372 then FFirst := FALSE
Roger Meierfebe8452012-06-06 10:32:24 +0000373 else IJSONProtocol(FProto).Transport.Write( COMMA);
Jake Farrell27274222011-11-10 20:32:44 +0000374end;
375
376
377procedure TJSONProtocolImpl.TJSONListContext.Read;
378begin
379 if FFirst
380 then FFirst := FALSE
Roger Meierfebe8452012-06-06 10:32:24 +0000381 else IJSONProtocol(FProto).ReadJSONSyntaxChar( COMMA[0]);
Jake Farrell27274222011-11-10 20:32:44 +0000382end;
383
384
385constructor TJSONProtocolImpl.TJSONPairContext.Create( const aProto : IJSONProtocol);
386begin
387 inherited Create( aProto);
388 FFirst := TRUE;
389 FColon := TRUE;
390end;
391
392
393procedure TJSONProtocolImpl.TJSONPairContext.Write;
394begin
395 if FFirst then begin
396 FFirst := FALSE;
397 FColon := TRUE;
398 end
399 else begin
400 if FColon
Roger Meierfebe8452012-06-06 10:32:24 +0000401 then IJSONProtocol(FProto).Transport.Write( COLON)
402 else IJSONProtocol(FProto).Transport.Write( COMMA);
Jake Farrell27274222011-11-10 20:32:44 +0000403 FColon := not FColon;
404 end;
405end;
406
407
408procedure TJSONProtocolImpl.TJSONPairContext.Read;
409begin
410 if FFirst then begin
411 FFirst := FALSE;
412 FColon := TRUE;
413 end
414 else begin
415 if FColon
Roger Meierfebe8452012-06-06 10:32:24 +0000416 then IJSONProtocol(FProto).ReadJSONSyntaxChar( COLON[0])
417 else IJSONProtocol(FProto).ReadJSONSyntaxChar( COMMA[0]);
Jake Farrell27274222011-11-10 20:32:44 +0000418 FColon := not FColon;
419 end;
420end;
421
422
423function TJSONProtocolImpl.TJSONPairContext.EscapeNumbers : Boolean;
424begin
425 result := FColon;
426end;
427
428
429constructor TJSONProtocolImpl.TLookaheadReader.Create( const aProto : IJSONProtocol);
430begin
431 inherited Create;
Roger Meierfebe8452012-06-06 10:32:24 +0000432 FProto := Pointer(aProto);
Jake Farrell27274222011-11-10 20:32:44 +0000433 FHasData := FALSE;
434end;
435
436
437function TJSONProtocolImpl.TLookaheadReader.Read : Byte;
438begin
439 if FHasData
440 then FHasData := FALSE
441 else begin
Jens Geyer17c3ad92017-09-05 20:31:27 +0200442 IJSONProtocol(FProto).Transport.ReadAll( @FData, SizeOf(FData), 0, 1);
Jake Farrell27274222011-11-10 20:32:44 +0000443 end;
Jens Geyer17c3ad92017-09-05 20:31:27 +0200444 result := FData;
Jake Farrell27274222011-11-10 20:32:44 +0000445end;
446
447
448function TJSONProtocolImpl.TLookaheadReader.Peek : Byte;
449begin
450 if not FHasData then begin
Jens Geyer17c3ad92017-09-05 20:31:27 +0200451 IJSONProtocol(FProto).Transport.ReadAll( @FData, SizeOf(FData), 0, 1);
Jake Farrell27274222011-11-10 20:32:44 +0000452 FHasData := TRUE;
453 end;
Jens Geyer17c3ad92017-09-05 20:31:27 +0200454 result := FData;
Jake Farrell27274222011-11-10 20:32:44 +0000455end;
456
457
Roger Meier333bbf32012-01-08 21:51:08 +0000458constructor TJSONProtocolImpl.Create( const aTrans : ITransport);
Jake Farrell27274222011-11-10 20:32:44 +0000459begin
460 inherited Create( aTrans);
461
462 // Stack of nested contexts that we may be in
463 FContextStack := TStack<TJSONBaseContext>.Create;
464
465 FContext := TJSONBaseContext.Create( Self);
466 FReader := TLookaheadReader.Create( Self);
467end;
468
469
470destructor TJSONProtocolImpl.Destroy;
471begin
472 try
Roger Meier45a37262012-01-08 21:44:44 +0000473 ResetContextStack; // free any contents
Jake Farrell27274222011-11-10 20:32:44 +0000474 FreeAndNil( FReader);
475 FreeAndNil( FContext);
476 FreeAndNil( FContextStack);
477 finally
478 inherited Destroy;
479 end;
480end;
481
482
Roger Meier45a37262012-01-08 21:44:44 +0000483procedure TJSONProtocolImpl.ResetContextStack;
484begin
485 while FContextStack.Count > 0
486 do PopContext;
487end;
488
489
Roger Meier333bbf32012-01-08 21:51:08 +0000490procedure TJSONProtocolImpl.PushContext( const aCtx : TJSONBaseContext);
Roger Meier45a37262012-01-08 21:44:44 +0000491begin
492 FContextStack.Push( FContext);
493 FContext := aCtx;
494end;
495
496
497procedure TJSONProtocolImpl.PopContext;
498begin
499 FreeAndNil(FContext);
500 FContext := FContextStack.Pop;
501end;
502
503
Jake Farrell27274222011-11-10 20:32:44 +0000504procedure TJSONProtocolImpl.ReadJSONSyntaxChar( b : Byte);
505var ch : Byte;
506begin
507 ch := FReader.Read;
508 if (ch <> b)
Jens Geyere0e32402016-04-20 21:50:48 +0200509 then raise TProtocolExceptionInvalidData.Create('Unexpected character ('+Char(ch)+')');
Jake Farrell27274222011-11-10 20:32:44 +0000510end;
511
512
513class function TJSONProtocolImpl.HexVal( ch : Byte) : Byte;
514var i : Integer;
515begin
516 i := StrToIntDef( '$0'+Char(ch), -1);
517 if (0 <= i) and (i < $10)
518 then result := i
Jens Geyere0e32402016-04-20 21:50:48 +0200519 else raise TProtocolExceptionInvalidData.Create('Expected hex character ('+Char(ch)+')');
Jake Farrell27274222011-11-10 20:32:44 +0000520end;
521
522
523class function TJSONProtocolImpl.HexChar( val : Byte) : Byte;
524const HEXCHARS = '0123456789ABCDEF';
525begin
526 result := Byte( PChar(HEXCHARS)[val and $0F]);
527 ASSERT( Pos( Char(result), HEXCHARS) > 0);
528end;
529
530
Roger Meier333bbf32012-01-08 21:51:08 +0000531procedure TJSONProtocolImpl.WriteJSONString( const str : string);
Jake Farrell27274222011-11-10 20:32:44 +0000532begin
533 WriteJSONString( SysUtils.TEncoding.UTF8.GetBytes( str));
534end;
535
536
537procedure TJSONProtocolImpl.WriteJSONString( const b : TBytes);
538var i : Integer;
539 tmp : TBytes;
540begin
541 FContext.Write;
542 Transport.Write( QUOTE);
543 for i := 0 to Length(b)-1 do begin
544
545 if (b[i] and $00FF) >= $30 then begin
546
547 if (b[i] = BACKSLASH[0]) then begin
548 Transport.Write( BACKSLASH);
549 Transport.Write( BACKSLASH);
550 end
551 else begin
552 Transport.Write( b, i, 1);
553 end;
554
555 end
556 else begin
557 SetLength( tmp, 2);
558 tmp[0] := JSON_CHAR_TABLE[b[i]];
559 if (tmp[0] = 1) then begin
560 Transport.Write( b, i, 1)
561 end
562 else if (tmp[0] > 1) then begin
563 Transport.Write( BACKSLASH);
564 Transport.Write( tmp, 0, 1);
565 end
566 else begin
567 Transport.Write( ESCSEQ);
568 tmp[0] := HexChar( b[i] div $10);
569 tmp[1] := HexChar( b[i]);
570 Transport.Write( tmp, 0, 2);
571 end;
572 end;
573 end;
574 Transport.Write( QUOTE);
575end;
576
577
Roger Meier333bbf32012-01-08 21:51:08 +0000578procedure TJSONProtocolImpl.WriteJSONInteger( const num : Int64);
Jake Farrell27274222011-11-10 20:32:44 +0000579var str : String;
580 escapeNum : Boolean;
581begin
582 FContext.Write;
583 str := IntToStr(num);
584
585 escapeNum := FContext.EscapeNumbers;
586 if escapeNum
587 then Transport.Write( QUOTE);
588
589 Transport.Write( SysUtils.TEncoding.UTF8.GetBytes( str));
590
591 if escapeNum
592 then Transport.Write( QUOTE);
593end;
594
595
596procedure TJSONProtocolImpl.WriteJSONDouble( const num : Double);
597var str : string;
598 special : Boolean;
599 escapeNum : Boolean;
600begin
601 FContext.Write;
602
603 str := FloatToStr( num, INVARIANT_CULTURE);
604 special := FALSE;
605
606 case UpCase(str[1]) of
607 'N' : special := TRUE; // NaN
608 'I' : special := TRUE; // Infinity
609 '-' : special := (UpCase(str[2]) = 'I'); // -Infinity
610 end;
611
612 escapeNum := special or FContext.EscapeNumbers;
613
614
615 if escapeNum
616 then Transport.Write( QUOTE);
617
618 Transport.Write( SysUtils.TEncoding.UTF8.GetBytes( str));
619
620 if escapeNum
621 then Transport.Write( QUOTE);
622end;
623
624
625procedure TJSONProtocolImpl.WriteJSONBase64( const b : TBytes);
Jens Geyerd8bddbc2014-12-14 00:41:33 +0100626var len, off, cnt : Integer;
627 tmpBuf : TBytes;
Jake Farrell27274222011-11-10 20:32:44 +0000628begin
629 FContext.Write;
630 Transport.Write( QUOTE);
631
Jens Geyerd8bddbc2014-12-14 00:41:33 +0100632 len := Length(b);
633 off := 0;
634 SetLength( tmpBuf, 4);
635
636 while len >= 3 do begin
637 // Encode 3 bytes at a time
638 Base64Utils.Encode( b, off, 3, tmpBuf, 0);
639 Transport.Write( tmpBuf, 0, 4);
640 Inc( off, 3);
641 Dec( len, 3);
Jake Farrell27274222011-11-10 20:32:44 +0000642 end;
Jens Geyerd8bddbc2014-12-14 00:41:33 +0100643
644 // Encode remainder, if any
645 if len > 0 then begin
646 cnt := Base64Utils.Encode( b, off, len, tmpBuf, 0);
647 Transport.Write( tmpBuf, 0, cnt);
648 end;
Jake Farrell27274222011-11-10 20:32:44 +0000649
650 Transport.Write( QUOTE);
651end;
652
653
654procedure TJSONProtocolImpl.WriteJSONObjectStart;
655begin
656 FContext.Write;
657 Transport.Write( LBRACE);
658 PushContext( TJSONPairContext.Create( Self));
659end;
660
661
662procedure TJSONProtocolImpl.WriteJSONObjectEnd;
663begin
664 PopContext;
665 Transport.Write( RBRACE);
666end;
667
668
669procedure TJSONProtocolImpl.WriteJSONArrayStart;
670begin
671 FContext.Write;
672 Transport.Write( LBRACKET);
673 PushContext( TJSONListContext.Create( Self));
674end;
675
676
677procedure TJSONProtocolImpl.WriteJSONArrayEnd;
678begin
679 PopContext;
680 Transport.Write( RBRACKET);
681end;
682
683
Jens Geyer17c3ad92017-09-05 20:31:27 +0200684procedure TJSONProtocolImpl.WriteMessageBegin( const aMsg : TThriftMessage);
Jake Farrell27274222011-11-10 20:32:44 +0000685begin
Roger Meier45a37262012-01-08 21:44:44 +0000686 ResetContextStack; // THRIFT-1473
687
Jake Farrell27274222011-11-10 20:32:44 +0000688 WriteJSONArrayStart;
689 WriteJSONInteger(VERSION);
690
691 WriteJSONString( SysUtils.TEncoding.UTF8.GetBytes( aMsg.Name));
692
693 WriteJSONInteger( LongInt( aMsg.Type_));
694 WriteJSONInteger( aMsg.SeqID);
695end;
696
697procedure TJSONProtocolImpl.WriteMessageEnd;
698begin
699 WriteJSONArrayEnd;
700end;
701
702
Jens Geyer17c3ad92017-09-05 20:31:27 +0200703procedure TJSONProtocolImpl.WriteStructBegin( const struc: TThriftStruct);
Jake Farrell27274222011-11-10 20:32:44 +0000704begin
705 WriteJSONObjectStart;
706end;
707
708
709procedure TJSONProtocolImpl.WriteStructEnd;
710begin
711 WriteJSONObjectEnd;
712end;
713
714
Jens Geyer17c3ad92017-09-05 20:31:27 +0200715procedure TJSONProtocolImpl.WriteFieldBegin( const field : TThriftField);
Jake Farrell27274222011-11-10 20:32:44 +0000716begin
717 WriteJSONInteger(field.ID);
718 WriteJSONObjectStart;
719 WriteJSONString( GetTypeNameForTypeID(field.Type_));
720end;
721
722
723procedure TJSONProtocolImpl.WriteFieldEnd;
724begin
725 WriteJSONObjectEnd;
726end;
727
728
729procedure TJSONProtocolImpl.WriteFieldStop;
730begin
731 // nothing to do
732end;
733
Jens Geyer17c3ad92017-09-05 20:31:27 +0200734procedure TJSONProtocolImpl.WriteMapBegin( const map: TThriftMap);
Jake Farrell27274222011-11-10 20:32:44 +0000735begin
736 WriteJSONArrayStart;
737 WriteJSONString( GetTypeNameForTypeID( map.KeyType));
738 WriteJSONString( GetTypeNameForTypeID( map.ValueType));
739 WriteJSONInteger( map.Count);
740 WriteJSONObjectStart;
741end;
742
743
744procedure TJSONProtocolImpl.WriteMapEnd;
745begin
746 WriteJSONObjectEnd;
747 WriteJSONArrayEnd;
748end;
749
750
Jens Geyer17c3ad92017-09-05 20:31:27 +0200751procedure TJSONProtocolImpl.WriteListBegin( const list: TThriftList);
Jake Farrell27274222011-11-10 20:32:44 +0000752begin
753 WriteJSONArrayStart;
754 WriteJSONString( GetTypeNameForTypeID( list.ElementType));
755 WriteJSONInteger(list.Count);
756end;
757
758
759procedure TJSONProtocolImpl.WriteListEnd;
760begin
761 WriteJSONArrayEnd;
762end;
763
764
Jens Geyer17c3ad92017-09-05 20:31:27 +0200765procedure TJSONProtocolImpl.WriteSetBegin( const set_: TThriftSet);
Jake Farrell27274222011-11-10 20:32:44 +0000766begin
767 WriteJSONArrayStart;
768 WriteJSONString( GetTypeNameForTypeID( set_.ElementType));
769 WriteJSONInteger( set_.Count);
770end;
771
772
773procedure TJSONProtocolImpl.WriteSetEnd;
774begin
775 WriteJSONArrayEnd;
776end;
777
778procedure TJSONProtocolImpl.WriteBool( b: Boolean);
779begin
780 if b
781 then WriteJSONInteger( 1)
782 else WriteJSONInteger( 0);
783end;
784
785procedure TJSONProtocolImpl.WriteByte( b: ShortInt);
786begin
787 WriteJSONInteger( b);
788end;
789
790procedure TJSONProtocolImpl.WriteI16( i16: SmallInt);
791begin
792 WriteJSONInteger( i16);
793end;
794
795procedure TJSONProtocolImpl.WriteI32( i32: Integer);
796begin
797 WriteJSONInteger( i32);
798end;
799
Roger Meier333bbf32012-01-08 21:51:08 +0000800procedure TJSONProtocolImpl.WriteI64( const i64: Int64);
Jake Farrell27274222011-11-10 20:32:44 +0000801begin
802 WriteJSONInteger(i64);
803end;
804
Roger Meier333bbf32012-01-08 21:51:08 +0000805procedure TJSONProtocolImpl.WriteDouble( const d: Double);
Jake Farrell27274222011-11-10 20:32:44 +0000806begin
807 WriteJSONDouble( d);
808end;
809
810procedure TJSONProtocolImpl.WriteString( const s: string );
811begin
812 WriteJSONString( SysUtils.TEncoding.UTF8.GetBytes( s));
813end;
814
815procedure TJSONProtocolImpl.WriteBinary( const b: TBytes);
816begin
817 WriteJSONBase64( b);
818end;
819
820
821function TJSONProtocolImpl.ReadJSONString( skipContext : Boolean) : TBytes;
822var buffer : TMemoryStream;
Jens Geyer7bb44a32014-02-07 22:24:37 +0100823 ch : Byte;
824 wch : Word;
Phongphan Phutthaa6509f72015-10-31 01:09:47 +0700825 highSurogate: Char;
826 surrogatePairs: Array[0..1] of Char;
Jake Farrell27274222011-11-10 20:32:44 +0000827 off : Integer;
828 tmp : TBytes;
829begin
Phongphan Phutthaa6509f72015-10-31 01:09:47 +0700830 highSurogate := #0;
Jake Farrell27274222011-11-10 20:32:44 +0000831 buffer := TMemoryStream.Create;
832 try
833 if not skipContext
834 then FContext.Read;
835
836 ReadJSONSyntaxChar( QUOTE[0]);
837
838 while TRUE do begin
839 ch := FReader.Read;
840
841 if (ch = QUOTE[0])
842 then Break;
843
Jens Geyer7bb44a32014-02-07 22:24:37 +0100844 // check for escapes
845 if (ch <> ESCSEQ[0]) then begin
846 buffer.Write( ch, 1);
847 Continue;
Jake Farrell27274222011-11-10 20:32:44 +0000848 end;
Jens Geyer7bb44a32014-02-07 22:24:37 +0100849
850 // distuinguish between \uNNNN and \?
851 ch := FReader.Read;
852 if (ch <> ESCSEQ[1])
853 then begin
854 off := Pos( Char(ch), ESCAPE_CHARS);
855 if off < 1
Jens Geyere0e32402016-04-20 21:50:48 +0200856 then raise TProtocolExceptionInvalidData.Create('Expected control char');
Jens Geyer7bb44a32014-02-07 22:24:37 +0100857 ch := Byte( ESCAPE_CHAR_VALS[off]);
858 buffer.Write( ch, 1);
859 Continue;
860 end;
861
862 // it is \uXXXX
863 SetLength( tmp, 4);
864 Transport.ReadAll( tmp, 0, 4);
865 wch := (HexVal(tmp[0]) shl 12)
866 + (HexVal(tmp[1]) shl 8)
867 + (HexVal(tmp[2]) shl 4)
868 + HexVal(tmp[3]);
Phongphan Phutthaa6509f72015-10-31 01:09:47 +0700869
Jens Geyer7bb44a32014-02-07 22:24:37 +0100870 // we need to make UTF8 bytes from it, to be decoded later
Jens Geyer71070432016-01-29 10:08:39 +0100871 if CharUtils.IsHighSurrogate(char(wch)) then begin
Phongphan Phutthaa6509f72015-10-31 01:09:47 +0700872 if highSurogate <> #0
Jens Geyere0e32402016-04-20 21:50:48 +0200873 then raise TProtocolExceptionInvalidData.Create('Expected low surrogate char');
Phongphan Phutthaa6509f72015-10-31 01:09:47 +0700874 highSurogate := char(wch);
875 end
Jens Geyer71070432016-01-29 10:08:39 +0100876 else if CharUtils.IsLowSurrogate(char(wch)) then begin
Phongphan Phutthaa6509f72015-10-31 01:09:47 +0700877 if highSurogate = #0
Jens Geyere0e32402016-04-20 21:50:48 +0200878 then TProtocolExceptionInvalidData.Create('Expected high surrogate char');
Phongphan Phutthaa6509f72015-10-31 01:09:47 +0700879 surrogatePairs[0] := highSurogate;
880 surrogatePairs[1] := char(wch);
881 tmp := TEncoding.UTF8.GetBytes(surrogatePairs);
882 buffer.Write( tmp[0], Length(tmp));
883 highSurogate := #0;
884 end
885 else begin
886 tmp := SysUtils.TEncoding.UTF8.GetBytes(Char(wch));
887 buffer.Write( tmp[0], Length(tmp));
888 end;
Jake Farrell27274222011-11-10 20:32:44 +0000889 end;
890
Phongphan Phutthaa6509f72015-10-31 01:09:47 +0700891 if highSurogate <> #0
Jens Geyere0e32402016-04-20 21:50:48 +0200892 then raise TProtocolExceptionInvalidData.Create('Expected low surrogate char');
Phongphan Phutthaa6509f72015-10-31 01:09:47 +0700893
Jake Farrell27274222011-11-10 20:32:44 +0000894 SetLength( result, buffer.Size);
Jake Farrella2a9ee92011-12-15 20:50:31 +0000895 if buffer.Size > 0 then Move( buffer.Memory^, result[0], Length(result));
Jake Farrell27274222011-11-10 20:32:44 +0000896
897 finally
898 buffer.Free;
899 end;
900end;
901
902
903function TJSONProtocolImpl.IsJSONNumeric( b : Byte) : Boolean;
904const NUMCHARS = ['+','-','.','0','1','2','3','4','5','6','7','8','9','E','e'];
905begin
906 result := CharInSet( Char(b), NUMCHARS);
907end;
908
909
910function TJSONProtocolImpl.ReadJSONNumericChars : string;
911var strbld : TThriftStringBuilder;
912 ch : Byte;
913begin
914 strbld := TThriftStringBuilder.Create;
915 try
916 while TRUE do begin
917 ch := FReader.Peek;
918 if IsJSONNumeric(ch)
919 then strbld.Append( Char(FReader.Read))
920 else Break;
921 end;
922 result := strbld.ToString;
923
924 finally
925 strbld.Free;
926 end;
927end;
928
929
930function TJSONProtocolImpl.ReadJSONInteger : Int64;
931var str : string;
932begin
933 FContext.Read;
934 if FContext.EscapeNumbers
935 then ReadJSONSyntaxChar( QUOTE[0]);
936
937 str := ReadJSONNumericChars;
938
939 if FContext.EscapeNumbers
940 then ReadJSONSyntaxChar( QUOTE[0]);
941
942 try
943 result := StrToInt64(str);
944 except
945 on e:Exception do begin
Jens Geyere0e32402016-04-20 21:50:48 +0200946 raise TProtocolExceptionInvalidData.Create('Bad data encounted in numeric data ('+str+') ('+e.Message+')');
Jake Farrell27274222011-11-10 20:32:44 +0000947 end;
948 end;
949end;
950
951
952function TJSONProtocolImpl.ReadJSONDouble : Double;
953var dub : Double;
954 str : string;
955begin
956 FContext.Read;
957
958 if FReader.Peek = QUOTE[0]
959 then begin
960 str := SysUtils.TEncoding.UTF8.GetString( ReadJSONString( TRUE));
961 dub := StrToFloat( str, INVARIANT_CULTURE);
962
963 if not FContext.EscapeNumbers()
964 and not Math.IsNaN(dub)
965 and not Math.IsInfinite(dub)
966 then begin
967 // Throw exception -- we should not be in a string in Self case
Jens Geyere0e32402016-04-20 21:50:48 +0200968 raise TProtocolExceptionInvalidData.Create('Numeric data unexpectedly quoted');
Jake Farrell27274222011-11-10 20:32:44 +0000969 end;
970 result := dub;
971 Exit;
972 end;
973
974 // will throw - we should have had a quote if escapeNum == true
975 if FContext.EscapeNumbers
976 then ReadJSONSyntaxChar( QUOTE[0]);
977
978 try
979 str := ReadJSONNumericChars;
980 result := StrToFloat( str, INVARIANT_CULTURE);
981 except
982 on e:Exception
Jens Geyere0e32402016-04-20 21:50:48 +0200983 do raise TProtocolExceptionInvalidData.Create('Bad data encounted in numeric data ('+str+') ('+e.Message+')');
Jake Farrell27274222011-11-10 20:32:44 +0000984 end;
985end;
986
987
988function TJSONProtocolImpl.ReadJSONBase64 : TBytes;
989var b : TBytes;
Jens Geyer9f9535c2014-12-14 04:16:05 +0100990 len, off, size : Integer;
Jake Farrell27274222011-11-10 20:32:44 +0000991begin
992 b := ReadJSONString(false);
993
Jens Geyerd8bddbc2014-12-14 00:41:33 +0100994 len := Length(b);
995 off := 0;
996 size := 0;
997
998 // reduce len to ignore fill bytes
999 Dec(len);
1000 while (len >= 0) and (b[len] = Byte('=')) do Dec(len);
1001 Inc(len);
1002
1003 // read & decode full byte triplets = 4 source bytes
1004 while (len >= 4) do begin
1005 // Decode 4 bytes at a time
1006 Inc( size, Base64Utils.Decode( b, off, 4, b, size)); // decoded in place
1007 Inc( off, 4);
1008 Dec( len, 4);
1009 end;
1010
1011 // Don't decode if we hit the end or got a single leftover byte (invalid
1012 // base64 but legal for skip of regular string type)
1013 if len > 1 then begin
1014 // Decode remainder
1015 Inc( size, Base64Utils.Decode( b, off, len, b, size)); // decoded in place
1016 end;
1017
1018 // resize to final size and return the data
1019 SetLength( b, size);
1020 result := b;
Jake Farrell27274222011-11-10 20:32:44 +00001021end;
1022
1023
1024procedure TJSONProtocolImpl.ReadJSONObjectStart;
1025begin
1026 FContext.Read;
1027 ReadJSONSyntaxChar( LBRACE[0]);
1028 PushContext( TJSONPairContext.Create( Self));
1029end;
1030
1031
1032procedure TJSONProtocolImpl.ReadJSONObjectEnd;
1033begin
1034 ReadJSONSyntaxChar( RBRACE[0]);
1035 PopContext;
1036end;
1037
1038
1039procedure TJSONProtocolImpl.ReadJSONArrayStart;
1040begin
1041 FContext.Read;
1042 ReadJSONSyntaxChar( LBRACKET[0]);
1043 PushContext( TJSONListContext.Create( Self));
1044end;
1045
1046
1047procedure TJSONProtocolImpl.ReadJSONArrayEnd;
1048begin
1049 ReadJSONSyntaxChar( RBRACKET[0]);
1050 PopContext;
1051end;
1052
1053
Jens Geyer17c3ad92017-09-05 20:31:27 +02001054function TJSONProtocolImpl.ReadMessageBegin: TThriftMessage;
Jake Farrell27274222011-11-10 20:32:44 +00001055begin
Roger Meier45a37262012-01-08 21:44:44 +00001056 ResetContextStack; // THRIFT-1473
1057
Jens Geyer17c3ad92017-09-05 20:31:27 +02001058 Init( result);
Jake Farrell27274222011-11-10 20:32:44 +00001059 ReadJSONArrayStart;
1060
1061 if ReadJSONInteger <> VERSION
Jens Geyere0e32402016-04-20 21:50:48 +02001062 then raise TProtocolExceptionBadVersion.Create('Message contained bad version.');
Jake Farrell27274222011-11-10 20:32:44 +00001063
1064 result.Name := SysUtils.TEncoding.UTF8.GetString( ReadJSONString( FALSE));
1065 result.Type_ := TMessageType( ReadJSONInteger);
1066 result.SeqID := ReadJSONInteger;
1067end;
1068
1069
1070procedure TJSONProtocolImpl.ReadMessageEnd;
1071begin
1072 ReadJSONArrayEnd;
1073end;
1074
1075
Jens Geyer17c3ad92017-09-05 20:31:27 +02001076function TJSONProtocolImpl.ReadStructBegin : TThriftStruct ;
Jake Farrell27274222011-11-10 20:32:44 +00001077begin
1078 ReadJSONObjectStart;
Jens Geyer17c3ad92017-09-05 20:31:27 +02001079 Init( result);
Jake Farrell27274222011-11-10 20:32:44 +00001080end;
1081
1082
1083procedure TJSONProtocolImpl.ReadStructEnd;
1084begin
1085 ReadJSONObjectEnd;
1086end;
1087
1088
Jens Geyer17c3ad92017-09-05 20:31:27 +02001089function TJSONProtocolImpl.ReadFieldBegin : TThriftField;
Jake Farrell27274222011-11-10 20:32:44 +00001090var ch : Byte;
1091 str : string;
1092begin
Jens Geyer17c3ad92017-09-05 20:31:27 +02001093 Init( result);
Jake Farrell27274222011-11-10 20:32:44 +00001094 ch := FReader.Peek;
1095 if ch = RBRACE[0]
1096 then result.Type_ := TType.Stop
1097 else begin
1098 result.ID := ReadJSONInteger;
1099 ReadJSONObjectStart;
1100
1101 str := SysUtils.TEncoding.UTF8.GetString( ReadJSONString( FALSE));
1102 result.Type_ := GetTypeIDForTypeName( str);
1103 end;
1104end;
1105
1106
1107procedure TJSONProtocolImpl.ReadFieldEnd;
1108begin
1109 ReadJSONObjectEnd;
1110end;
1111
1112
Jens Geyer17c3ad92017-09-05 20:31:27 +02001113function TJSONProtocolImpl.ReadMapBegin : TThriftMap;
Jake Farrell27274222011-11-10 20:32:44 +00001114var str : string;
1115begin
Jens Geyer17c3ad92017-09-05 20:31:27 +02001116 Init( result);
Jake Farrell27274222011-11-10 20:32:44 +00001117 ReadJSONArrayStart;
1118
1119 str := SysUtils.TEncoding.UTF8.GetString( ReadJSONString(FALSE));
1120 result.KeyType := GetTypeIDForTypeName( str);
1121
1122 str := SysUtils.TEncoding.UTF8.GetString( ReadJSONString(FALSE));
1123 result.ValueType := GetTypeIDForTypeName( str);
1124
1125 result.Count := ReadJSONInteger;
1126 ReadJSONObjectStart;
1127end;
1128
1129
1130procedure TJSONProtocolImpl.ReadMapEnd;
1131begin
1132 ReadJSONObjectEnd;
1133 ReadJSONArrayEnd;
1134end;
1135
1136
Jens Geyer17c3ad92017-09-05 20:31:27 +02001137function TJSONProtocolImpl.ReadListBegin : TThriftList;
Jake Farrell27274222011-11-10 20:32:44 +00001138var str : string;
1139begin
Jens Geyer17c3ad92017-09-05 20:31:27 +02001140 Init( result);
Jake Farrell27274222011-11-10 20:32:44 +00001141 ReadJSONArrayStart;
1142
1143 str := SysUtils.TEncoding.UTF8.GetString( ReadJSONString(FALSE));
1144 result.ElementType := GetTypeIDForTypeName( str);
1145 result.Count := ReadJSONInteger;
1146end;
1147
1148
1149procedure TJSONProtocolImpl.ReadListEnd;
1150begin
1151 ReadJSONArrayEnd;
1152end;
1153
1154
Jens Geyer17c3ad92017-09-05 20:31:27 +02001155function TJSONProtocolImpl.ReadSetBegin : TThriftSet;
Jake Farrell27274222011-11-10 20:32:44 +00001156var str : string;
1157begin
Jens Geyer17c3ad92017-09-05 20:31:27 +02001158 Init( result);
Jake Farrell27274222011-11-10 20:32:44 +00001159 ReadJSONArrayStart;
1160
1161 str := SysUtils.TEncoding.UTF8.GetString( ReadJSONString(FALSE));
1162 result.ElementType := GetTypeIDForTypeName( str);
1163 result.Count := ReadJSONInteger;
1164end;
1165
1166
1167procedure TJSONProtocolImpl.ReadSetEnd;
1168begin
1169 ReadJSONArrayEnd;
1170end;
1171
1172
1173function TJSONProtocolImpl.ReadBool : Boolean;
1174begin
1175 result := (ReadJSONInteger <> 0);
1176end;
1177
1178
1179function TJSONProtocolImpl.ReadByte : ShortInt;
1180begin
1181 result := ReadJSONInteger;
1182end;
1183
1184
1185function TJSONProtocolImpl.ReadI16 : SmallInt;
1186begin
1187 result := ReadJSONInteger;
1188end;
1189
1190
1191function TJSONProtocolImpl.ReadI32 : LongInt;
1192begin
1193 result := ReadJSONInteger;
1194end;
1195
1196
1197function TJSONProtocolImpl.ReadI64 : Int64;
1198begin
1199 result := ReadJSONInteger;
1200end;
1201
1202
1203function TJSONProtocolImpl.ReadDouble : Double;
1204begin
1205 result := ReadJSONDouble;
1206end;
1207
1208
1209function TJSONProtocolImpl.ReadString : string;
1210begin
1211 result := SysUtils.TEncoding.UTF8.GetString( ReadJSONString( FALSE));
1212end;
1213
1214
1215function TJSONProtocolImpl.ReadBinary : TBytes;
1216begin
1217 result := ReadJSONBase64;
1218end;
1219
1220
1221//--- init code ---
1222
1223procedure InitBytes( var b : TBytes; aData : array of Byte);
1224begin
1225 SetLength( b, Length(aData));
1226 Move( aData, b[0], Length(b));
1227end;
1228
1229initialization
1230 InitBytes( COMMA, [Byte(',')]);
1231 InitBytes( COLON, [Byte(':')]);
1232 InitBytes( LBRACE, [Byte('{')]);
1233 InitBytes( RBRACE, [Byte('}')]);
1234 InitBytes( LBRACKET, [Byte('[')]);
1235 InitBytes( RBRACKET, [Byte(']')]);
1236 InitBytes( QUOTE, [Byte('"')]);
1237 InitBytes( BACKSLASH, [Byte('\')]);
Jake Farrell27274222011-11-10 20:32:44 +00001238 InitBytes( ESCSEQ, [Byte('\'),Byte('u'),Byte('0'),Byte('0')]);
1239end.