123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622 |
- /* ProtocolBuffer client 0.1.0*/
- /**
- * pomelo-protobuf
- * @author <zhang0935@gmail.com>
- */
- /**
- * Protocol buffer root
- * In browser, it will be window.protbuf
- */
- (function (exports, global){
- var Protobuf = exports;
- Protobuf.init = function(opts){
- //On the serverside, use serverProtos to encode messages send to client
- Protobuf.encoder.init(opts.encoderProtos);
- //On the serverside, user clientProtos to decode messages receive from clients
- Protobuf.decoder.init(opts.decoderProtos);
- };
- Protobuf.encode = function(key, msg){
- return Protobuf.encoder.encode(key, msg);
- };
- Protobuf.decode = function(key, msg){
- return Protobuf.decoder.decode(key, msg);
- };
- // exports to support for components
- module.exports = Protobuf;
- if(typeof(window) != "undefined") {
- window.protobuf = Protobuf;
- }
-
- })(typeof(window) == "undefined" ? module.exports : (this.protobuf = {}), this);
- /**
- * constants
- */
- (function (exports, global){
- var constants = exports.constants = {};
- constants.TYPES = {
- uInt32 : 0,
- sInt32 : 0,
- int32 : 0,
- double : 1,
- string : 2,
- message : 2,
- float : 5
- };
- })('undefined' !== typeof protobuf ? protobuf : module.exports, this);
- /**
- * util module
- */
- (function (exports, global){
- var Util = exports.util = {};
- Util.isSimpleType = function(type){
- return ( type === 'uInt32' ||
- type === 'sInt32' ||
- type === 'int32' ||
- type === 'uInt64' ||
- type === 'sInt64' ||
- type === 'float' ||
- type === 'double' );
- };
- })('undefined' !== typeof protobuf ? protobuf : module.exports, this);
- /**
- * codec module
- */
- (function (exports, global){
- var Codec = exports.codec = {};
- var buffer = new ArrayBuffer(8);
- var float32Array = new Float32Array(buffer);
- var float64Array = new Float64Array(buffer);
- var uInt8Array = new Uint8Array(buffer);
- Codec.encodeUInt32 = function(n){
- var n = parseInt(n);
- if(isNaN(n) || n < 0){
- return null;
- }
- var result = [];
- do{
- var tmp = n % 128;
- var next = Math.floor(n/128);
- if(next !== 0){
- tmp = tmp + 128;
- }
- result.push(tmp);
- n = next;
- }while(n !== 0);
- return result;
- };
- Codec.encodeSInt32 = function(n){
- var n = parseInt(n);
- if(isNaN(n)){
- return null;
- }
- n = n<0?(Math.abs(n)*2-1):n*2;
- return Codec.encodeUInt32(n);
- };
- Codec.decodeUInt32 = function(bytes){
- var n = 0;
- for(var i = 0; i < bytes.length; i++){
- var m = parseInt(bytes[i]);
- n = n + ((m & 0x7f) * Math.pow(2,(7*i)));
- if(m < 128){
- return n;
- }
- }
- return n;
- };
- Codec.decodeSInt32 = function(bytes){
- var n = this.decodeUInt32(bytes);
- var flag = ((n%2) === 1)?-1:1;
- n = ((n%2 + n)/2)*flag;
- return n;
- };
- Codec.encodeFloat = function(float){
- float32Array[0] = float;
- return uInt8Array;
- };
- Codec.decodeFloat = function(bytes, offset){
- if(!bytes || bytes.length < (offset + 4)){
- return null;
- }
- for(var i = 0; i < 4; i++){
- uInt8Array[i] = bytes[offset + i];
- }
- return float32Array[0];
- };
- Codec.encodeDouble = function(double){
- float64Array[0] = double;
- return uInt8Array.subarray(0, 8);
- };
- Codec.decodeDouble = function(bytes, offset){
- if(!bytes || bytes.length < (offset + 8)){
- return null;
- }
- for(var i = 0; i < 8; i++){
- uInt8Array[i] = bytes[offset + i];
- }
- return float64Array[0];
- };
- Codec.encodeStr = function(bytes, offset, str){
- for(var i = 0; i < str.length; i++){
- var code = str.charCodeAt(i);
- var codes = encode2UTF8(code);
- for(var j = 0; j < codes.length; j++){
- bytes[offset] = codes[j];
- offset++;
- }
- }
- return offset;
- };
- /**
- * Decode string from utf8 bytes
- */
- Codec.decodeStr = function(bytes, offset, length){
- var array = [];
- var end = offset + length;
- while(offset < end){
- var code = 0;
- if(bytes[offset] < 128){
- code = bytes[offset];
- offset += 1;
- }else if(bytes[offset] < 224){
- code = ((bytes[offset] & 0x3f)<<6) + (bytes[offset+1] & 0x3f);
- offset += 2;
- }else{
- code = ((bytes[offset] & 0x0f)<<12) + ((bytes[offset+1] & 0x3f)<<6) + (bytes[offset+2] & 0x3f);
- offset += 3;
- }
- array.push(code);
- }
- var str = '';
- for(var i = 0; i < array.length;){
- str += String.fromCharCode.apply(null, array.slice(i, i + 10000));
- i += 10000;
- }
- return str;
- };
- /**
- * Return the byte length of the str use utf8
- */
- Codec.byteLength = function(str){
- if(typeof(str) !== 'string'){
- return -1;
- }
- var length = 0;
- for(var i = 0; i < str.length; i++){
- var code = str.charCodeAt(i);
- length += codeLength(code);
- }
- return length;
- };
- /**
- * Encode a unicode16 char code to utf8 bytes
- */
- function encode2UTF8(charCode){
- if(charCode <= 0x7f){
- return [charCode];
- }else if(charCode <= 0x7ff){
- return [0xc0|(charCode>>6), 0x80|(charCode & 0x3f)];
- }else{
- return [0xe0|(charCode>>12), 0x80|((charCode & 0xfc0)>>6), 0x80|(charCode & 0x3f)];
- }
- }
- function codeLength(code){
- if(code <= 0x7f){
- return 1;
- }else if(code <= 0x7ff){
- return 2;
- }else{
- return 3;
- }
- }
- })('undefined' !== typeof protobuf ? protobuf : module.exports, this);
- /**
- * encoder module
- */
- (function (exports, global){
- var protobuf = exports;
- var MsgEncoder = exports.encoder = {};
- var codec = protobuf.codec;
- var constant = protobuf.constants;
- var util = protobuf.util;
- MsgEncoder.init = function(protos){
- this.protos = protos || {};
- };
- MsgEncoder.encode = function(route, msg){
- //Get protos from protos map use the route as key
- var protos = this.protos[route];
- //Check msg
- if(!checkMsg(msg, protos)){
- return null;
- }
- //Set the length of the buffer 2 times bigger to prevent overflow
- var length = codec.byteLength(JSON.stringify(msg));
- //Init buffer and offset
- var buffer = new ArrayBuffer(length);
- var uInt8Array = new Uint8Array(buffer);
- var offset = 0;
- if(!!protos){
- offset = encodeMsg(uInt8Array, offset, protos, msg);
- if(offset > 0){
- return uInt8Array.subarray(0, offset);
- }
- }
- return null;
- };
- /**
- * Check if the msg follow the defination in the protos
- */
- function checkMsg(msg, protos){
- if(!protos){
- return false;
- }
- for(var name in protos){
- var proto = protos[name];
- //All required element must exist
- switch(proto.option){
- case 'required' :
- if(typeof(msg[name]) === 'undefined'){
- console.warn('no property exist for required! name: %j, proto: %j, msg: %j', name, proto, msg);
- return false;
- }
- case 'optional' :
- if(typeof(msg[name]) !== 'undefined'){
- var message = protos.__messages[proto.type] || MsgEncoder.protos['message ' + proto.type];
- if(!!message && !checkMsg(msg[name], message)){
- console.warn('inner proto error! name: %j, proto: %j, msg: %j', name, proto, msg);
- return false;
- }
- }
- break;
- case 'repeated' :
- //Check nest message in repeated elements
- var message = protos.__messages[proto.type] || MsgEncoder.protos['message ' + proto.type];
- if(!!msg[name] && !!message){
- for(var i = 0; i < msg[name].length; i++){
- if(!checkMsg(msg[name][i], message)){
- return false;
- }
- }
- }
- break;
- }
- }
- return true;
- }
- function encodeMsg(buffer, offset, protos, msg){
- for(var name in msg){
- if(!!protos[name]){
- var proto = protos[name];
- switch(proto.option){
- case 'required' :
- case 'optional' :
- offset = writeBytes(buffer, offset, encodeTag(proto.type, proto.tag));
- offset = encodeProp(msg[name], proto.type, offset, buffer, protos);
- break;
- case 'repeated' :
- if(msg[name].length > 0){
- offset = encodeArray(msg[name], proto, offset, buffer, protos);
- }
- break;
- }
- }
- }
- return offset;
- }
- function encodeProp(value, type, offset, buffer, protos){
- switch(type){
- case 'uInt32':
- offset = writeBytes(buffer, offset, codec.encodeUInt32(value));
- break;
- case 'int32' :
- case 'sInt32':
- offset = writeBytes(buffer, offset, codec.encodeSInt32(value));
- break;
- case 'float':
- writeBytes(buffer, offset, codec.encodeFloat(value));
- offset += 4;
- break;
- case 'double':
- writeBytes(buffer, offset, codec.encodeDouble(value));
- offset += 8;
- break;
- case 'string':
- var length = codec.byteLength(value);
- //Encode length
- offset = writeBytes(buffer, offset, codec.encodeUInt32(length));
- //write string
- codec.encodeStr(buffer, offset, value);
- offset += length;
- break;
- default :
- var message = protos.__messages[type] || MsgEncoder.protos['message ' + type];
- if(!!message){
- //Use a tmp buffer to build an internal msg
- var tmpBuffer = new ArrayBuffer(codec.byteLength(JSON.stringify(value))*2);
- var length = 0;
- length = encodeMsg(tmpBuffer, length, message, value);
- //Encode length
- offset = writeBytes(buffer, offset, codec.encodeUInt32(length));
- //contact the object
- for(var i = 0; i < length; i++){
- buffer[offset] = tmpBuffer[i];
- offset++;
- }
- }
- break;
- }
- return offset;
- }
- /**
- * Encode reapeated properties, simple msg and object are decode differented
- */
- function encodeArray(array, proto, offset, buffer, protos){
- var i = 0;
- if(util.isSimpleType(proto.type)){
- offset = writeBytes(buffer, offset, encodeTag(proto.type, proto.tag));
- offset = writeBytes(buffer, offset, codec.encodeUInt32(array.length));
- for(i = 0; i < array.length; i++){
- offset = encodeProp(array[i], proto.type, offset, buffer);
- }
- }else{
- for(i = 0; i < array.length; i++){
- offset = writeBytes(buffer, offset, encodeTag(proto.type, proto.tag));
- offset = encodeProp(array[i], proto.type, offset, buffer, protos);
- }
- }
- return offset;
- }
- function writeBytes(buffer, offset, bytes){
- for(var i = 0; i < bytes.length; i++, offset++){
- buffer[offset] = bytes[i];
- }
- return offset;
- }
- function encodeTag(type, tag){
- var value = constant.TYPES[type]||2;
- return codec.encodeUInt32((tag<<3)|value);
- }
- })('undefined' !== typeof protobuf ? protobuf : module.exports, this);
- /**
- * decoder module
- */
- (function (exports, global){
- var protobuf = exports;
- var MsgDecoder = exports.decoder = {};
- var codec = protobuf.codec;
- var util = protobuf.util;
- var buffer;
- var offset = 0;
- MsgDecoder.init = function(protos){
- this.protos = protos || {};
- };
- MsgDecoder.setProtos = function(protos){
- if(!!protos){
- this.protos = protos;
- }
- };
- MsgDecoder.decode = function(route, buf){
- var protos = this.protos[route];
- buffer = buf;
- offset = 0;
- if(!!protos){
- return decodeMsg({}, protos, buffer.length);
- }
- return null;
- };
- function decodeMsg(msg, protos, length){
- while(offset<length){
- var head = getHead();
- var type = head.type;
- var tag = head.tag;
- var name = protos.__tags[tag];
- switch(protos[name].option){
- case 'optional' :
- case 'required' :
- msg[name] = decodeProp(protos[name].type, protos);
- break;
- case 'repeated' :
- if(!msg[name]){
- msg[name] = [];
- }
- decodeArray(msg[name], protos[name].type, protos);
- break;
- }
- }
- return msg;
- }
- /**
- * Test if the given msg is finished
- */
- function isFinish(msg, protos){
- return (!protos.__tags[peekHead().tag]);
- }
- /**
- * Get property head from protobuf
- */
- function getHead(){
- var tag = codec.decodeUInt32(getBytes());
- return {
- type : tag&0x7,
- tag : tag>>3
- };
- }
- /**
- * Get tag head without move the offset
- */
- function peekHead(){
- var tag = codec.decodeUInt32(peekBytes());
- return {
- type : tag&0x7,
- tag : tag>>3
- };
- }
- function decodeProp(type, protos){
- switch(type){
- case 'uInt32':
- return codec.decodeUInt32(getBytes());
- case 'int32' :
- case 'sInt32' :
- return codec.decodeSInt32(getBytes());
- case 'float' :
- var float = codec.decodeFloat(buffer, offset);
- offset += 4;
- return float;
- case 'double' :
- var double = codec.decodeDouble(buffer, offset);
- offset += 8;
- return double;
- case 'string' :
- var length = codec.decodeUInt32(getBytes());
- var str = codec.decodeStr(buffer, offset, length);
- offset += length;
- return str;
- default :
- var message = protos && (protos.__messages[type] || MsgDecoder.protos['message ' + type]);
- if(!!message){
- var length = codec.decodeUInt32(getBytes());
- var msg = {};
- decodeMsg(msg, message, offset+length);
- return msg;
- }
- break;
- }
- }
- function decodeArray(array, type, protos){
- if(util.isSimpleType(type)){
- var length = codec.decodeUInt32(getBytes());
- for(var i = 0; i < length; i++){
- array.push(decodeProp(type));
- }
- }else{
- array.push(decodeProp(type, protos));
- }
- }
- function getBytes(flag){
- var bytes = [];
- var pos = offset;
- flag = flag || false;
- var b;
- do{
- b = buffer[pos];
- bytes.push(b);
- pos++;
- }while(b >= 128);
- if(!flag){
- offset = pos;
- }
- return bytes;
- }
- function peekBytes(){
- return getBytes(true);
- }
- })('undefined' !== typeof protobuf ? protobuf : module.exports, this);
|