]> git.proxmox.com Git - ceph.git/blob - ceph/src/jaegertracing/thrift/lib/nodejs/lib/thrift/compact_protocol.js
buildsys: switch source download to quincy
[ceph.git] / ceph / src / jaegertracing / thrift / lib / nodejs / lib / thrift / compact_protocol.js
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
20 var log = require('./log');
21 var Int64 = require('node-int64');
22 var Thrift = require('./thrift');
23 var Type = Thrift.Type;
24
25 module.exports = TCompactProtocol;
26
27 var POW_8 = Math.pow(2, 8);
28 var POW_24 = Math.pow(2, 24);
29 var POW_32 = Math.pow(2, 32);
30 var POW_40 = Math.pow(2, 40);
31 var POW_48 = Math.pow(2, 48);
32 var POW_52 = Math.pow(2, 52);
33 var POW_1022 = Math.pow(2, 1022);
34
35 /**
36 * Constructor Function for the Compact Protocol.
37 * @constructor
38 * @param {object} [trans] - The underlying transport to read/write.
39 * @classdesc The Apache Thrift Protocol layer performs serialization
40 * of base types, the compact protocol serializes data in binary
41 * form with minimal space used for scalar values.
42 */
43 function TCompactProtocol(trans) {
44 this.trans = trans;
45 this.lastField_ = [];
46 this.lastFieldId_ = 0;
47 this.string_limit_ = 0;
48 this.string_buf_ = null;
49 this.string_buf_size_ = 0;
50 this.container_limit_ = 0;
51 this.booleanField_ = {
52 name: null,
53 hasBoolValue: false
54 };
55 this.boolValue_ = {
56 hasBoolValue: false,
57 boolValue: false
58 };
59 };
60
61
62 //
63 // Compact Protocol Constants
64 //
65
66 /**
67 * Compact Protocol ID number.
68 * @readonly
69 * @const {number} PROTOCOL_ID
70 */
71 TCompactProtocol.PROTOCOL_ID = -126; //1000 0010
72
73 /**
74 * Compact Protocol version number.
75 * @readonly
76 * @const {number} VERSION_N
77 */
78 TCompactProtocol.VERSION_N = 1;
79
80 /**
81 * Compact Protocol version mask for combining protocol version and message type in one byte.
82 * @readonly
83 * @const {number} VERSION_MASK
84 */
85 TCompactProtocol.VERSION_MASK = 0x1f; //0001 1111
86
87 /**
88 * Compact Protocol message type mask for combining protocol version and message type in one byte.
89 * @readonly
90 * @const {number} TYPE_MASK
91 */
92 TCompactProtocol.TYPE_MASK = -32; //1110 0000
93
94 /**
95 * Compact Protocol message type bits for ensuring message type bit size.
96 * @readonly
97 * @const {number} TYPE_BITS
98 */
99 TCompactProtocol.TYPE_BITS = 7; //0000 0111
100
101 /**
102 * Compact Protocol message type shift amount for combining protocol version and message type in one byte.
103 * @readonly
104 * @const {number} TYPE_SHIFT_AMOUNT
105 */
106 TCompactProtocol.TYPE_SHIFT_AMOUNT = 5;
107
108 /**
109 * Compact Protocol type IDs used to keep type data within one nibble.
110 * @readonly
111 * @property {number} CT_STOP - End of a set of fields.
112 * @property {number} CT_BOOLEAN_TRUE - Flag for Boolean field with true value (packed field and value).
113 * @property {number} CT_BOOLEAN_FALSE - Flag for Boolean field with false value (packed field and value).
114 * @property {number} CT_BYTE - Signed 8 bit integer.
115 * @property {number} CT_I16 - Signed 16 bit integer.
116 * @property {number} CT_I32 - Signed 32 bit integer.
117 * @property {number} CT_I64 - Signed 64 bit integer (2^53 max in JavaScript).
118 * @property {number} CT_DOUBLE - 64 bit IEEE 854 floating point.
119 * @property {number} CT_BINARY - Array of bytes (used for strings also).
120 * @property {number} CT_LIST - A collection type (unordered).
121 * @property {number} CT_SET - A collection type (unordered and without repeated values).
122 * @property {number} CT_MAP - A collection type (map/associative-array/dictionary).
123 * @property {number} CT_STRUCT - A multifield type.
124 */
125 TCompactProtocol.Types = {
126 CT_STOP: 0x00,
127 CT_BOOLEAN_TRUE: 0x01,
128 CT_BOOLEAN_FALSE: 0x02,
129 CT_BYTE: 0x03,
130 CT_I16: 0x04,
131 CT_I32: 0x05,
132 CT_I64: 0x06,
133 CT_DOUBLE: 0x07,
134 CT_BINARY: 0x08,
135 CT_LIST: 0x09,
136 CT_SET: 0x0A,
137 CT_MAP: 0x0B,
138 CT_STRUCT: 0x0C
139 };
140
141 /**
142 * Array mapping Compact type IDs to standard Thrift type IDs.
143 * @readonly
144 */
145 TCompactProtocol.TTypeToCType = [
146 TCompactProtocol.Types.CT_STOP, // T_STOP
147 0, // unused
148 TCompactProtocol.Types.CT_BOOLEAN_TRUE, // T_BOOL
149 TCompactProtocol.Types.CT_BYTE, // T_BYTE
150 TCompactProtocol.Types.CT_DOUBLE, // T_DOUBLE
151 0, // unused
152 TCompactProtocol.Types.CT_I16, // T_I16
153 0, // unused
154 TCompactProtocol.Types.CT_I32, // T_I32
155 0, // unused
156 TCompactProtocol.Types.CT_I64, // T_I64
157 TCompactProtocol.Types.CT_BINARY, // T_STRING
158 TCompactProtocol.Types.CT_STRUCT, // T_STRUCT
159 TCompactProtocol.Types.CT_MAP, // T_MAP
160 TCompactProtocol.Types.CT_SET, // T_SET
161 TCompactProtocol.Types.CT_LIST, // T_LIST
162 ];
163
164
165 //
166 // Compact Protocol Utilities
167 //
168
169 /**
170 * Returns the underlying transport layer.
171 * @return {object} The underlying transport layer.
172 */TCompactProtocol.prototype.getTransport = function() {
173 return this.trans;
174 };
175
176 /**
177 * Lookup a Compact Protocol Type value for a given Thrift Type value.
178 * N.B. Used only internally.
179 * @param {number} ttype - Thrift type value
180 * @returns {number} Compact protocol type value
181 */
182 TCompactProtocol.prototype.getCompactType = function(ttype) {
183 return TCompactProtocol.TTypeToCType[ttype];
184 };
185
186 /**
187 * Lookup a Thrift Type value for a given Compact Protocol Type value.
188 * N.B. Used only internally.
189 * @param {number} type - Compact Protocol type value
190 * @returns {number} Thrift Type value
191 */
192 TCompactProtocol.prototype.getTType = function(type) {
193 switch (type) {
194 case Type.STOP:
195 return Type.STOP;
196 case TCompactProtocol.Types.CT_BOOLEAN_FALSE:
197 case TCompactProtocol.Types.CT_BOOLEAN_TRUE:
198 return Type.BOOL;
199 case TCompactProtocol.Types.CT_BYTE:
200 return Type.BYTE;
201 case TCompactProtocol.Types.CT_I16:
202 return Type.I16;
203 case TCompactProtocol.Types.CT_I32:
204 return Type.I32;
205 case TCompactProtocol.Types.CT_I64:
206 return Type.I64;
207 case TCompactProtocol.Types.CT_DOUBLE:
208 return Type.DOUBLE;
209 case TCompactProtocol.Types.CT_BINARY:
210 return Type.STRING;
211 case TCompactProtocol.Types.CT_LIST:
212 return Type.LIST;
213 case TCompactProtocol.Types.CT_SET:
214 return Type.SET;
215 case TCompactProtocol.Types.CT_MAP:
216 return Type.MAP;
217 case TCompactProtocol.Types.CT_STRUCT:
218 return Type.STRUCT;
219 default:
220 throw new Thrift.TProtocolException(Thrift.TProtocolExceptionType.INVALID_DATA, "Unknown type: " + type);
221 }
222 return Type.STOP;
223 };
224
225
226 //
227 // Compact Protocol write operations
228 //
229
230 /**
231 * Send any buffered bytes to the end point.
232 */
233 TCompactProtocol.prototype.flush = function() {
234 return this.trans.flush();
235 };
236
237 /**
238 * Writes an RPC message header
239 * @param {string} name - The method name for the message.
240 * @param {number} type - The type of message (CALL, REPLY, EXCEPTION, ONEWAY).
241 * @param {number} seqid - The call sequence number (if any).
242 */
243 TCompactProtocol.prototype.writeMessageBegin = function(name, type, seqid) {
244 this.writeByte(TCompactProtocol.PROTOCOL_ID);
245 this.writeByte((TCompactProtocol.VERSION_N & TCompactProtocol.VERSION_MASK) |
246 ((type << TCompactProtocol.TYPE_SHIFT_AMOUNT) & TCompactProtocol.TYPE_MASK));
247 this.writeVarint32(seqid);
248 this.writeString(name);
249
250 // Record client seqid to find callback again
251 if (this._seqid) {
252 log.warning('SeqId already set', { 'name': name });
253 } else {
254 this._seqid = seqid;
255 this.trans.setCurrSeqId(seqid);
256 }
257 };
258
259 TCompactProtocol.prototype.writeMessageEnd = function() {
260 };
261
262 TCompactProtocol.prototype.writeStructBegin = function(name) {
263 this.lastField_.push(this.lastFieldId_);
264 this.lastFieldId_ = 0;
265 };
266
267 TCompactProtocol.prototype.writeStructEnd = function() {
268 this.lastFieldId_ = this.lastField_.pop();
269 };
270
271 /**
272 * Writes a struct field header
273 * @param {string} name - The field name (not written with the compact protocol).
274 * @param {number} type - The field data type (a normal Thrift field Type).
275 * @param {number} id - The IDL field Id.
276 */
277 TCompactProtocol.prototype.writeFieldBegin = function(name, type, id) {
278 if (type != Type.BOOL) {
279 return this.writeFieldBeginInternal(name, type, id, -1);
280 }
281
282 this.booleanField_.name = name;
283 this.booleanField_.fieldType = type;
284 this.booleanField_.fieldId = id;
285 };
286
287 TCompactProtocol.prototype.writeFieldEnd = function() {
288 };
289
290 TCompactProtocol.prototype.writeFieldStop = function() {
291 this.writeByte(TCompactProtocol.Types.CT_STOP);
292 };
293
294 /**
295 * Writes a map collection header
296 * @param {number} keyType - The Thrift type of the map keys.
297 * @param {number} valType - The Thrift type of the map values.
298 * @param {number} size - The number of k/v pairs in the map.
299 */
300 TCompactProtocol.prototype.writeMapBegin = function(keyType, valType, size) {
301 if (size === 0) {
302 this.writeByte(0);
303 } else {
304 this.writeVarint32(size);
305 this.writeByte(this.getCompactType(keyType) << 4 | this.getCompactType(valType));
306 }
307 };
308
309 TCompactProtocol.prototype.writeMapEnd = function() {
310 };
311
312 /**
313 * Writes a list collection header
314 * @param {number} elemType - The Thrift type of the list elements.
315 * @param {number} size - The number of elements in the list.
316 */
317 TCompactProtocol.prototype.writeListBegin = function(elemType, size) {
318 this.writeCollectionBegin(elemType, size);
319 };
320
321 TCompactProtocol.prototype.writeListEnd = function() {
322 };
323
324 /**
325 * Writes a set collection header
326 * @param {number} elemType - The Thrift type of the set elements.
327 * @param {number} size - The number of elements in the set.
328 */
329 TCompactProtocol.prototype.writeSetBegin = function(elemType, size) {
330 this.writeCollectionBegin(elemType, size);
331 };
332
333 TCompactProtocol.prototype.writeSetEnd = function() {
334 };
335
336 TCompactProtocol.prototype.writeBool = function(value) {
337 if (this.booleanField_.name !== null) {
338 // we haven't written the field header yet
339 this.writeFieldBeginInternal(this.booleanField_.name,
340 this.booleanField_.fieldType,
341 this.booleanField_.fieldId,
342 (value ? TCompactProtocol.Types.CT_BOOLEAN_TRUE
343 : TCompactProtocol.Types.CT_BOOLEAN_FALSE));
344 this.booleanField_.name = null;
345 } else {
346 // we're not part of a field, so just write the value
347 this.writeByte((value ? TCompactProtocol.Types.CT_BOOLEAN_TRUE
348 : TCompactProtocol.Types.CT_BOOLEAN_FALSE));
349 }
350 };
351
352 TCompactProtocol.prototype.writeByte = function(b) {
353 this.trans.write(new Buffer([b]));
354 };
355
356 TCompactProtocol.prototype.writeI16 = function(i16) {
357 this.writeVarint32(this.i32ToZigzag(i16));
358 };
359
360 TCompactProtocol.prototype.writeI32 = function(i32) {
361 this.writeVarint32(this.i32ToZigzag(i32));
362 };
363
364 TCompactProtocol.prototype.writeI64 = function(i64) {
365 this.writeVarint64(this.i64ToZigzag(i64));
366 };
367
368 // Little-endian, unlike TBinaryProtocol
369 TCompactProtocol.prototype.writeDouble = function(v) {
370 var buff = new Buffer(8);
371 var m, e, c;
372
373 buff[7] = (v < 0 ? 0x80 : 0x00);
374
375 v = Math.abs(v);
376 if (v !== v) {
377 // NaN, use QNaN IEEE format
378 m = 2251799813685248;
379 e = 2047;
380 } else if (v === Infinity) {
381 m = 0;
382 e = 2047;
383 } else {
384 e = Math.floor(Math.log(v) / Math.LN2);
385 c = Math.pow(2, -e);
386 if (v * c < 1) {
387 e--;
388 c *= 2;
389 }
390
391 if (e + 1023 >= 2047)
392 {
393 // Overflow
394 m = 0;
395 e = 2047;
396 }
397 else if (e + 1023 >= 1)
398 {
399 // Normalized - term order matters, as Math.pow(2, 52-e) and v*Math.pow(2, 52) can overflow
400 m = (v*c-1) * POW_52;
401 e += 1023;
402 }
403 else
404 {
405 // Denormalized - also catches the '0' case, somewhat by chance
406 m = (v * POW_1022) * POW_52;
407 e = 0;
408 }
409 }
410
411 buff[6] = (e << 4) & 0xf0;
412 buff[7] |= (e >> 4) & 0x7f;
413
414 buff[0] = m & 0xff;
415 m = Math.floor(m / POW_8);
416 buff[1] = m & 0xff;
417 m = Math.floor(m / POW_8);
418 buff[2] = m & 0xff;
419 m = Math.floor(m / POW_8);
420 buff[3] = m & 0xff;
421 m >>= 8;
422 buff[4] = m & 0xff;
423 m >>= 8;
424 buff[5] = m & 0xff;
425 m >>= 8;
426 buff[6] |= m & 0x0f;
427
428 this.trans.write(buff);
429 };
430
431 TCompactProtocol.prototype.writeStringOrBinary = function(name, encoding, arg) {
432 if (typeof arg === 'string') {
433 this.writeVarint32(Buffer.byteLength(arg, encoding)) ;
434 this.trans.write(new Buffer(arg, encoding));
435 } else if (arg instanceof Buffer ||
436 Object.prototype.toString.call(arg) == '[object Uint8Array]') {
437 // Buffers in Node.js under Browserify may extend UInt8Array instead of
438 // defining a new object. We detect them here so we can write them
439 // correctly
440 this.writeVarint32(arg.length);
441 this.trans.write(arg);
442 } else {
443 throw new Error(name + ' called without a string/Buffer argument: ' + arg);
444 }
445 };
446
447 TCompactProtocol.prototype.writeString = function(arg) {
448 this.writeStringOrBinary('writeString', 'utf8', arg);
449 };
450
451 TCompactProtocol.prototype.writeBinary = function(arg) {
452 this.writeStringOrBinary('writeBinary', 'binary', arg);
453 };
454
455
456 //
457 // Compact Protocol internal write methods
458 //
459
460 TCompactProtocol.prototype.writeFieldBeginInternal = function(name,
461 fieldType,
462 fieldId,
463 typeOverride) {
464 //If there's a type override, use that.
465 var typeToWrite = (typeOverride == -1 ? this.getCompactType(fieldType) : typeOverride);
466 //Check if we can delta encode the field id
467 if (fieldId > this.lastFieldId_ && fieldId - this.lastFieldId_ <= 15) {
468 //Include the type delta with the field ID
469 this.writeByte((fieldId - this.lastFieldId_) << 4 | typeToWrite);
470 } else {
471 //Write separate type and ID values
472 this.writeByte(typeToWrite);
473 this.writeI16(fieldId);
474 }
475 this.lastFieldId_ = fieldId;
476 };
477
478 TCompactProtocol.prototype.writeCollectionBegin = function(elemType, size) {
479 if (size <= 14) {
480 //Combine size and type in one byte if possible
481 this.writeByte(size << 4 | this.getCompactType(elemType));
482 } else {
483 this.writeByte(0xf0 | this.getCompactType(elemType));
484 this.writeVarint32(size);
485 }
486 };
487
488 /**
489 * Write an i32 as a varint. Results in 1-5 bytes on the wire.
490 */
491 TCompactProtocol.prototype.writeVarint32 = function(n) {
492 var buf = new Buffer(5);
493 var wsize = 0;
494 while (true) {
495 if ((n & ~0x7F) === 0) {
496 buf[wsize++] = n;
497 break;
498 } else {
499 buf[wsize++] = ((n & 0x7F) | 0x80);
500 n = n >>> 7;
501 }
502 }
503 var wbuf = new Buffer(wsize);
504 buf.copy(wbuf,0,0,wsize);
505 this.trans.write(wbuf);
506 };
507
508 /**
509 * Write an i64 as a varint. Results in 1-10 bytes on the wire.
510 * N.B. node-int64 is always big endian
511 */
512 TCompactProtocol.prototype.writeVarint64 = function(n) {
513 if (typeof n === "number"){
514 n = new Int64(n);
515 }
516 if (! (n instanceof Int64)) {
517 throw new Thrift.TProtocolException(Thrift.TProtocolExceptionType.INVALID_DATA, "Expected Int64 or Number, found: " + n);
518 }
519
520 var buf = new Buffer(10);
521 var wsize = 0;
522 var hi = n.buffer.readUInt32BE(0, true);
523 var lo = n.buffer.readUInt32BE(4, true);
524 var mask = 0;
525 while (true) {
526 if (((lo & ~0x7F) === 0) && (hi === 0)) {
527 buf[wsize++] = lo;
528 break;
529 } else {
530 buf[wsize++] = ((lo & 0x7F) | 0x80);
531 mask = hi << 25;
532 lo = lo >>> 7;
533 hi = hi >>> 7;
534 lo = lo | mask;
535 }
536 }
537 var wbuf = new Buffer(wsize);
538 buf.copy(wbuf,0,0,wsize);
539 this.trans.write(wbuf);
540 };
541
542 /**
543 * Convert l into a zigzag long. This allows negative numbers to be
544 * represented compactly as a varint.
545 */
546 TCompactProtocol.prototype.i64ToZigzag = function(l) {
547 if (typeof l === 'string') {
548 l = new Int64(parseInt(l, 10));
549 } else if (typeof l === 'number') {
550 l = new Int64(l);
551 }
552 if (! (l instanceof Int64)) {
553 throw new Thrift.TProtocolException(Thrift.TProtocolExceptionType.INVALID_DATA, "Expected Int64 or Number, found: " + l);
554 }
555 var hi = l.buffer.readUInt32BE(0, true);
556 var lo = l.buffer.readUInt32BE(4, true);
557 var sign = hi >>> 31;
558 hi = ((hi << 1) | (lo >>> 31)) ^ ((!!sign) ? 0xFFFFFFFF : 0);
559 lo = (lo << 1) ^ ((!!sign) ? 0xFFFFFFFF : 0);
560 return new Int64(hi, lo);
561 };
562
563 /**
564 * Convert n into a zigzag int. This allows negative numbers to be
565 * represented compactly as a varint.
566 */
567 TCompactProtocol.prototype.i32ToZigzag = function(n) {
568 return (n << 1) ^ ((n & 0x80000000) ? 0xFFFFFFFF : 0);
569 };
570
571
572 //
573 // Compact Protocol read operations
574 //
575
576 TCompactProtocol.prototype.readMessageBegin = function() {
577 //Read protocol ID
578 var protocolId = this.trans.readByte();
579 if (protocolId != TCompactProtocol.PROTOCOL_ID) {
580 throw new Thrift.TProtocolException(Thrift.TProtocolExceptionType.BAD_VERSION, "Bad protocol identifier " + protocolId);
581 }
582
583 //Read Version and Type
584 var versionAndType = this.trans.readByte();
585 var version = (versionAndType & TCompactProtocol.VERSION_MASK);
586 if (version != TCompactProtocol.VERSION_N) {
587 throw new Thrift.TProtocolException(Thrift.TProtocolExceptionType.BAD_VERSION, "Bad protocol version " + version);
588 }
589 var type = ((versionAndType >> TCompactProtocol.TYPE_SHIFT_AMOUNT) & TCompactProtocol.TYPE_BITS);
590
591 //Read SeqId
592 var seqid = this.readVarint32();
593
594 //Read name
595 var name = this.readString();
596
597 return {fname: name, mtype: type, rseqid: seqid};
598 };
599
600 TCompactProtocol.prototype.readMessageEnd = function() {
601 };
602
603 TCompactProtocol.prototype.readStructBegin = function() {
604 this.lastField_.push(this.lastFieldId_);
605 this.lastFieldId_ = 0;
606 return {fname: ''};
607 };
608
609 TCompactProtocol.prototype.readStructEnd = function() {
610 this.lastFieldId_ = this.lastField_.pop();
611 };
612
613 TCompactProtocol.prototype.readFieldBegin = function() {
614 var fieldId = 0;
615 var b = this.trans.readByte(b);
616 var type = (b & 0x0f);
617
618 if (type == TCompactProtocol.Types.CT_STOP) {
619 return {fname: null, ftype: Thrift.Type.STOP, fid: 0};
620 }
621
622 //Mask off the 4 MSB of the type header to check for field id delta.
623 var modifier = ((b & 0x000000f0) >>> 4);
624 if (modifier === 0) {
625 //If not a delta read the field id.
626 fieldId = this.readI16();
627 } else {
628 //Recover the field id from the delta
629 fieldId = (this.lastFieldId_ + modifier);
630 }
631 var fieldType = this.getTType(type);
632
633 //Boolean are encoded with the type
634 if (type == TCompactProtocol.Types.CT_BOOLEAN_TRUE ||
635 type == TCompactProtocol.Types.CT_BOOLEAN_FALSE) {
636 this.boolValue_.hasBoolValue = true;
637 this.boolValue_.boolValue =
638 (type == TCompactProtocol.Types.CT_BOOLEAN_TRUE ? true : false);
639 }
640
641 //Save the new field for the next delta computation.
642 this.lastFieldId_ = fieldId;
643 return {fname: null, ftype: fieldType, fid: fieldId};
644 };
645
646 TCompactProtocol.prototype.readFieldEnd = function() {
647 };
648
649 TCompactProtocol.prototype.readMapBegin = function() {
650 var msize = this.readVarint32();
651 if (msize < 0) {
652 throw new Thrift.TProtocolException(Thrift.TProtocolExceptionType.NEGATIVE_SIZE, "Negative map size");
653 }
654
655 var kvType = 0;
656 if (msize !== 0) {
657 kvType = this.trans.readByte();
658 }
659
660 var keyType = this.getTType((kvType & 0xf0) >>> 4);
661 var valType = this.getTType(kvType & 0xf);
662 return {ktype: keyType, vtype: valType, size: msize};
663 };
664
665 TCompactProtocol.prototype.readMapEnd = function() {
666 };
667
668 TCompactProtocol.prototype.readListBegin = function() {
669 var size_and_type = this.trans.readByte();
670
671 var lsize = (size_and_type >>> 4) & 0x0000000f;
672 if (lsize == 15) {
673 lsize = this.readVarint32();
674 }
675
676 if (lsize < 0) {
677 throw new Thrift.TProtocolException(Thrift.TProtocolExceptionType.NEGATIVE_SIZE, "Negative list size");
678 }
679
680 var elemType = this.getTType(size_and_type & 0x0000000f);
681
682 return {etype: elemType, size: lsize};
683 };
684
685 TCompactProtocol.prototype.readListEnd = function() {
686 };
687
688 TCompactProtocol.prototype.readSetBegin = function() {
689 return this.readListBegin();
690 };
691
692 TCompactProtocol.prototype.readSetEnd = function() {
693 };
694
695 TCompactProtocol.prototype.readBool = function() {
696 var value = false;
697 var rsize = 0;
698 if (this.boolValue_.hasBoolValue === true) {
699 value = this.boolValue_.boolValue;
700 this.boolValue_.hasBoolValue = false;
701 } else {
702 var res = this.trans.readByte();
703 rsize = res.rsize;
704 value = (res.value == TCompactProtocol.Types.CT_BOOLEAN_TRUE);
705 }
706 return value;
707 };
708
709 TCompactProtocol.prototype.readByte = function() {
710 return this.trans.readByte();
711 };
712
713 TCompactProtocol.prototype.readI16 = function() {
714 return this.readI32();
715 };
716
717 TCompactProtocol.prototype.readI32 = function() {
718 return this.zigzagToI32(this.readVarint32());
719 };
720
721 TCompactProtocol.prototype.readI64 = function() {
722 return this.zigzagToI64(this.readVarint64());
723 };
724
725 // Little-endian, unlike TBinaryProtocol
726 TCompactProtocol.prototype.readDouble = function() {
727 var buff = this.trans.read(8);
728 var off = 0;
729
730 var signed = buff[off + 7] & 0x80;
731 var e = (buff[off+6] & 0xF0) >> 4;
732 e += (buff[off+7] & 0x7F) << 4;
733
734 var m = buff[off];
735 m += buff[off+1] << 8;
736 m += buff[off+2] << 16;
737 m += buff[off+3] * POW_24;
738 m += buff[off+4] * POW_32;
739 m += buff[off+5] * POW_40;
740 m += (buff[off+6] & 0x0F) * POW_48;
741
742 switch (e) {
743 case 0:
744 e = -1022;
745 break;
746 case 2047:
747 return m ? NaN : (signed ? -Infinity : Infinity);
748 default:
749 m += POW_52;
750 e -= 1023;
751 }
752
753 if (signed) {
754 m *= -1;
755 }
756
757 return m * Math.pow(2, e - 52);
758 };
759
760 TCompactProtocol.prototype.readBinary = function() {
761 var size = this.readVarint32();
762 if (size === 0) {
763 return new Buffer(0);
764 }
765
766 if (size < 0) {
767 throw new Thrift.TProtocolException(Thrift.TProtocolExceptionType.NEGATIVE_SIZE, "Negative binary size");
768 }
769 return this.trans.read(size);
770 };
771
772 TCompactProtocol.prototype.readString = function() {
773 var size = this.readVarint32();
774 // Catch empty string case
775 if (size === 0) {
776 return "";
777 }
778
779 // Catch error cases
780 if (size < 0) {
781 throw new Thrift.TProtocolException(Thrift.TProtocolExceptionType.NEGATIVE_SIZE, "Negative string size");
782 }
783 return this.trans.readString(size);
784 };
785
786
787 //
788 // Compact Protocol internal read operations
789 //
790
791 /**
792 * Read an i32 from the wire as a varint. The MSB of each byte is set
793 * if there is another byte to follow. This can read up to 5 bytes.
794 */
795 TCompactProtocol.prototype.readVarint32 = function() {
796 return this.readVarint64().toNumber();
797 };
798
799 /**
800 * Read an i64 from the wire as a proper varint. The MSB of each byte is set
801 * if there is another byte to follow. This can read up to 10 bytes.
802 */
803 TCompactProtocol.prototype.readVarint64 = function() {
804 var rsize = 0;
805 var lo = 0;
806 var hi = 0;
807 var shift = 0;
808 while (true) {
809 var b = this.trans.readByte();
810 rsize ++;
811 if (shift <= 25) {
812 lo = lo | ((b & 0x7f) << shift);
813 } else if (25 < shift && shift < 32) {
814 lo = lo | ((b & 0x7f) << shift);
815 hi = hi | ((b & 0x7f) >>> (32-shift));
816 } else {
817 hi = hi | ((b & 0x7f) << (shift-32));
818 }
819 shift += 7;
820 if (!(b & 0x80)) {
821 break;
822 }
823 if (rsize >= 10) {
824 throw new Thrift.TProtocolException(Thrift.TProtocolExceptionType.INVALID_DATA, "Variable-length int over 10 bytes.");
825 }
826 }
827 return new Int64(hi, lo);
828 };
829
830 /**
831 * Convert from zigzag int to int.
832 */
833 TCompactProtocol.prototype.zigzagToI32 = function(n) {
834 return (n >>> 1) ^ (-1 * (n & 1));
835 };
836
837 /**
838 * Convert from zigzag long to long.
839 */
840 TCompactProtocol.prototype.zigzagToI64 = function(n) {
841 var hi = n.buffer.readUInt32BE(0, true);
842 var lo = n.buffer.readUInt32BE(4, true);
843
844 var neg = new Int64(hi & 0, lo & 1);
845 neg._2scomp();
846 var hi_neg = neg.buffer.readUInt32BE(0, true);
847 var lo_neg = neg.buffer.readUInt32BE(4, true);
848
849 var hi_lo = (hi << 31);
850 hi = (hi >>> 1) ^ (hi_neg);
851 lo = ((lo >>> 1) | hi_lo) ^ (lo_neg);
852 return new Int64(hi, lo);
853 };
854
855 TCompactProtocol.prototype.skip = function(type) {
856 switch (type) {
857 case Type.BOOL:
858 this.readBool();
859 break;
860 case Type.BYTE:
861 this.readByte();
862 break;
863 case Type.I16:
864 this.readI16();
865 break;
866 case Type.I32:
867 this.readI32();
868 break;
869 case Type.I64:
870 this.readI64();
871 break;
872 case Type.DOUBLE:
873 this.readDouble();
874 break;
875 case Type.STRING:
876 this.readString();
877 break;
878 case Type.STRUCT:
879 this.readStructBegin();
880 while (true) {
881 var r = this.readFieldBegin();
882 if (r.ftype === Type.STOP) {
883 break;
884 }
885 this.skip(r.ftype);
886 this.readFieldEnd();
887 }
888 this.readStructEnd();
889 break;
890 case Type.MAP:
891 var mapBegin = this.readMapBegin();
892 for (var i = 0; i < mapBegin.size; ++i) {
893 this.skip(mapBegin.ktype);
894 this.skip(mapBegin.vtype);
895 }
896 this.readMapEnd();
897 break;
898 case Type.SET:
899 var setBegin = this.readSetBegin();
900 for (var i2 = 0; i2 < setBegin.size; ++i2) {
901 this.skip(setBegin.etype);
902 }
903 this.readSetEnd();
904 break;
905 case Type.LIST:
906 var listBegin = this.readListBegin();
907 for (var i3 = 0; i3 < listBegin.size; ++i3) {
908 this.skip(listBegin.etype);
909 }
910 this.readListEnd();
911 break;
912 default:
913 throw new Error("Invalid type: " + type);
914 }
915 };