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 20var Int64 = require('node-int64'); 21var Thrift = require('./thrift'); 22var Type = Thrift.Type; 23var util = require("util"); 24 25var Int64Util = require('./int64_util'); 26var json_parse = require('./json_parse'); 27 28var InputBufferUnderrunError = require('./input_buffer_underrun_error'); 29 30module.exports = TJSONProtocol; 31 32/** 33 * Initializes a Thrift JSON protocol instance. 34 * @constructor 35 * @param {Thrift.Transport} trans - The transport to serialize to/from. 36 * @classdesc Apache Thrift Protocols perform serialization which enables cross 37 * language RPC. The Protocol type is the JavaScript browser implementation 38 * of the Apache Thrift TJSONProtocol. 39 * @example 40 * var protocol = new Thrift.Protocol(transport); 41 */ 42function TJSONProtocol(trans) { 43 this.tstack = []; 44 this.tpos = []; 45 this.trans = trans; 46}; 47 48/** 49 * Thrift IDL type Id to string mapping. 50 * @readonly 51 * @see {@link Thrift.Type} 52 */ 53TJSONProtocol.Type = {}; 54TJSONProtocol.Type[Type.BOOL] = '"tf"'; 55TJSONProtocol.Type[Type.BYTE] = '"i8"'; 56TJSONProtocol.Type[Type.I16] = '"i16"'; 57TJSONProtocol.Type[Type.I32] = '"i32"'; 58TJSONProtocol.Type[Type.I64] = '"i64"'; 59TJSONProtocol.Type[Type.DOUBLE] = '"dbl"'; 60TJSONProtocol.Type[Type.STRUCT] = '"rec"'; 61TJSONProtocol.Type[Type.STRING] = '"str"'; 62TJSONProtocol.Type[Type.MAP] = '"map"'; 63TJSONProtocol.Type[Type.LIST] = '"lst"'; 64TJSONProtocol.Type[Type.SET] = '"set"'; 65 66/** 67 * Thrift IDL type string to Id mapping. 68 * @readonly 69 * @see {@link Thrift.Type} 70 */ 71TJSONProtocol.RType = {}; 72TJSONProtocol.RType.tf = Type.BOOL; 73TJSONProtocol.RType.i8 = Type.BYTE; 74TJSONProtocol.RType.i16 = Type.I16; 75TJSONProtocol.RType.i32 = Type.I32; 76TJSONProtocol.RType.i64 = Type.I64; 77TJSONProtocol.RType.dbl = Type.DOUBLE; 78TJSONProtocol.RType.rec = Type.STRUCT; 79TJSONProtocol.RType.str = Type.STRING; 80TJSONProtocol.RType.map = Type.MAP; 81TJSONProtocol.RType.lst = Type.LIST; 82TJSONProtocol.RType.set = Type.SET; 83 84/** 85 * The TJSONProtocol version number. 86 * @readonly 87 * @const {number} Version 88 * @memberof Thrift.Protocol 89 */ 90TJSONProtocol.Version = 1; 91 92TJSONProtocol.prototype.flush = function() { 93 this.writeToTransportIfStackIsFlushable(); 94 return this.trans.flush(); 95}; 96 97TJSONProtocol.prototype.writeToTransportIfStackIsFlushable = function() { 98 if (this.tstack.length === 1) { 99 this.trans.write(this.tstack.pop()); 100 } 101}; 102 103/** 104 * Serializes the beginning of a Thrift RPC message. 105 * @param {string} name - The service method to call. 106 * @param {Thrift.MessageType} messageType - The type of method call. 107 * @param {number} seqid - The sequence number of this call (always 0 in Apache Thrift). 108 */ 109TJSONProtocol.prototype.writeMessageBegin = function(name, messageType, seqid) { 110 this.tstack.push([TJSONProtocol.Version, '"' + name + '"', messageType, seqid]); 111}; 112 113/** 114 * Serializes the end of a Thrift RPC message. 115 */ 116TJSONProtocol.prototype.writeMessageEnd = function() { 117 var obj = this.tstack.pop(); 118 119 this.wobj = this.tstack.pop(); 120 this.wobj.push(obj); 121 122 this.wbuf = '[' + this.wobj.join(',') + ']'; 123 124 // we assume there is nothing more to come so we write 125 this.trans.write(this.wbuf); 126}; 127 128/** 129 * Serializes the beginning of a struct. 130 * @param {string} name - The name of the struct. 131 */ 132TJSONProtocol.prototype.writeStructBegin = function(name) { 133 this.tpos.push(this.tstack.length); 134 this.tstack.push({}); 135}; 136 137/** 138 * Serializes the end of a struct. 139 */ 140TJSONProtocol.prototype.writeStructEnd = function() { 141 var p = this.tpos.pop(); 142 var struct = this.tstack[p]; 143 var str = '{'; 144 var first = true; 145 for (var key in struct) { 146 if (first) { 147 first = false; 148 } else { 149 str += ','; 150 } 151 152 str += key + ':' + struct[key]; 153 } 154 155 str += '}'; 156 this.tstack[p] = str; 157 158 this.writeToTransportIfStackIsFlushable(); 159}; 160 161/** 162 * Serializes the beginning of a struct field. 163 * @param {string} name - The name of the field. 164 * @param {Thrift.Protocol.Type} fieldType - The data type of the field. 165 * @param {number} fieldId - The field's unique identifier. 166 */ 167TJSONProtocol.prototype.writeFieldBegin = function(name, fieldType, fieldId) { 168 this.tpos.push(this.tstack.length); 169 this.tstack.push({ 'fieldId': '"' + 170 fieldId + '"', 'fieldType': TJSONProtocol.Type[fieldType] 171 }); 172}; 173 174/** 175 * Serializes the end of a field. 176 */ 177TJSONProtocol.prototype.writeFieldEnd = function() { 178 var value = this.tstack.pop(); 179 var fieldInfo = this.tstack.pop(); 180 181 if (':' + value === ":[object Object]") { 182 this.tstack[this.tstack.length - 1][fieldInfo.fieldId] = '{' + 183 fieldInfo.fieldType + ':' + JSON.stringify(value) + '}'; 184 } else { 185 this.tstack[this.tstack.length - 1][fieldInfo.fieldId] = '{' + 186 fieldInfo.fieldType + ':' + value + '}'; 187 } 188 this.tpos.pop(); 189 190 this.writeToTransportIfStackIsFlushable(); 191}; 192 193/** 194 * Serializes the end of the set of fields for a struct. 195 */ 196TJSONProtocol.prototype.writeFieldStop = function() { 197}; 198 199/** 200 * Serializes the beginning of a map collection. 201 * @param {Thrift.Type} keyType - The data type of the key. 202 * @param {Thrift.Type} valType - The data type of the value. 203 * @param {number} [size] - The number of elements in the map (ignored). 204 */ 205TJSONProtocol.prototype.writeMapBegin = function(keyType, valType, size) { 206 //size is invalid, we'll set it on end. 207 this.tpos.push(this.tstack.length); 208 this.tstack.push([TJSONProtocol.Type[keyType], TJSONProtocol.Type[valType], 0]); 209}; 210 211/** 212 * Serializes the end of a map. 213 */ 214TJSONProtocol.prototype.writeMapEnd = function() { 215 var p = this.tpos.pop(); 216 217 if (p == this.tstack.length) { 218 return; 219 } 220 221 if ((this.tstack.length - p - 1) % 2 !== 0) { 222 this.tstack.push(''); 223 } 224 225 var size = (this.tstack.length - p - 1) / 2; 226 227 this.tstack[p][this.tstack[p].length - 1] = size; 228 229 var map = '}'; 230 var first = true; 231 while (this.tstack.length > p + 1) { 232 var v = this.tstack.pop(); 233 var k = this.tstack.pop(); 234 if (first) { 235 first = false; 236 } else { 237 map = ',' + map; 238 } 239 240 if (! isNaN(k)) { k = '"' + k + '"'; } //json "keys" need to be strings 241 map = k + ':' + v + map; 242 } 243 map = '{' + map; 244 245 this.tstack[p].push(map); 246 this.tstack[p] = '[' + this.tstack[p].join(',') + ']'; 247 248 this.writeToTransportIfStackIsFlushable(); 249}; 250 251/** 252 * Serializes the beginning of a list collection. 253 * @param {Thrift.Type} elemType - The data type of the elements. 254 * @param {number} size - The number of elements in the list. 255 */ 256TJSONProtocol.prototype.writeListBegin = function(elemType, size) { 257 this.tpos.push(this.tstack.length); 258 this.tstack.push([TJSONProtocol.Type[elemType], size]); 259}; 260 261/** 262 * Serializes the end of a list. 263 */ 264TJSONProtocol.prototype.writeListEnd = function() { 265 var p = this.tpos.pop(); 266 267 while (this.tstack.length > p + 1) { 268 var tmpVal = this.tstack[p + 1]; 269 this.tstack.splice(p + 1, 1); 270 this.tstack[p].push(tmpVal); 271 } 272 273 this.tstack[p] = '[' + this.tstack[p].join(',') + ']'; 274 275 this.writeToTransportIfStackIsFlushable(); 276}; 277 278/** 279 * Serializes the beginning of a set collection. 280 * @param {Thrift.Type} elemType - The data type of the elements. 281 * @param {number} size - The number of elements in the list. 282 */ 283TJSONProtocol.prototype.writeSetBegin = function(elemType, size) { 284 this.tpos.push(this.tstack.length); 285 this.tstack.push([TJSONProtocol.Type[elemType], size]); 286}; 287 288/** 289 * Serializes the end of a set. 290 */ 291TJSONProtocol.prototype.writeSetEnd = function() { 292 var p = this.tpos.pop(); 293 294 while (this.tstack.length > p + 1) { 295 var tmpVal = this.tstack[p + 1]; 296 this.tstack.splice(p + 1, 1); 297 this.tstack[p].push(tmpVal); 298 } 299 300 this.tstack[p] = '[' + this.tstack[p].join(',') + ']'; 301 302 this.writeToTransportIfStackIsFlushable(); 303}; 304 305/** Serializes a boolean */ 306TJSONProtocol.prototype.writeBool = function(bool) { 307 this.tstack.push(bool ? 1 : 0); 308}; 309 310/** Serializes a number */ 311TJSONProtocol.prototype.writeByte = function(byte) { 312 this.tstack.push(byte); 313}; 314 315/** Serializes a number */ 316TJSONProtocol.prototype.writeI16 = function(i16) { 317 this.tstack.push(i16); 318}; 319 320/** Serializes a number */ 321TJSONProtocol.prototype.writeI32 = function(i32) { 322 this.tstack.push(i32); 323}; 324 325/** Serializes a number */ 326TJSONProtocol.prototype.writeI64 = function(i64) { 327 if (i64 instanceof Int64) { 328 this.tstack.push(Int64Util.toDecimalString(i64)); 329 } else { 330 this.tstack.push(i64); 331 } 332}; 333 334/** Serializes a number */ 335TJSONProtocol.prototype.writeDouble = function(dub) { 336 this.tstack.push(dub); 337}; 338 339/** Serializes a string */ 340TJSONProtocol.prototype.writeString = function(arg) { 341 // We do not encode uri components for wire transfer: 342 if (arg === null) { 343 this.tstack.push(null); 344 } else { 345 if (typeof arg === 'string') { 346 var str = arg; 347 } else if (arg instanceof Buffer) { 348 var str = arg.toString('utf8'); 349 } else { 350 throw new Error('writeString called without a string/Buffer argument: ' + arg); 351 } 352 353 // concat may be slower than building a byte buffer 354 var escapedString = ''; 355 for (var i = 0; i < str.length; i++) { 356 var ch = str.charAt(i); // a single double quote: " 357 if (ch === '\"') { 358 escapedString += '\\\"'; // write out as: \" 359 } else if (ch === '\\') { // a single backslash: \ 360 escapedString += '\\\\'; // write out as: \\ 361 /* Currently escaped forward slashes break TJSONProtocol. 362 * As it stands, we can simply pass forward slashes into 363 * our strings across the wire without being escaped. 364 * I think this is the protocol's bug, not thrift.js 365 * } else if(ch === '/') { // a single forward slash: / 366 * escapedString += '\\/'; // write out as \/ 367 * } 368 */ 369 } else if (ch === '\b') { // a single backspace: invisible 370 escapedString += '\\b'; // write out as: \b" 371 } else if (ch === '\f') { // a single formfeed: invisible 372 escapedString += '\\f'; // write out as: \f" 373 } else if (ch === '\n') { // a single newline: invisible 374 escapedString += '\\n'; // write out as: \n" 375 } else if (ch === '\r') { // a single return: invisible 376 escapedString += '\\r'; // write out as: \r" 377 } else if (ch === '\t') { // a single tab: invisible 378 escapedString += '\\t'; // write out as: \t" 379 } else { 380 escapedString += ch; // Else it need not be escaped 381 } 382 } 383 this.tstack.push('"' + escapedString + '"'); 384 } 385}; 386 387/** Serializes a string */ 388TJSONProtocol.prototype.writeBinary = function(arg) { 389 if (typeof arg === 'string') { 390 var buf = new Buffer(arg, 'binary'); 391 } else if (arg instanceof Buffer || 392 Object.prototype.toString.call(arg) == '[object Uint8Array]') { 393 var buf = arg; 394 } else { 395 throw new Error('writeBinary called without a string/Buffer argument: ' + arg); 396 } 397 this.tstack.push('"' + buf.toString('base64') + '"'); 398}; 399 400/** 401 * @class 402 * @name AnonReadMessageBeginReturn 403 * @property {string} fname - The name of the service method. 404 * @property {Thrift.MessageType} mtype - The type of message call. 405 * @property {number} rseqid - The sequence number of the message (0 in Thrift RPC). 406 */ 407/** 408 * Deserializes the beginning of a message. 409 * @returns {AnonReadMessageBeginReturn} 410 */ 411TJSONProtocol.prototype.readMessageBegin = function() { 412 this.rstack = []; 413 this.rpos = []; 414 415 //Borrow the inbound transport buffer and ensure data is present/consistent 416 var transBuf = this.trans.borrow(); 417 if (transBuf.readIndex >= transBuf.writeIndex) { 418 throw new InputBufferUnderrunError(); 419 } 420 var cursor = transBuf.readIndex; 421 422 if (transBuf.buf[cursor] !== 0x5B) { //[ 423 throw new Error("Malformed JSON input, no opening bracket"); 424 } 425 426 //Parse a single message (there may be several in the buffer) 427 // TODO: Handle characters using multiple code units 428 cursor++; 429 var openBracketCount = 1; 430 var inString = false; 431 for (; cursor < transBuf.writeIndex; cursor++) { 432 var chr = transBuf.buf[cursor]; 433 //we use hexa charcode here because data[i] returns an int and not a char 434 if (inString) { 435 if (chr === 0x22) { //" 436 inString = false; 437 } else if (chr === 0x5C) { //\ 438 //escaped character, skip 439 cursor += 1; 440 } 441 } else { 442 if (chr === 0x5B) { //[ 443 openBracketCount += 1; 444 } else if (chr === 0x5D) { //] 445 openBracketCount -= 1; 446 if (openBracketCount === 0) { 447 //end of json message detected 448 break; 449 } 450 } else if (chr === 0x22) { //" 451 inString = true; 452 } 453 } 454 } 455 456 if (openBracketCount !== 0) { 457 // Missing closing bracket. Can be buffer underrun. 458 throw new InputBufferUnderrunError(); 459 } 460 461 //Reconstitute the JSON object and conume the necessary bytes 462 this.robj = json_parse(transBuf.buf.slice(transBuf.readIndex, cursor+1).toString()); 463 this.trans.consume(cursor + 1 - transBuf.readIndex); 464 465 //Verify the protocol version 466 var version = this.robj.shift(); 467 if (version != TJSONProtocol.Version) { 468 throw new Error('Wrong thrift protocol version: ' + version); 469 } 470 471 //Objectify the thrift message {name/type/sequence-number} for return 472 // and then save the JSON object in rstack 473 var r = {}; 474 r.fname = this.robj.shift(); 475 r.mtype = this.robj.shift(); 476 r.rseqid = this.robj.shift(); 477 this.rstack.push(this.robj.shift()); 478 return r; 479}; 480 481/** Deserializes the end of a message. */ 482TJSONProtocol.prototype.readMessageEnd = function() { 483}; 484 485/** 486 * Deserializes the beginning of a struct. 487 * @param {string} [name] - The name of the struct (ignored) 488 * @returns {object} - An object with an empty string fname property 489 */ 490TJSONProtocol.prototype.readStructBegin = function() { 491 var r = {}; 492 r.fname = ''; 493 494 //incase this is an array of structs 495 if (this.rstack[this.rstack.length - 1] instanceof Array) { 496 this.rstack.push(this.rstack[this.rstack.length - 1].shift()); 497 } 498 499 return r; 500}; 501 502/** Deserializes the end of a struct. */ 503TJSONProtocol.prototype.readStructEnd = function() { 504 this.rstack.pop(); 505}; 506 507/** 508 * @class 509 * @name AnonReadFieldBeginReturn 510 * @property {string} fname - The name of the field (always ''). 511 * @property {Thrift.Type} ftype - The data type of the field. 512 * @property {number} fid - The unique identifier of the field. 513 */ 514/** 515 * Deserializes the beginning of a field. 516 * @returns {AnonReadFieldBeginReturn} 517 */ 518TJSONProtocol.prototype.readFieldBegin = function() { 519 var r = {}; 520 521 var fid = -1; 522 var ftype = Type.STOP; 523 524 //get a fieldId 525 for (var f in (this.rstack[this.rstack.length - 1])) { 526 if (f === null) { 527 continue; 528 } 529 530 fid = parseInt(f, 10); 531 this.rpos.push(this.rstack.length); 532 533 var field = this.rstack[this.rstack.length - 1][fid]; 534 535 //remove so we don't see it again 536 delete this.rstack[this.rstack.length - 1][fid]; 537 538 this.rstack.push(field); 539 540 break; 541 } 542 543 if (fid != -1) { 544 //should only be 1 of these but this is the only 545 //way to match a key 546 for (var i in (this.rstack[this.rstack.length - 1])) { 547 if (TJSONProtocol.RType[i] === null) { 548 continue; 549 } 550 551 ftype = TJSONProtocol.RType[i]; 552 this.rstack[this.rstack.length - 1] = this.rstack[this.rstack.length - 1][i]; 553 } 554 } 555 556 r.fname = ''; 557 r.ftype = ftype; 558 r.fid = fid; 559 560 return r; 561}; 562 563/** Deserializes the end of a field. */ 564TJSONProtocol.prototype.readFieldEnd = function() { 565 var pos = this.rpos.pop(); 566 567 //get back to the right place in the stack 568 while (this.rstack.length > pos) { 569 this.rstack.pop(); 570 } 571}; 572 573/** 574 * @class 575 * @name AnonReadMapBeginReturn 576 * @property {Thrift.Type} ktype - The data type of the key. 577 * @property {Thrift.Type} vtype - The data type of the value. 578 * @property {number} size - The number of elements in the map. 579 */ 580/** 581 * Deserializes the beginning of a map. 582 * @returns {AnonReadMapBeginReturn} 583 */ 584TJSONProtocol.prototype.readMapBegin = function() { 585 var map = this.rstack.pop(); 586 var first = map.shift(); 587 if (first instanceof Array) { 588 this.rstack.push(map); 589 map = first; 590 first = map.shift(); 591 } 592 593 var r = {}; 594 r.ktype = TJSONProtocol.RType[first]; 595 r.vtype = TJSONProtocol.RType[map.shift()]; 596 r.size = map.shift(); 597 598 599 this.rpos.push(this.rstack.length); 600 this.rstack.push(map.shift()); 601 602 return r; 603}; 604 605/** Deserializes the end of a map. */ 606TJSONProtocol.prototype.readMapEnd = function() { 607 this.readFieldEnd(); 608}; 609 610/** 611 * @class 612 * @name AnonReadColBeginReturn 613 * @property {Thrift.Type} etype - The data type of the element. 614 * @property {number} size - The number of elements in the collection. 615 */ 616/** 617 * Deserializes the beginning of a list. 618 * @returns {AnonReadColBeginReturn} 619 */ 620TJSONProtocol.prototype.readListBegin = function() { 621 var list = this.rstack[this.rstack.length - 1]; 622 623 var r = {}; 624 r.etype = TJSONProtocol.RType[list.shift()]; 625 r.size = list.shift(); 626 627 this.rpos.push(this.rstack.length); 628 this.rstack.push(list.shift()); 629 630 return r; 631}; 632 633/** Deserializes the end of a list. */ 634TJSONProtocol.prototype.readListEnd = function() { 635 var pos = this.rpos.pop() - 2; 636 var st = this.rstack; 637 st.pop(); 638 if (st instanceof Array && st.length > pos && st[pos].length > 0) { 639 st.push(st[pos].shift()); 640 } 641}; 642 643/** 644 * Deserializes the beginning of a set. 645 * @returns {AnonReadColBeginReturn} 646 */ 647TJSONProtocol.prototype.readSetBegin = function() { 648 return this.readListBegin(); 649}; 650 651/** Deserializes the end of a set. */ 652TJSONProtocol.prototype.readSetEnd = function() { 653 return this.readListEnd(); 654}; 655 656TJSONProtocol.prototype.readBool = function() { 657 return this.readValue() == '1'; 658}; 659 660TJSONProtocol.prototype.readByte = function() { 661 return this.readI32(); 662}; 663 664TJSONProtocol.prototype.readI16 = function() { 665 return this.readI32(); 666}; 667 668TJSONProtocol.prototype.readI32 = function(f) { 669 return +this.readValue(); 670} 671 672/** Returns the next value found in the protocol buffer */ 673TJSONProtocol.prototype.readValue = function(f) { 674 if (f === undefined) { 675 f = this.rstack[this.rstack.length - 1]; 676 } 677 678 var r = {}; 679 680 if (f instanceof Array) { 681 if (f.length === 0) { 682 r.value = undefined; 683 } else { 684 r.value = f.shift(); 685 } 686 } else if (!(f instanceof Int64) && f instanceof Object) { 687 for (var i in f) { 688 if (i === null) { 689 continue; 690 } 691 this.rstack.push(f[i]); 692 delete f[i]; 693 694 r.value = i; 695 break; 696 } 697 } else { 698 r.value = f; 699 this.rstack.pop(); 700 } 701 702 return r.value; 703}; 704 705TJSONProtocol.prototype.readI64 = function() { 706 var n = this.readValue() 707 if (typeof n === 'string') { 708 // Assuming no one is sending in 1.11111e+33 format 709 return Int64Util.fromDecimalString(n); 710 } else { 711 return new Int64(n); 712 } 713}; 714 715TJSONProtocol.prototype.readDouble = function() { 716 return this.readI32(); 717}; 718 719TJSONProtocol.prototype.readBinary = function() { 720 return new Buffer(this.readValue(), 'base64'); 721}; 722 723TJSONProtocol.prototype.readString = function() { 724 return this.readValue(); 725}; 726 727/** 728 * Returns the underlying transport. 729 * @readonly 730 * @returns {Thrift.Transport} The underlying transport. 731 */ 732TJSONProtocol.prototype.getTransport = function() { 733 return this.trans; 734}; 735 736/** 737 * Method to arbitrarily skip over data 738 */ 739TJSONProtocol.prototype.skip = function(type) { 740 switch (type) { 741 case Type.BOOL: 742 this.readBool(); 743 break; 744 case Type.BYTE: 745 this.readByte(); 746 break; 747 case Type.I16: 748 this.readI16(); 749 break; 750 case Type.I32: 751 this.readI32(); 752 break; 753 case Type.I64: 754 this.readI64(); 755 break; 756 case Type.DOUBLE: 757 this.readDouble(); 758 break; 759 case Type.STRING: 760 this.readString(); 761 break; 762 case Type.STRUCT: 763 this.readStructBegin(); 764 while (true) { 765 var r = this.readFieldBegin(); 766 if (r.ftype === Type.STOP) { 767 break; 768 } 769 this.skip(r.ftype); 770 this.readFieldEnd(); 771 } 772 this.readStructEnd(); 773 break; 774 case Type.MAP: 775 var mapBegin = this.readMapBegin(); 776 for (var i = 0; i < mapBegin.size; ++i) { 777 this.skip(mapBegin.ktype); 778 this.skip(mapBegin.vtype); 779 } 780 this.readMapEnd(); 781 break; 782 case Type.SET: 783 var setBegin = this.readSetBegin(); 784 for (var i2 = 0; i2 < setBegin.size; ++i2) { 785 this.skip(setBegin.etype); 786 } 787 this.readSetEnd(); 788 break; 789 case Type.LIST: 790 var listBegin = this.readListBegin(); 791 for (var i3 = 0; i3 < listBegin.size; ++i3) { 792 this.skip(listBegin.etype); 793 } 794 this.readListEnd(); 795 break; 796 default: 797 throw new Error("Invalid type: " + type); 798 } 799}; 800