]> git.proxmox.com Git - ceph.git/blame - ceph/src/jaegertracing/thrift/lib/haxe/src/org/apache/thrift/protocol/TJSONProtocol.hx
buildsys: switch source download to quincy
[ceph.git] / ceph / src / jaegertracing / thrift / lib / haxe / src / org / apache / thrift / protocol / TJSONProtocol.hx
CommitLineData
f67539c2
TL
1/*
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
20package org.apache.thrift.protocol;
21
22import haxe.io.Bytes;
23import haxe.io.BytesInput;
24import haxe.io.BytesOutput;
25import haxe.io.BytesBuffer;
26import haxe.ds.GenericStack;
27import haxe.Utf8;
28import haxe.crypto.Base64;
29import haxe.Int64;
30
31import org.apache.thrift.TException;
32import org.apache.thrift.protocol.TMessage;
33import org.apache.thrift.protocol.TField;
34import org.apache.thrift.protocol.TMap;
35import org.apache.thrift.protocol.TSet;
36import org.apache.thrift.protocol.TList;
37import org.apache.thrift.transport.TTransport;
38
39
40
41/* JSON protocol implementation for thrift.
42* This is a full-featured protocol supporting Write and Read.
43*
44* Please see the C++ class header for a detailed description of the wire format.
45*
46* Adapted from the Java version.
47*/
48class TJSONProtocol extends TRecursionTracker implements TProtocol {
49
50 public var trans(default,null) : TTransport;
51
52 // Stack of nested contexts that we may be in
53 private var contextStack : GenericStack<JSONBaseContext> = new GenericStack<JSONBaseContext>();
54
55 // Current context that we are in
56 private var context : JSONBaseContext;
57
58 // Reader that manages a 1-byte buffer
59 private var reader : LookaheadReader;
60
61 // whether the underlying system holds Strings as UTF-8
62 // http://old.haxe.org/manual/encoding
63 private static var utf8Strings = haxe.Utf8.validate("Ç-ß-Æ-Ю-Ш");
64
65 // TJSONProtocol Constructor
66 public function new( trans : TTransport)
67 {
68 this.trans = trans;
69 this.context = new JSONBaseContext(this);
70 this.reader = new LookaheadReader(this);
71 }
72
73 public function getTransport() : TTransport {
74 return trans;
75 }
76
77 public function writeMessageBegin(message:TMessage) : Void {
78 WriteJSONArrayStart();
79 WriteJSONInteger( JSONConstants.VERSION);
80 WriteJSONString( BytesFromString(message.name));
81 WriteJSONInteger( message.type);
82 WriteJSONInteger( message.seqid);
83 }
84
85 public function writeMessageEnd() : Void {
86 WriteJSONArrayEnd();
87 }
88
89 public function writeStructBegin(struct:TStruct) : Void {
90 WriteJSONObjectStart();
91 }
92
93 public function writeStructEnd() : Void {
94 WriteJSONObjectEnd();
95 }
96
97 public function writeFieldBegin(field:TField) : Void {
98 WriteJSONInteger( field.id );
99 WriteJSONObjectStart();
100 WriteJSONString( BytesFromString( JSONConstants.GetTypeNameForTypeID( field.type)));
101 }
102
103 public function writeFieldEnd() : Void {
104 WriteJSONObjectEnd();
105 }
106
107 public function writeFieldStop() : Void { }
108
109 public function writeMapBegin(map:TMap) : Void {
110 WriteJSONArrayStart();
111 WriteJSONString( BytesFromString( JSONConstants.GetTypeNameForTypeID( map.keyType)));
112 WriteJSONString( BytesFromString( JSONConstants.GetTypeNameForTypeID( map.valueType)));
113 WriteJSONInteger( map.size);
114 WriteJSONObjectStart();
115 }
116
117 public function writeMapEnd() : Void {
118 WriteJSONObjectEnd();
119 WriteJSONArrayEnd();
120 }
121
122 public function writeListBegin(list:TList) : Void {
123 WriteJSONArrayStart();
124 WriteJSONString( BytesFromString( JSONConstants.GetTypeNameForTypeID( list.elemType )));
125 WriteJSONInteger( list.size);
126 }
127
128 public function writeListEnd() : Void {
129 WriteJSONArrayEnd();
130 }
131
132 public function writeSetBegin(set:TSet) : Void {
133 WriteJSONArrayStart();
134 WriteJSONString( BytesFromString( JSONConstants.GetTypeNameForTypeID( set.elemType)));
135 WriteJSONInteger( set.size);
136 }
137
138 public function writeSetEnd() : Void {
139 WriteJSONArrayEnd();
140 }
141
142 public function writeBool(b : Bool) : Void {
143 if( b)
144 WriteJSONInteger( 1);
145 else
146 WriteJSONInteger( 0);
147 }
148
149 public function writeByte(b : Int) : Void {
150 WriteJSONInteger( b);
151 }
152
153 public function writeI16(i16 : Int) : Void {
154 WriteJSONInteger( i16);
155 }
156
157 public function writeI32(i32 : Int) : Void {
158 WriteJSONInteger( i32);
159 }
160
161 public function writeI64(i64 : haxe.Int64) : Void {
162 WriteJSONInt64( i64);
163 }
164
165 public function writeDouble(dub:Float) : Void {
166 WriteJSONDouble(dub);
167 }
168
169 public function writeString(str : String) : Void {
170 WriteJSONString( BytesFromString(str));
171 }
172
173 public function writeBinary(bin:Bytes) : Void {
174 WriteJSONBase64(bin);
175 }
176
177 public function readMessageBegin():TMessage {
178 var message : TMessage = new TMessage();
179 ReadJSONArrayStart();
180 if (ReadJSONInteger() != JSONConstants.VERSION)
181 {
182 throw new TProtocolException(TProtocolException.BAD_VERSION,
183 "Message contained bad version.");
184 }
185
186 message.name = ReadJSONString(false);
187 message.type = ReadJSONInteger();
188 message.seqid = ReadJSONInteger();
189 return message;
190 }
191
192 public function readMessageEnd() : Void {
193 ReadJSONArrayEnd();
194 }
195
196 public function readStructBegin():TStruct {
197 ReadJSONObjectStart();
198 return new TStruct();
199 }
200
201 public function readStructEnd() : Void {
202 ReadJSONObjectEnd();
203 }
204
205 public function readFieldBegin() : TField {
206 var field : TField = new TField();
207 var ch = reader.Peek();
208 if (StringFromBytes(ch) == JSONConstants.RBRACE)
209 {
210 field.type = TType.STOP;
211 }
212 else
213 {
214 field.id = ReadJSONInteger();
215 ReadJSONObjectStart();
216 field.type = JSONConstants.GetTypeIDForTypeName( ReadJSONString(false));
217 }
218 return field;
219 }
220
221 public function readFieldEnd() : Void {
222 ReadJSONObjectEnd();
223 }
224
225 public function readMapBegin() : TMap {
226 ReadJSONArrayStart();
227 var KeyType = JSONConstants.GetTypeIDForTypeName( ReadJSONString(false));
228 var ValueType = JSONConstants.GetTypeIDForTypeName( ReadJSONString(false));
229 var Count : Int = ReadJSONInteger();
230 ReadJSONObjectStart();
231
232 var map = new TMap( KeyType, ValueType, Count);
233 return map;
234 }
235
236 public function readMapEnd() : Void {
237 ReadJSONObjectEnd();
238 ReadJSONArrayEnd();
239 }
240
241 public function readListBegin():TList {
242 ReadJSONArrayStart();
243 var ElementType = JSONConstants.GetTypeIDForTypeName( ReadJSONString(false));
244 var Count : Int = ReadJSONInteger();
245
246 var list = new TList( ElementType, Count);
247 return list;
248 }
249
250 public function readListEnd() : Void {
251 ReadJSONArrayEnd();
252 }
253
254 public function readSetBegin() : TSet {
255 ReadJSONArrayStart();
256 var ElementType = JSONConstants.GetTypeIDForTypeName( ReadJSONString(false));
257 var Count : Int = ReadJSONInteger();
258
259 var set = new TSet( ElementType, Count);
260 return set;
261 }
262
263 public function readSetEnd() : Void {
264 ReadJSONArrayEnd();
265 }
266
267 public function readBool() : Bool {
268 return (ReadJSONInteger() != 0);
269 }
270
271 public function readByte() : Int {
272 return ReadJSONInteger();
273 }
274
275 public function readI16() : Int {
276 return ReadJSONInteger();
277 }
278
279 public function readI32() : Int {
280 return ReadJSONInteger();
281 }
282
283 public function readI64() : haxe.Int64 {
284 return ReadJSONInt64();
285 }
286
287 public function readDouble():Float {
288 return ReadJSONDouble();
289 }
290
291 public function readString() : String {
292 return ReadJSONString(false);
293 }
294
295 public function readBinary() : Bytes {
296 return ReadJSONBase64();
297 }
298
299 // Push a new JSON context onto the stack.
300 private function PushContext(c : JSONBaseContext) : Void {
301 contextStack.add(context);
302 context = c;
303 }
304
305 // Pop the last JSON context off the stack
306 private function PopContext() : Void {
307 context = contextStack.pop();
308 }
309
310
311 // Write the bytes in array buf as a JSON characters, escaping as needed
312 private function WriteJSONString( b : Bytes) : Void {
313 context.Write();
314
315 var tmp = BytesFromString( JSONConstants.QUOTE);
316 trans.write( tmp, 0, tmp.length);
317
318 for (i in 0 ... b.length) {
319 var value = b.get(i);
320
321 if ((value & 0x00FF) >= 0x30)
322 {
323 if (String.fromCharCode(value) == JSONConstants.BACKSLASH.charAt(0))
324 {
325 tmp = BytesFromString( JSONConstants.BACKSLASH + JSONConstants.BACKSLASH);
326 trans.write( tmp, 0, tmp.length);
327 }
328 else
329 {
330 trans.write( b, i, 1);
331 }
332 }
333 else
334 {
335 var num = JSONConstants.JSON_CHAR_TABLE[value];
336 if (num == 1)
337 {
338 trans.write( b, i, 1);
339 }
340 else if (num > 1)
341 {
342 var buf = new BytesBuffer();
343 buf.addString( JSONConstants.BACKSLASH);
344 buf.addByte( num);
345 tmp = buf.getBytes();
346 trans.write( tmp, 0, tmp.length);
347 }
348 else
349 {
350 var buf = new BytesBuffer();
351 buf.addString( JSONConstants.ESCSEQ);
352 buf.addString( HexChar( (value & 0xFF000000) >> 12));
353 buf.addString( HexChar( (value & 0x00FF0000) >> 8));
354 buf.addString( HexChar( (value & 0x0000FF00) >> 4));
355 buf.addString( HexChar( value & 0x000000FF));
356 tmp = buf.getBytes();
357 trans.write( tmp, 0, tmp.length);
358 }
359 }
360 }
361
362 tmp = BytesFromString( JSONConstants.QUOTE);
363 trans.write( tmp, 0, tmp.length);
364 }
365
366 // Write out number as a JSON value. If the context dictates so,
367 // it will be wrapped in quotes to output as a JSON string.
368 private function WriteJSONInteger( num : Int) : Void {
369 context.Write();
370
371 var str : String = "";
372 var escapeNum : Bool = context.EscapeNumbers();
373
374 if (escapeNum) {
375 str += JSONConstants.QUOTE;
376 }
377
378 str += Std.string(num);
379
380 if (escapeNum) {
381 str += JSONConstants.QUOTE;
382 }
383
384 var tmp = BytesFromString( str);
385 trans.write( tmp, 0, tmp.length);
386 }
387
388 // Write out number as a JSON value. If the context dictates so,
389 // it will be wrapped in quotes to output as a JSON string.
390 private function WriteJSONInt64( num : Int64) : Void {
391 context.Write();
392
393 var str : String = "";
394 var escapeNum : Bool = context.EscapeNumbers();
395
396 if (escapeNum) {
397 str += JSONConstants.QUOTE;
398 }
399
400 str += Std.string(num);
401
402 if (escapeNum) {
403 str += JSONConstants.QUOTE;
404 }
405
406 var tmp = BytesFromString( str);
407 trans.write( tmp, 0, tmp.length);
408 }
409
410 // Write out a double as a JSON value. If it is NaN or infinity or if the
411 // context dictates escaping, Write out as JSON string.
412 private function WriteJSONDouble(num : Float) : Void {
413 context.Write();
414
415
416 var special : Bool = false;
417 var rendered : String = "";
418 if( Math.isNaN(num)) {
419 special = true;
420 rendered = JSONConstants.FLOAT_IS_NAN;
421 } else if (! Math.isFinite(num)) {
422 special = true;
423 if( num > 0) {
424 rendered = JSONConstants.FLOAT_IS_POS_INF;
425 } else {
426 rendered = JSONConstants.FLOAT_IS_NEG_INF;
427 }
428 } else {
429 rendered = Std.string(num); // plain and simple float number
430 }
431
432 // compose output
433 var escapeNum : Bool = special || context.EscapeNumbers();
434 var str : String = "";
435 if (escapeNum) {
436 str += JSONConstants.QUOTE;
437 }
438 str += rendered;
439 if (escapeNum) {
440 str += JSONConstants.QUOTE;
441 }
442
443 var tmp = BytesFromString( str);
444 trans.write( tmp, 0, tmp.length);
445 }
446
447 // Write out contents of byte array b as a JSON string with base-64 encoded data
448 private function WriteJSONBase64( b : Bytes) : Void {
449 context.Write();
450
451 var buf = new BytesBuffer();
452 buf.addString( JSONConstants.QUOTE);
453 buf.addString( Base64.encode(b));
454 buf.addString( JSONConstants.QUOTE);
455
456 var tmp = buf.getBytes();
457 trans.write( tmp, 0, tmp.length);
458 }
459
460 private function WriteJSONObjectStart() : Void {
461 context.Write();
462 var tmp = BytesFromString( JSONConstants.LBRACE);
463 trans.write( tmp, 0, tmp.length);
464 PushContext( new JSONPairContext(this));
465 }
466
467 private function WriteJSONObjectEnd() : Void {
468 PopContext();
469 var tmp = BytesFromString( JSONConstants.RBRACE);
470 trans.write( tmp, 0, tmp.length);
471 }
472
473 private function WriteJSONArrayStart() : Void {
474 context.Write();
475 var tmp = BytesFromString( JSONConstants.LBRACKET);
476 trans.write( tmp, 0, tmp.length);
477 PushContext( new JSONListContext(this));
478 }
479
480 private function WriteJSONArrayEnd() : Void {
481 PopContext();
482 var tmp = BytesFromString( JSONConstants.RBRACKET);
483 trans.write( tmp, 0, tmp.length);
484 }
485
486
487 /**
488 * Reading methods.
489 */
490
491 // Read a byte that must match char, otherwise an exception is thrown.
492 public function ReadJSONSyntaxChar( char : String) : Void {
493 var b = BytesFromString( char);
494
495 var ch = reader.Read();
496 if (ch.get(0) != b.get(0))
497 {
498 throw new TProtocolException(TProtocolException.INVALID_DATA,
499 'Unexpected character: $ch');
500 }
501 }
502
503 // Read in a JSON string, unescaping as appropriate.
504 // Skip Reading from the context if skipContext is true.
505 private function ReadJSONString(skipContext : Bool) : String
506 {
507 if (!skipContext)
508 {
509 context.Read();
510 }
511
512 var buffer : BytesBuffer = new BytesBuffer();
513
514 ReadJSONSyntaxChar( JSONConstants.QUOTE);
515 while (true)
516 {
517 var ch = reader.Read();
518
519 // end of string?
520 if (StringFromBytes(ch) == JSONConstants.QUOTE)
521 {
522 break;
523 }
524
525 // escaped?
526 if (StringFromBytes(ch) != JSONConstants.ESCSEQ.charAt(0))
527 {
528 buffer.addByte( ch.get(0));
529 continue;
530 }
531
532 // distinguish between \uXXXX (hex unicode) and \X (control chars)
533 ch = reader.Read();
534 if (StringFromBytes(ch) != JSONConstants.ESCSEQ.charAt(1))
535 {
536 var value = JSONConstants.ESCAPE_CHARS_TO_VALUES[ch.get(0)];
537 if( value == null)
538 {
539 throw new TProtocolException( TProtocolException.INVALID_DATA, "Expected control char");
540 }
541 buffer.addByte( value);
542 continue;
543 }
544
545
546 // it's \uXXXX
547 var hexbuf = new BytesBuffer();
548 var hexlen = trans.readAll( hexbuf, 0, 4);
549 if( hexlen != 4)
550 {
551 throw new TProtocolException( TProtocolException.INVALID_DATA, "Not enough data for \\uNNNN sequence");
552 }
553
554 var hexdigits = hexbuf.getBytes();
555 var charcode = 0;
556 charcode = (charcode << 4) + HexVal( String.fromCharCode(hexdigits.get(0)));
557 charcode = (charcode << 4) + HexVal( String.fromCharCode(hexdigits.get(1)));
558 charcode = (charcode << 4) + HexVal( String.fromCharCode(hexdigits.get(2)));
559 charcode = (charcode << 4) + HexVal( String.fromCharCode(hexdigits.get(3)));
560 buffer.addString( String.fromCharCode(charcode));
561 }
562
563 return StringFromBytes( buffer.getBytes());
564 }
565
566 // Return true if the given byte could be a valid part of a JSON number.
567 private function IsJSONNumeric(b : Int) : Bool {
568 switch (b)
569 {
570 case "+".code: return true;
571 case "-".code: return true;
572 case ".".code: return true;
573 case "0".code: return true;
574 case "1".code: return true;
575 case "2".code: return true;
576 case "3".code: return true;
577 case "4".code: return true;
578 case "5".code: return true;
579 case "6".code: return true;
580 case "7".code: return true;
581 case "8".code: return true;
582 case "9".code: return true;
583 case "E".code: return true;
584 case "e".code: return true;
585 }
586 return false;
587 }
588
589 // Read in a sequence of characters that are all valid in JSON numbers. Does
590 // not do a complete regex check to validate that this is actually a number.
591 private function ReadJSONNumericChars() : String
592 {
593 var buffer : BytesBuffer = new BytesBuffer();
594 while (true)
595 {
596 var ch = reader.Peek();
597 if( ! IsJSONNumeric( ch.get(0)))
598 {
599 break;
600 }
601 buffer.addByte( reader.Read().get(0));
602 }
603 return StringFromBytes( buffer.getBytes());
604 }
605
606 // Read in a JSON number. If the context dictates, Read in enclosing quotes.
607 private function ReadJSONInteger() : Int {
608 context.Read();
609
610 if (context.EscapeNumbers()) {
611 ReadJSONSyntaxChar( JSONConstants.QUOTE);
612 }
613
614 var str : String = ReadJSONNumericChars();
615
616 if (context.EscapeNumbers()) {
617 ReadJSONSyntaxChar( JSONConstants.QUOTE);
618 }
619
620 var value = Std.parseInt(str);
621 if( value == null) {
622 throw new TProtocolException(TProtocolException.INVALID_DATA, 'Bad numeric data: $str');
623 }
624
625 return value;
626 }
627
628 // Read in a JSON number. If the context dictates, Read in enclosing quotes.
629 private function ReadJSONInt64() : haxe.Int64 {
630 context.Read();
631
632 if (context.EscapeNumbers()) {
633 ReadJSONSyntaxChar( JSONConstants.QUOTE);
634 }
635
636 var str : String = ReadJSONNumericChars();
637 if( str.length == 0) {
638 throw new TProtocolException(TProtocolException.INVALID_DATA, 'Bad numeric data: $str');
639 }
640
641 if (context.EscapeNumbers()) {
642 ReadJSONSyntaxChar( JSONConstants.QUOTE);
643 }
644
645 // process sign
646 var bMinus = false;
647 var startAt = 0;
648 if( (str.charAt(0) == "+") || (str.charAt(0) == "-")) {
649 bMinus = (str.charAt(0) == "-");
650 startAt++;
651 }
652
653 // process digits
654 var value : Int64 = Int64.make(0,0);
655 var bGotDigits = false;
656 for( i in startAt ... str.length) {
657 var ch = str.charAt(i);
658 var digit = JSONConstants.DECIMAL_DIGITS[ch];
659 if( digit == null) {
660 throw new TProtocolException(TProtocolException.INVALID_DATA, 'Bad numeric data: $str');
661 }
662 bGotDigits = true;
663
664 // these are decimal digits
665 value = Int64.mul( value, Int64.make(0,10));
666 value = Int64.add( value, Int64.make(0,digit));
667 }
668
669 // process pending minus sign, if applicable
670 // this should also handle the edge case MIN_INT64 correctly
671 if( bMinus && (Int64.compare(value,Int64.make(0,0)) > 0)) {
672 value = Int64.neg( value);
673 bMinus = false;
674 }
675
676 if( ! bGotDigits) {
677 throw new TProtocolException(TProtocolException.INVALID_DATA, 'Bad numeric data: $str');
678 }
679
680 return value;
681 }
682
683 // Read in a JSON double value. Throw if the value is not wrapped in quotes
684 // when expected or if wrapped in quotes when not expected.
685 private function ReadJSONDouble() : Float {
686 context.Read();
687
688 var str : String = "";
689 if (StringFromBytes(reader.Peek()) == JSONConstants.QUOTE) {
690 str = ReadJSONString(true);
691
692 // special cases
693 if( str == JSONConstants.FLOAT_IS_NAN) {
694 return Math.NaN;
695 }
696 if( str == JSONConstants.FLOAT_IS_POS_INF) {
697 return Math.POSITIVE_INFINITY;
698 }
699 if( str == JSONConstants.FLOAT_IS_NEG_INF) {
700 return Math.NEGATIVE_INFINITY;
701 }
702
703 if( ! context.EscapeNumbers()) {
704 // throw - we should not be in a string in this case
705 throw new TProtocolException(TProtocolException.INVALID_DATA, "Numeric data unexpectedly quoted");
706 }
707 }
708 else
709 {
710 if( context.EscapeNumbers()) {
711 // This will throw - we should have had a quote if EscapeNumbers() == true
712 ReadJSONSyntaxChar( JSONConstants.QUOTE);
713 }
714
715 str = ReadJSONNumericChars();
716 }
717
718 // parse and check - we should have at least one valid digit
719 var dub = Std.parseFloat( str);
720 if( (str.length == 0) || Math.isNaN(dub)) {
721 throw new TProtocolException(TProtocolException.INVALID_DATA, 'Bad numeric data: $str');
722 }
723
724 return dub;
725 }
726
727 // Read in a JSON string containing base-64 encoded data and decode it.
728 private function ReadJSONBase64() : Bytes
729 {
730 var str = ReadJSONString(false);
731 return Base64.decode( str);
732 }
733
734 private function ReadJSONObjectStart() : Void {
735 context.Read();
736 ReadJSONSyntaxChar( JSONConstants.LBRACE);
737 PushContext(new JSONPairContext(this));
738 }
739
740 private function ReadJSONObjectEnd() : Void {
741 ReadJSONSyntaxChar( JSONConstants.RBRACE);
742 PopContext();
743 }
744
745 private function ReadJSONArrayStart() : Void {
746 context.Read();
747 ReadJSONSyntaxChar( JSONConstants.LBRACKET);
748 PushContext(new JSONListContext(this));
749 }
750
751 private function ReadJSONArrayEnd() : Void {
752 ReadJSONSyntaxChar( JSONConstants.RBRACKET);
753 PopContext();
754 }
755
756
757 public static function BytesFromString( str : String) : Bytes {
758 var buf = new BytesBuffer();
759 if( utf8Strings)
760 buf.addString( str); // no need to encode on UTF8 targets, the string is just fine
761 else
762 buf.addString( Utf8.encode( str));
763 return buf.getBytes();
764 }
765
766 public static function StringFromBytes( buf : Bytes) : String {
767 var inp = new BytesInput( buf);
768 if( buf.length == 0)
769 return ""; // readString() would return null in that case, which is wrong
770 var str = inp.readString( buf.length);
771 if( utf8Strings)
772 return str; // no need to decode on UTF8 targets, the string is just fine
773 else
774 return Utf8.decode( str);
775 }
776
777 // Convert a byte containing a hex char ('0'-'9' or 'a'-'f') into its corresponding hex value
778 private static function HexVal(char : String) : Int {
779 var value = JSONConstants.HEX_DIGITS[char];
780 if( value == null) {
781 throw new TProtocolException(TProtocolException.INVALID_DATA, 'Expected hex character: $char');
782 }
783 return value;
784 }
785
786 // Convert a byte containing a hex nibble to its corresponding hex character
787 private static function HexChar(nibble : Int) : String
788 {
789 return "0123456789abcdef".charAt(nibble & 0x0F);
790 }
791
792
793}
794
795
796@:allow(TJSONProtocol)
797class JSONConstants {
798 public static var COMMA = ",";
799 public static var COLON = ":";
800 public static var LBRACE = "{";
801 public static var RBRACE = "}";
802 public static var LBRACKET = "[";
803 public static var RBRACKET = "]";
804 public static var QUOTE = "\"";
805 public static var BACKSLASH = "\\";
806
807 public static var ESCSEQ = "\\u";
808
809 public static var FLOAT_IS_NAN = "NaN";
810 public static var FLOAT_IS_POS_INF = "Infinity";
811 public static var FLOAT_IS_NEG_INF = "-Infinity";
812
813 public static var VERSION = 1;
814 public static var JSON_CHAR_TABLE = [
815 0, 0, 0, 0, 0, 0, 0, 0,
816 "b".code, "t".code, "n".code, 0, "f".code, "r".code, 0, 0,
817 0, 0, 0, 0, 0, 0, 0, 0,
818 0, 0, 0, 0, 0, 0, 0, 0,
819 1, 1, "\"".code, 1, 1, 1, 1, 1,
820 1, 1, 1, 1, 1, 1, 1, 1,
821 ];
822
823 public static var ESCAPE_CHARS = ['"','\\','/','b','f','n','r','t'];
824 public static var ESCAPE_CHARS_TO_VALUES = [
825 "\"".code => 0x22,
826 "\\".code => 0x5C,
827 "/".code => 0x2F,
828 "b".code => 0x08,
829 "f".code => 0x0C,
830 "n".code => 0x0A,
831 "r".code => 0x0D,
832 "t".code => 0x09
833 ];
834
835 public static var DECIMAL_DIGITS = [
836 "0" => 0,
837 "1" => 1,
838 "2" => 2,
839 "3" => 3,
840 "4" => 4,
841 "5" => 5,
842 "6" => 6,
843 "7" => 7,
844 "8" => 8,
845 "9" => 9
846 ];
847
848 public static var HEX_DIGITS = [
849 "0" => 0,
850 "1" => 1,
851 "2" => 2,
852 "3" => 3,
853 "4" => 4,
854 "5" => 5,
855 "6" => 6,
856 "7" => 7,
857 "8" => 8,
858 "9" => 9,
859 "A" => 10,
860 "a" => 10,
861 "B" => 11,
862 "b" => 11,
863 "C" => 12,
864 "c" => 12,
865 "D" => 13,
866 "d" => 13,
867 "E" => 14,
868 "e" => 14,
869 "F" => 15,
870 "f" => 15
871 ];
872
873
874 public static var DEF_STRING_SIZE = 16;
875
876 public static var NAME_BOOL = 'tf';
877 public static var NAME_BYTE = 'i8';
878 public static var NAME_I16 = 'i16';
879 public static var NAME_I32 = 'i32';
880 public static var NAME_I64 = 'i64';
881 public static var NAME_DOUBLE = 'dbl';
882 public static var NAME_STRUCT = 'rec';
883 public static var NAME_STRING = 'str';
884 public static var NAME_MAP = 'map';
885 public static var NAME_LIST = 'lst';
886 public static var NAME_SET = 'set';
887
888 public static function GetTypeNameForTypeID(typeID : Int) : String {
889 switch (typeID)
890 {
891 case TType.BOOL: return NAME_BOOL;
892 case TType.BYTE: return NAME_BYTE;
893 case TType.I16: return NAME_I16;
894 case TType.I32: return NAME_I32;
895 case TType.I64: return NAME_I64;
896 case TType.DOUBLE: return NAME_DOUBLE;
897 case TType.STRING: return NAME_STRING;
898 case TType.STRUCT: return NAME_STRUCT;
899 case TType.MAP: return NAME_MAP;
900 case TType.SET: return NAME_SET;
901 case TType.LIST: return NAME_LIST;
902 }
903 throw new TProtocolException(TProtocolException.NOT_IMPLEMENTED, "Unrecognized type");
904 }
905
906 private static var NAMES_TO_TYPES = [
907 NAME_BOOL => TType.BOOL,
908 NAME_BYTE => TType.BYTE,
909 NAME_I16 => TType.I16,
910 NAME_I32 => TType.I32,
911 NAME_I64 => TType.I64,
912 NAME_DOUBLE => TType.DOUBLE,
913 NAME_STRING => TType.STRING,
914 NAME_STRUCT => TType.STRUCT,
915 NAME_MAP => TType.MAP,
916 NAME_SET => TType.SET,
917 NAME_LIST => TType.LIST
918 ];
919
920 public static function GetTypeIDForTypeName(name : String) : Int
921 {
922 var type = NAMES_TO_TYPES[name];
923 if( null != type) {
924 return type;
925 }
926 throw new TProtocolException(TProtocolException.NOT_IMPLEMENTED, "Unrecognized type");
927 }
928
929}
930
931
932// Base class for tracking JSON contexts that may require inserting/Reading
933// additional JSON syntax characters. This base context does nothing.
934@:allow(TJSONProtocol)
935class JSONBaseContext
936{
937 private var proto : TJSONProtocol;
938
939 public function new(proto : TJSONProtocol )
940 {
941 this.proto = proto;
942 }
943
944 public function Write() : Void { }
945 public function Read() : Void { }
946
947 public function EscapeNumbers() : Bool {
948 return false;
949 }
950}
951
952
953// Context for JSON lists.
954// Will insert/Read commas before each item except for the first one
955@:allow(TJSONProtocol)
956class JSONListContext extends JSONBaseContext
957{
958 public function new( proto : TJSONProtocol) {
959 super(proto);
960 }
961
962 private var first : Bool = true;
963
964 public override function Write() : Void {
965 if (first)
966 {
967 first = false;
968 }
969 else
970 {
971 var buf = new BytesBuffer();
972 buf.addString( JSONConstants.COMMA);
973 var tmp = buf.getBytes();
974 proto.trans.write( tmp, 0, tmp.length);
975 }
976 }
977
978 public override function Read() : Void {
979 if (first)
980 {
981 first = false;
982 }
983 else
984 {
985 proto.ReadJSONSyntaxChar( JSONConstants.COMMA);
986 }
987 }
988}
989
990
991// Context for JSON records.
992// Will insert/Read colons before the value portion of each record
993// pair, and commas before each key except the first. In addition,
994// will indicate that numbers in the key position need to be escaped
995// in quotes (since JSON keys must be strings).
996@:allow(TJSONProtocol)
997class JSONPairContext extends JSONBaseContext
998{
999 public function new( proto : TJSONProtocol ) {
1000 super( proto);
1001 }
1002
1003 private var first : Bool = true;
1004 private var colon : Bool = true;
1005
1006 public override function Write() : Void {
1007 if (first)
1008 {
1009 first = false;
1010 colon = true;
1011 }
1012 else
1013 {
1014 var buf = new BytesBuffer();
1015 buf.addString( colon ? JSONConstants.COLON : JSONConstants.COMMA);
1016 var tmp = buf.getBytes();
1017 proto.trans.write( tmp, 0, tmp.length);
1018 colon = !colon;
1019 }
1020 }
1021
1022 public override function Read() : Void {
1023 if (first)
1024 {
1025 first = false;
1026 colon = true;
1027 }
1028 else
1029 {
1030 proto.ReadJSONSyntaxChar( colon ? JSONConstants.COLON : JSONConstants.COMMA);
1031 colon = !colon;
1032 }
1033 }
1034
1035 public override function EscapeNumbers() : Bool
1036 {
1037 return colon;
1038 }
1039}
1040
1041// Holds up to one byte from the transport
1042@:allow(TJSONProtocol)
1043class LookaheadReader {
1044
1045 private var proto : TJSONProtocol;
1046 private var data : Bytes;
1047
1048 public function new( proto : TJSONProtocol ) {
1049 this.proto = proto;
1050 data = null;
1051 }
1052
1053
1054 // Return and consume the next byte to be Read, either taking it from the
1055 // data buffer if present or getting it from the transport otherwise.
1056 public function Read() : Bytes {
1057 var retval = Peek();
1058 data = null;
1059 return retval;
1060 }
1061
1062 // Return the next byte to be Read without consuming, filling the data
1063 // buffer if it has not been filled alReady.
1064 public function Peek() : Bytes {
1065 if (data == null) {
1066 var buf = new BytesBuffer();
1067 proto.trans.readAll(buf, 0, 1);
1068 data = buf.getBytes();
1069 }
1070 return data;
1071 }
1072}
1073