//RemObjects SDK classes //interface var RemObjects = {}; RemObjects.SDK = { RTTI : { }, Enum : {}, ROComplexType : function ROComplexType() { }, ROEnumType : function ROEnumType() { }, ROStructType : function ROStructType() { }, ROArrayType : function ROArrayType() { this.elementType = ""; this.items = []; }, ROException : function ROException(e) { if (e) { this.name = e.name; this.message = e.message; }; this.fields = new RemObjects.SDK.ROStructType(); }, ROEventSink : function ROEventSink() { }, ClientChannel : function ClientChannel(aUrl) { this.url = aUrl; //post }, HTTPClientChannel : function HTTPClientChannel(aUrl) { RemObjects.SDK.ClientChannel.call(this, aUrl); }, Message : function Message() { this.fClientID = RemObjects.UTIL.NewGuid(); this.fRequestObject = {}; this.fResponseObject = {}; //clone //getClientID //setClientID }, JSONMessage : function JSONMessage() { RemObjects.SDK.Message.call(this); //initialize //finalize //write //read //requestStream //setResponseStream }, BinMessage : function BinMessage() { RemObjects.SDK.Message.call(this); //initialize //finalize //write //read //requestStream //setResponseStream }, BinHeader : function BinHeader() { this.fHeader = [0x52, 0x4f, 0x31, 0x30, 0x37]; //should contain 0x1c bytes for (var i = 5; i<0x1c; this.fHeader[i++] = 0); //readFrom //asStream //isValidHeader //getCompressed //setCompressed //getMessageType //setMessageType //setClientID // Header BINARY LAYOUT: 0x1C bytes // // Keep in sync with // - Delphi - uROBINMessage.pas // - C# - BinMessage.cs // // 52 4f 31 30 = "RO10" basic RO signature for RO 1.0 // XX YY ZZ -- = XX: subversion (currenly "7") // YY: option flags: 01 = compressed // ZZ: message type as defined in uROClientIntf // --: reserved for future use // -- -- UU UU = UU: user data (word) // CC CC CC CC 0x10 bytes ClientID (guid) // CC CC CC CC // CC CC CC CC // CC CC CC CC }, RemoteService : function RemoteService(aChannel, aMessage, aServiceName) { this.fChannel = aChannel; this.fMessage = aMessage; this.fServiceName = aServiceName; }, ROService : function ROService(aChannel, aMessage, aServiceName) { if (RemObjects.UTIL.checkArgumentTypes(arguments, [RemObjects.SDK.ClientChannel, RemObjects.SDK.Message, "string"]) || RemObjects.UTIL.checkArgumentTypes(arguments, [RemObjects.SDK.ClientChannel, RemObjects.SDK.Message, "undefined"])) { this.fChannel = aChannel; this.fMessage = aMessage; this.fServiceName = aServiceName; } else if (RemObjects.UTIL.checkArgumentTypes(arguments, [RemObjects.SDK.RemoteService, "undefined", "undefined"])) { this.fChannel = aChannel.fChannel; this.fMessage = aChannel.fMessage; this.fServiceName = aChannel.fServiceName; } else if (RemObjects.UTIL.checkArgumentTypes(arguments, ["string"])) { //URL var m = /https?:\/\/([-\w\.]+)+(:\d+)?\/([\w/_\.]*)/i.exec(aChannel); var path; if (m && m.length == 4 ) { path = m[3]; } else { m = /https?:\/\/\[((?=.*::)(?!.*::.+::)(::)?([\dA-F]{1,4}:(:|\b)|){5}|([\dA-F]{1,4}:){6})((([\dA-F]{1,4}((?!\3)::|:\b|$))|(?!\2\3)){2}|(((2[0-4]|1\d|[1-9])?\d|25[0-5])\.?\b){4})\](:\d+)\/([\w/_\.]*)$/i.exec(aChannel); if (!m) { throw new Error("ROService constructor: incorrect URL"); } else { path = m[14]; }; }; if (path.toLowerCase() == "json") { this.fMessage = new RemObjects.SDK.JSONMessage(); } else { this.fMessage = new RemObjects.SDK.BinMessage(); }; this.fChannel = new RemObjects.SDK.HTTPClientChannel(aChannel); if (typeof(aMessage) == "string") this.fServiceName = aMessage; } else if (!RemObjects.UTIL.checkArgumentTypes(arguments, ["undefined", "undefined", "undefined"])) { throw new Error("ROService constructor: Incorrect arguments"); }; //getChannel //getMessage //getServiceName }, EventReceiver : function EventReceiver(aChannel, aMessage, aServiceName, aTimeout) { this.fChannel = aChannel; this.fMessage = aMessage; this.fServiceName = aServiceName; this.fTimeout = aTimeout; this.fActive = false; this.fHandlers = {}; this.fInterval = null; //addHandler //intPollServer //setActive //getActive //getTimeout //setTimeout } }; RemObjects.UTIL = { testBrowser : function testBrowser() { var result = ""; if (typeof(JSON) == 'undefined') result += "Browser doesn't support JSON\n"; var AJAX; if (typeof(XMLHttpRequest) == 'undefined') { try { AJAX = new XMLHttpRequest(); } catch (e) { try { AJAX = new ActiveXObject("Msxml2.XMLHTTP"); } catch (e) { try { AJAX = new ActiveXObject("Microsoft.XMLHTTP"); } catch (e) { result += "Browser doesn't support XMLHttpRequest object\n"; }; }; }; }; result += RemObjects.UTIL.testBrowserBinary(); return result; }, testBrowserBinary : function testBrowserBinary() { var result = ""; if (!(((typeof(XMLHttpRequest) != 'undefined') && (typeof(XMLHttpRequest.prototype.sendAsBinary) != 'undefined')) || (typeof(Uint8Array) != 'undefined') )) result += "Browser doesn't support sending binary data\n"; return result; }, browserHasBinarySupport : function browserHasBinarySupport() { return RemObjects.UTIL.testBrowserBinary() == ""; }, showMessage : function(msg) { //for non-browser environments: //replace alert() call with something appropriate alert(msg); }, showError : function showError(msg, e) { var result = ""; if (e) { result += e.name + ": " + e.message; } else { result += msg.getErrorMessage() + "\n"; }; result += "\nCall stack:\n"; var fn = showError; // if (!(fn.caller)) //possibly IE // fn = arguments.callee; // while((fn = fn.caller) !== null) { // var fnName = fn.toString().match(/^function\s*(\w+)\(/); // fnName = (fnName) ? fnName[1] : 'anonymous function'; // result += fnName; // result += "\n"; // } RemObjects.UTIL.showMessage(result); }, toJSON : function toJSON(aValue) { if(typeof(JSON) != 'undefined') { var jsonString = JSON.stringify(aValue); jsonString = jsonString.replace(/[\u007F-\uFFFF]/g, function(chr) { return "\\u" + ("0000" + chr.charCodeAt(0).toString(16)).substr(-4) }); return jsonString; } else { throw new Error("Your browser doesn't support JSON.stringify"); }; }, parseJSON : function parseJSON(aValue) { if(typeof(JSON) != 'undefined') { return JSON.parse(aValue); } else { throw new Error("Your browser doesn't support JSON.parse"); }; }, NewGuid : function NewGuid() { return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) { var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8); return v.toString(16); }) }, GuidToArray : function GuidToArray(aGuid) { var result = []; aGuid = aGuid.replace(/-/g, ""); for (var i = 3; i >= 0; result.push(parseInt(aGuid.substr(i-- * 2, 2), 16))); for (var i = 5; i >= 4; result.push(parseInt(aGuid.substr(i-- * 2, 2), 16))); for (var i = 7; i >= 6; result.push(parseInt(aGuid.substr(i-- * 2, 2), 16))); for (var i = 8; i < 16; result.push(parseInt(aGuid.substr(i++ * 2, 2), 16))); // for (var i = 0; i < 16; result.push(parseInt(aGuid.substr(i++ * 2, 2), 16))); return result; }, guidToByteArray : function guidToByteArray(aGuid) { function readPart(str, start, end) { var result = ""; for (var i = start; i <= end; result += String.fromCharCode(parseInt(aGuid.substr(i++ * 2 + 1, 2), 16))); return result; }; function readPartReversed(str, start, end) { var result = ""; for (var i = end; i >= start; result += String.fromCharCode(parseInt(aGuid.substr(i-- * 2 + 1, 2), 16))); return result; }; aGuid = aGuid.replace(/-/g, ""); return readPartReversed(aGuid, 0, 3) + readPartReversed(aGuid, 4, 5) + readPartReversed(aGuid, 6, 7) + readPart(aGuid, 8, 9) + readPart(aGuid, 10, 15); }, zeroPad : function zeroPad(num, count) { var numZeropad = num + ''; while (numZeropad.length < count) { numZeropad = "0" + numZeropad; } return numZeropad; }, byteArrayToGuid : function byteArrayToGuid(byteArray) { function readPartReversed(str, start, end) { var result = ""; for (var i = end; i >= start; i--) { result += RemObjects.UTIL.zeroPad((str.charCodeAt(i) & 0xFF).toString(16).toUpperCase(), 2); }; return result; }; function readPart(str, start, end) { var result = ""; for (var i = start; i <= end; i++) { result += RemObjects.UTIL.zeroPad((str.charCodeAt(i) & 0xFF).toString(16).toUpperCase(), 2); }; return result; }; return "{" + readPartReversed(byteArray, 0, 3) + "-" + readPartReversed(byteArray, 4, 5) + "-" + readPartReversed(byteArray, 6, 7) + "-" + readPart(byteArray, 8, 9) + "-" + readPart(byteArray, 10, 15) + "}"; }, strToByteArray : function strToByteArray(str) { var byteArray = []; for (var i = 0; i < str.length; i++) if (str.charCodeAt(i) <= 0x7F) byteArray.push(str.substr(i, 1)); else { var h = encodeURIComponent(str.charAt(i)).substr(1).split('%'); for (var j = 0; j < h.length; j++) byteArray.push(String.fromCharCode(parseInt(h[j], 16))); }; return byteArray.join(""); }, byteArrayToStr : function byteArrayToStr(byteArray) { var str = ''; for (var i = 0; i < byteArray.length; i++) str += byteArray.charCodeAt(i) <= 0x7F ? byteArray.charCodeAt(i) === 0x25 ? "%25" : // % byteArray.substr(i, 1) : "%" + (byteArray.charCodeAt(i) & 0xFF).toString(16).toUpperCase(); return decodeURIComponent(str); }, byteArrayToUtf16 : function byteArrayToUtf16(byteArray) { var str = ''; for (var i = 0; i < byteArray.length / 2; i++) str += String.fromCharCode((byteArray.charCodeAt(i * 2) & 0xFF) + ((byteArray.charCodeAt(i * 2 + 1) & 0xFF) << 8)); return str; }, utf16ToByteArray : function utf16ToByteArray(str) { var byteArray = ""; for (var i = 0; i < str.length; i++) { byteArray += String.fromCharCode(str.charCodeAt(i) & 0xFF); byteArray += String.fromCharCode((str.charCodeAt(i) & 0xFF00) >> 8); }; return byteArray; }, ISO8601toDateTime : function ISO8601toDateTime(str) { var regexp = "([0-9]{4})(-([0-9]{2})(-([0-9]{2})" + "(T([0-9]{2}):([0-9]{2})(:([0-9]{2})(\.([0-9]+))?)?" + "(Z|(([-+])([0-9]{2}):([0-9]{2})))?)?)?)?"; var d = ("" + str).match(new RegExp(regexp)); if (!d) return null; var offset = 0; var date = new Date(d[1], 0, 1); if (d[3]) { date.setMonth(d[3] - 1); } if (d[5]) { date.setDate(d[5]); } if (d[7]) { date.setHours(d[7]); } if (d[8]) { date.setMinutes(d[8]); } if (d[10]) { date.setSeconds(d[10]); } if (d[12]) { date.setMilliseconds(Number("0." + d[12]) * 1000); } if (d[14]) { offset = (Number(d[16]) * 60) + Number(d[17]); offset *= ((d[15] == '-') ? 1 : -1); offset -= date.getTimezoneOffset(); var time = (Number(date) + (offset * 60 * 1000)); date.setTime(Number(time)); } return date; }, dateTimeToSOAPString : function dateTimeToSOAPString(aValue) { //'yyyy-mm-ddThh:nn:ss' return aValue.getFullYear() + '-' + RemObjects.UTIL.zeroPad(aValue.getMonth() + 1, 2) + '-' + RemObjects.UTIL.zeroPad(aValue.getDate(), 2) + 'T' + RemObjects.UTIL.zeroPad(aValue.getHours(), 2) + ':' + RemObjects.UTIL.zeroPad(aValue.getMinutes(), 2) + ':' + RemObjects.UTIL.zeroPad(aValue.getSeconds(), 2); }, decimalToString : function decimalToString(aDecimal) { //aDecimal - array [0..6] var sign = (aDecimal[6] & 0x80000000) != 0; var scale = (aDecimal[6] & 0xFF0000) >> 16; var pos = 31; var aDec = aDecimal.slice(); var aResult = []; var modres; var d; while ((aDec[0] != 0) || (aDec[1] != 0) || (aDec[2] != 0) || (aDec[3] != 0) || (aDec[4] != 0) || (aDec[5] != 0) || ((31 - pos) < scale)) { modres = 0; for (var i = 5; i >= 0; i--) { d = (modres << 16) | aDec[i]; modres = d % 10; aDec[i] = Math.floor(d / 10); }; aResult[pos] = modres.toString(10); pos--; if ((31 - pos) == scale) { aResult[pos] = "."; pos--; if ((aDec[0] == 0) && (aDec[1] == 0) && (aDec[2] == 0)) { aResult[pos] = '0'; pos--; }; }; }; if (pos == 31) return "0"; if (sign) { aResult[pos] = '-'; pos--; }; return aResult.join(""); }, stringToDecimal : function stringToDecimal(aString) { var mulres; var d; var aRes = [0, 0, 0, 0, 0, 0, 0]; var pos = 0; var scalepos = -1; var c; var n; for (var i = 1; i <= aString.length; i++) { mulres = 0; c = aString.substr(i - 1, 1); if (n = parseFloat(c)) { mulres = n } else if (c == "-") { aRes[6] = 0x80000000; continue; } else if (c == ".") { if (scalepos == -1) scalepos = pos; continue; } else continue; for (var j = 0; j < 6; j++) { d = aRes[j] * 10 + mulres; mulres = d >> 16; aRes[j] = d & 0xffff; }; pos++; }; if (scalepos != -1) { pos = pos - scalepos; aRes[6] = aRes[6] | (pos << 16); }; return aRes; }, toBase64 : function toBase64(aValue) { if (typeof(btoa) != 'undefined') { return btoa(aValue); } else { throw(new Error("Base64 encoding is not supported by your browser.")); //return $.base64Encode(aValue); }; }, fromBase64 : function fromBase64 (aValue) { if (typeof(atob) != 'undefined') { return atob(aValue.replace(/(\n|\r)+/g, "")); } else { throw(new Error("Base64 decoding is not supported by your browser.")); // return $.base64Decode(aValue); }; }, checkArgumentTypes : function checkArgumentTypes (args, types) { for (var i = 0; i < types.length; i++) { if (typeof(types[i]) == "string") { if (typeof(args[i]) != types[i]) return false; } else { if (!(args[i] instanceof types[i])) return false; }; }; return true; } }; RemObjects.SDK.Enum.MessageType = { mtMessage : 0, mtException : 1, mtEvent : 2, mtPoll : 0x80, mtPollResponse : 0x81 }; //RO.SDK implementation RemObjects.SDK.ROEventSink.prototype = new RemObjects.SDK.ROComplexType(); RemObjects.SDK.ROEventSink.prototype.constructor = RemObjects.SDK.ROEventSink; RemObjects.SDK.ROEventSink.prototype.readEvent = function readEvent(aMessage, aName) { for (var prop in this[aName]) { if ((typeof this[aName][prop]) != "function") { this[aName][prop].value = aMessage.read(prop, this[aName][prop].dataType); }; }; }; RemObjects.SDK.ROException.prototype = new Error(); RemObjects.SDK.ROEnumType.prototype = new RemObjects.SDK.ROComplexType(); RemObjects.SDK.ROEnumType.prototype.constructor = RemObjects.SDK.ROEnumType; RemObjects.SDK.ROEnumType.prototype.writeTo = function writeTo(aMessage) { aMessage.write("", "Integer", this.enumValues.indexOf(this.value)); }; RemObjects.SDK.ROEnumType.prototype.readFrom = function readFrom(aMessage) { this.value = this.enumValues[aMessage.read("", "Integer")]; }; RemObjects.SDK.ROEnumType.prototype.toObject = function toObject() { return this.value; }; RemObjects.SDK.ROEnumType.prototype.fromObject = function fromObject(aValue) { this.value = aValue; //todo: add check }; RemObjects.SDK.ROStructType.prototype = new RemObjects.SDK.ROComplexType(); RemObjects.SDK.ROStructType.prototype.constructor = RemObjects.SDK.ROStructType; RemObjects.SDK.ROStructType.prototype.writeTo = function writeTo(aMessage) { for (var prop in this) { if ((typeof this[prop]) != "function") { aMessage.write(prop, this[prop].dataType, this[prop].value); }; }; }; RemObjects.SDK.ROStructType.prototype.readFrom = function readFrom(aMessage) { for (var prop in this) { if ((typeof this[prop]) != "function") { this[prop].value = aMessage.read(prop, this[prop].dataType); }; }; }; RemObjects.SDK.ROStructType.prototype.toObject = function toObject(aStoreType) { var result = {}; for (var prop in this) { if ((typeof this[prop]) != "function") { if (this[prop].value instanceof RemObjects.SDK.ROComplexType) { result[prop] = this[prop].value.toObject(aStoreType); } else result[prop] = this[prop].value; }; }; if(aStoreType) result.__type = /function\s*(.*?)\(/.exec(this.constructor.toString())[1]; return result; }; RemObjects.SDK.ROStructType.prototype.fromObject = function fromObject(aValue) { for (var prop in this) { if ((typeof this[prop]) != "function") { //!!! if (RemObjects.SDK.RTTI[this[prop].dataType] && RemObjects.SDK.RTTI[this[prop].dataType].prototype instanceof RemObjects.SDK.ROComplexType) { this[prop].value = new RemObjects.SDK.RTTI[this[prop].dataType](); this[prop].value.fromObject(aValue[prop]); } else { if (this[prop].dataType == "DateTime") { this[prop].value = RemObjects.UTIL.ISO8601toDateTime(aValue[prop]); } else { this[prop].value = aValue[prop]; }; }; }; }; return this; }; RemObjects.SDK.ROArrayType.prototype = new RemObjects.SDK.ROComplexType(); RemObjects.SDK.ROArrayType.prototype.constructor = RemObjects.SDK.ROArrayType; RemObjects.SDK.ROArrayType.prototype.writeTo = function writeTo(aMessage) { for (var i=0; i= 0) { result += String.fromCharCode(b); }; return result; }; RemObjects.SDK.BinMessage.prototype.read = function read(valueName, valueType) { var value; var rttiType = RemObjects.SDK.RTTI[valueType]; if (rttiType && rttiType.prototype instanceof RemObjects.SDK.ROComplexType) { if (rttiType.prototype instanceof RemObjects.SDK.ROEnumType) { value = new rttiType(); value.readFrom(this); return value; }; if (!(this.parser.decodeInt(this.fResponseString.substr(this.fStreamPos++, 1), 8, false))) { // Not assigned return null; }; if (rttiType.prototype instanceof RemObjects.SDK.ROStructType) { var realType = this.read("", "AnsiString"); if (valueType !== realType) { value = new RemObjects.SDK.RTTI[realType](); } else { value = new rttiType(); }; value.readFrom(this); return value; } value = new rttiType(); if (value instanceof RemObjects.SDK.ROArrayType) { value.items.length = this.parser.decodeInt(this.fResponseString.substr(this.fStreamPos, 4), 32, false); this.fStreamPos += 4; }; value.readFrom(this); return value; } switch (valueType) { case "Decimal": var decimal = []; for (var i = 0; i < 6; i++) { decimal[i] = this.parser.decodeInt(this.fResponseString.substr(this.fStreamPos, 2), 16, false); this.fStreamPos += 2; }; decimal[6] = this.parser.decodeInt(this.fResponseString.substr(this.fStreamPos, 4), 32, false); this.fStreamPos += 4; value = parseFloat(RemObjects.UTIL.decimalToString(decimal)); break; case "Double": value = this.parser.decodeFloat(this.fResponseString.substr(this.fStreamPos, 8), 52, 11); this.fStreamPos += 8; this.fResponseObject[valueName] = value; break; case "DateTime": var utcValue = this.parser.decodeFloat(this.fResponseString.substr(this.fStreamPos, 8), 52, 11); utcValue = new Date(Math.round((utcValue - 25569.0) * 86400000)); value = new Date(utcValue.getUTCFullYear(), utcValue.getUTCMonth(), utcValue.getUTCDate(), utcValue.getUTCHours(), utcValue.getUTCMinutes(), utcValue.getUTCSeconds()); this.fStreamPos += 8; this.fResponseObject[valueName] = value; break; case "Boolean": value = !(this.parser.decodeInt(this.fResponseString.substr(this.fStreamPos, 4), 32, false) == 0); this.fStreamPos += 4; this.fResponseObject[valueName] = value; break; case "Integer": value = this.parser.decodeInt(this.fResponseString.substr(this.fStreamPos, 4), 32, true); this.fStreamPos += 4; this.fResponseObject[valueName] = value; break; case "Int64": value = this.parser.decodeInt(this.fResponseString.substr(this.fStreamPos, 6), 48, true); this.fStreamPos += 8; this.fResponseObject[valueName] = value; break; case "Currency": value = this.parser.decodeInt(this.fResponseString.substr(this.fStreamPos, 6), 48, true) / 10000; this.fStreamPos += 8; this.fResponseObject[valueName] = value; break; case "Xml": case "Utf8String": var len = this.parser.decodeInt(this.fResponseString.substr(this.fStreamPos, 4), 32, false); this.fStreamPos += 4; value = RemObjects.UTIL.byteArrayToStr(this.fResponseString.substr(this.fStreamPos, len)); this.fStreamPos += len; break; case "WideString": var len = this.parser.decodeInt(this.fResponseString.substr(this.fStreamPos, 4), 32, false); this.fStreamPos += 4; value = RemObjects.UTIL.byteArrayToUtf16(this.fResponseString.substr(this.fStreamPos, len * 2)); this.fStreamPos += len * 2; break; case "Binary": var isAssigned = this.parser.decodeInt(this.fResponseString.substr(this.fStreamPos, 1), 8, false); this.fStreamPos += 1; if (isAssigned == 0) { value = null; break; }; var len = this.parser.decodeInt(this.fResponseString.substr(this.fStreamPos, 4), 32, false); this.fStreamPos += 4; value = ""; for (var i = this.fStreamPos; i < this.fStreamPos + len; i++) { value += String.fromCharCode(this.fResponseString.charCodeAt(i) & 0xFF); }; this.fStreamPos += len; break; case "AnsiString": var len = this.parser.decodeInt(this.fResponseString.substr(this.fStreamPos, 4), 32, false); this.fStreamPos += 4; value = this.fResponseString.substr(this.fStreamPos, len); this.fStreamPos += len; break; case "Guid": value = RemObjects.UTIL.byteArrayToGuid(this.fResponseString.substr(this.fStreamPos, 16)); this.fStreamPos += 16; break; case "Variant": value = this.readVariant(); break; default: if (RemObjects.SDK.RTTI[valueType] && (typeof(RemObjects.SDK.RTTI[valueType]) == "function") && (RemObjects.SDK.RTTI[valueType].prototype instanceof RemObjects.SDK.ROComplexType)) { value = new RemObjects.SDK.RTTI[valueType](); value.readFrom(this); } else { this.fResponseObject.error = {message : "BinMessage.read: Unknown type of " + valueName + " - " + valueType}; throw new Error(this.fResponseObject.error.message); }; }; return value; }; RemObjects.SDK.BinMessage.prototype.readVariant = function readVariant() { var code = this.parser.decodeInt(this.fResponseString.substr(this.fStreamPos, 4), 32, false); this.fStreamPos += 4; var result; if ((code & 0x2000) == 0x2000) { if (code == 0x2011) { //varBinary var binLength = this.read("", "Integer"); result = this.fResponseString.substr(this.fStreamPos, binLength); this.fStreamPos += binLength; } else {//varArray //var itemCode = code & 0xFFF; result = []; var lowBound = this.read("", "Integer"); var highBound = this.read("", "Integer"); for (var i = lowBound; i <= highBound; i++) result[i] = this.readVariant(); }; return result; }; switch(code) { case 0x000A: //varError case 0x0000: return undefined; //varEmpty case 0x0001: return null; //varNull case 0x0002: //varInt16 result = this.parser.decodeInt(this.fResponseString.substr(this.fStreamPos, 2), 16, true); this.fStreamPos += 2; return result; case 0x0003: //varInt32 result = this.parser.decodeInt(this.fResponseString.substr(this.fStreamPos, 4), 32, true); this.fStreamPos += 4; return result; case 0x0004: //varSingle result = this.parser.decodeFloat(this.fResponseString.substr(this.fStreamPos, 4), 23, 8); this.fStreamPos += 4; return result; case 0x0005: return this.read("", "Double");//varDouble case 0x0006: return this.read("", "Currency");//varCurrency case 0x0007: return this.read("", "DateTime");//varDateTime //varDispatch = 0x0009 case 0x000B: return this.read("", "Boolean");//varBoolean //varVariant = 0x000C //varUnknown = 0x000D case 0x000E: return this.read("", "Decimal");//varDecimal case 0x0010: //varInt8 result = this.parser.decodeInt(this.fResponseString.substr(this.fStreamPos, 1), 8, true); this.fStreamPos += 1; return result; case 0x0011: //varByte result = this.parser.decodeInt(this.fResponseString.substr(this.fStreamPos, 1), 8, false); this.fStreamPos += 1; return result; case 0x0012: //varWord result = this.parser.decodeInt(this.fResponseString.substr(this.fStreamPos, 2), 16, false); this.fStreamPos += 2; return result; case 0x0013: //varLongWord result = this.parser.decodeInt(this.fResponseString.substr(this.fStreamPos, 4), 32, false); this.fStreamPos += 4; return result; case 0x0014: //varInt64 result = this.parser.decodeInt(this.fResponseString.substr(this.fStreamPos, 8), 48, true); this.fStreamPos += 8; return result; case 0x0072: return this.read("", "Guid");//varGuid case 0x0100: return this.read("", "AnsiString");//varDelphiString case 0x0008: //varOleStr case 0x0102: return this.read("", "Utf8String");//varDelphiUtfString default : throw new Error("readVariant: unknown varCode 0x" + code.toString(16)); }; }; RemObjects.SDK.BinMessage.prototype.requestStream = function requestStream() { return this.fRequestObject; }; RemObjects.SDK.BinMessage.prototype.setResponseStream = function setResponseStream(aResponse) { this.fResponseString = aResponse; var header = new RemObjects.SDK.BinHeader(); header.readFrom(this.fResponseString.substr(0, 28)); this.fStreamPos = 28; //skip header if (!header.isValidHeader()) { this.fResponseObject.error = {message : "Invalid response: unsupported binary message signature"}; throw new Error(this.fResponseObject.error.message); }; if (header.getCompressed()) { this.fResponseString = this.readCompressed(); this.fStreamPos = 0; //this.fResponseObject.error = {message : "Invalid response: compression is not supported for binary message"}; //throw new Error(this.fResponseObject.error.message); }; switch (header.getMessageType()) { case RemObjects.SDK.Enum.MessageType.mtMessage : var value = this.parser.decodeInt(this.fResponseString.substr(this.fStreamPos, 4), 32, false); this.fStreamPos += 4 + value; //skip service name value = this.parser.decodeInt(this.fResponseString.substr(this.fStreamPos, 4), 32, false); this.fStreamPos += 4 + value; //skip method name break; case RemObjects.SDK.Enum.MessageType.mtException : var value = this.parser.decodeInt(this.fResponseString.substr(this.fStreamPos, 4), 32, false); var exceptionClass = this.fResponseString.substr(this.fStreamPos + 4, value); this.fStreamPos += 4 + value; value = this.parser.decodeInt(this.fResponseString.substr(this.fStreamPos, 4), 32, false); var exceptionMessage = this.fResponseString.substr(this.fStreamPos + 4, value); this.fStreamPos += 4 + value; //skip method name this.fResponseObject.error = {message : exceptionClass + ":\n" + exceptionMessage}; var __e = new Error(exceptionMessage); __e.name = exceptionClass; throw __e; break; case RemObjects.SDK.Enum.MessageType.mtPollResponse : case RemObjects.SDK.Enum.MessageType.mtEvent : break; default: throw new Error("Unsupported binary message type - 0x" + header.getMessageType().toString(16)); }; }; RemObjects.SDK.JSONMessage.prototype = new RemObjects.SDK.Message(); RemObjects.SDK.JSONMessage.prototype.constructor = RemObjects.SDK.JSONMessage; RemObjects.SDK.JSONMessage.prototype.initialize = function initialize(aServiceName, aMethodName, aMessageType) { this.fRequestObject.id = "{" + this.fClientID + "}"; this.fRequestObject.method = aServiceName + "." + aMethodName; this.fRequestObject.params = {}; if (aMessageType) this.fRequestObject.type = aMessageType; }; RemObjects.SDK.JSONMessage.prototype.finalize = function finalize() { }; RemObjects.SDK.JSONMessage.prototype.write = function write(aName, aType, aValue) { if (aValue instanceof RemObjects.SDK.ROComplexType) { this.fRequestObject.params[aName] = aValue.toObject(true); } else if (aValue instanceof Date) { this.fRequestObject.params[aName] = RemObjects.UTIL.dateTimeToSOAPString(aValue); } else if (aType == "Binary") { this.fRequestObject.params[aName] = RemObjects.UTIL.toBase64(aValue); } else { this.fRequestObject.params[aName] = aValue; }; }; RemObjects.SDK.JSONMessage.prototype.read = function read(aName, aType) { if (this.fResponseObject.result == undefined) { throw new Error("JSONMessage.read: result property is missing:\n" + RemObjects.UTIL.toJSON(this.fResponseObject)); }; if (this.fResponseObject.result[aName] == undefined) { throw new Error("JSONMessage.read error:\n" + aName + ":" + aType + " is missing."); }; var result; aType = this.fResponseObject.result[aName].__type || aType; if (RemObjects.SDK.RTTI[aType] && RemObjects.SDK.RTTI[aType].prototype instanceof RemObjects.SDK.ROComplexType) { result = new RemObjects.SDK.RTTI[aType](); if (RemObjects.SDK.RTTI[aType].prototype instanceof RemObjects.SDK.ROEnumType) { result.value = this.fResponseObject.result[aName]; } else { result.fromObject(this.fResponseObject.result[aName]); }; } else if ((aType == "DateTime") || ((aType == "Variant") && (RemObjects.UTIL.ISO8601toDateTime(this.fResponseObject.result[aName])))) { result = RemObjects.UTIL.ISO8601toDateTime(this.fResponseObject.result[aName]); } else { result = this.fResponseObject.result[aName]; }; return result; }; RemObjects.SDK.JSONMessage.prototype.requestStream = function requestStream() { return RemObjects.UTIL.toJSON(this.fRequestObject); }; RemObjects.SDK.JSONMessage.prototype.setResponseStream = function setResponseStream(aResponse) { try { this.fResponseObject = RemObjects.UTIL.parseJSON(aResponse); } catch (e) { throw new Error("JSONMessage.setResponseStream:\n JSON parsing error: " + e.message + "\nServer response:\n" + aResponse); }; if (this.fResponseObject.error) { var __e; __e = new Error(this.fResponseObject.error.message); if (this.fResponseObject.error.name == "ROJSONException") { __e.name = this.fResponseObject.error.roexception.type; } else { __e.name = this.fResponseObject.error.name; }; throw __e; }; if (!this.fResponseObject.result) { this.fResponseObject.result = this.fResponseObject.params; }; }; RemObjects.SDK.EventReceiver.prototype.addHandler = function addHandler(anEventName, aCallback) { this.fHandlers[anEventName] = aCallback; }; RemObjects.SDK.EventReceiver.prototype.setActive = function setActive(aValue) { this.fActive = aValue; if (this.fActive) { var that = this; this.fInterval = setInterval(function () {that.intPollServer();}, this.fTimeout); } else { clearInterval(this.fInterval); }; }; RemObjects.SDK.EventReceiver.prototype.getActive = function getActive() { return this.fActive; }; RemObjects.SDK.EventReceiver.prototype.getTimeout = function getTimeout() { return this.fTimeout; }; RemObjects.SDK.EventReceiver.prototype.setTimeout = function setTimeout(aValue) { this.fTimeout = aValue; if (this.fActive) { this.setActive(false); this.setActive(true); }; }; RemObjects.SDK.EventReceiver.prototype.intPollServer = function intPollServer() { try { var that = this; var msg = this.fMessage.clone(); msg.initialize(this.fServiceName, "poll", RemObjects.SDK.Enum.MessageType.mtPoll); msg.write("MaxMessageCount", "Integer", 10); if (msg instanceof RemObjects.SDK.BinMessage) { msg.write("", "Guid", msg.getClientID()); }; msg.finalize(); this.fChannel.dispatch(msg, function (__message) { var msgCount = __message.read("MessageCount", "Integer"); var msgLeft = __message.read("MessagesLeft", "Integer"); for (var i = 0; i < msgCount; i++) { var events = __message.clone(); events.initialize("", "", RemObjects.SDK.Enum.MessageType.mtPollResponse); var eventsStream = __message.read("Message_" + i, "Binary"); if (__message instanceof RemObjects.SDK.JSONMessage) { eventsStream = RemObjects.UTIL.fromBase64(eventsStream); }; events.setResponseStream(eventsStream); var sinkName = events.read("InterfaceName", "AnsiString"); var eventName = events.read("MessageName", "AnsiString"); if (RemObjects.SDK.RTTI[sinkName] && RemObjects.SDK.RTTI[sinkName].prototype instanceof RemObjects.SDK.ROComplexType) { var sink = new RemObjects.SDK.RTTI[sinkName](); sink.readEvent(events, eventName); if (that.fHandlers[eventName]) { that.fHandlers[eventName](RemObjects.SDK.ROStructType.prototype.toObject.call(sink[eventName])); }; } else { throw new Error("EventReceiver.intPollServer: unknown event sink"); }; }; }, RemObjects.UTIL.showError); } catch (e) { RemObjects.UTIL.showError(msg, e); }; }; function TitaniumAjaxWrapper(url) { this.updating = false; this.urlCall = url; }; TitaniumAjaxWrapper.prototype.post = function post(passData, isBinary, onSuccessFunction, onErrorFunction) { if (this.updating) { return false; }; this.AJAX = null; this.AJAX = Ti.Network.createHTTPClient({ onload: function(e) { Ti.API.info("onload"); if (isBinary) { onSuccessFunction(this.responseData, 200); } else { onSuccessFunction(this.responseText, 200); }; }, onerror: function(e) { Ti.API.info('XHR Error ' + e.error); }, timeout:5000 }); this.updating = new Date(); var uri = this.urlCall + '?' + this.updating.getTime(); Ti.API.info("TitaniumAjaxWrapper " + uri); this.AJAX.open("POST", uri); // if (isBinary) { // this.AJAX.setRequestHeader('Content-Type','multipart/form-data'); // } this.AJAX.send(passData); }; function AjaxWrapper(url) { this.updating = false; this.urlCall = url; }; AjaxWrapper.prototype.abort = function abort() { if (this.updating) { this.updating = false; this.AJAX.abort(); this.AJAX = null; }; }; AjaxWrapper.prototype.post = function post(passData, isBinary, onSuccessFunction, onErrorFunction) { function isIE10Up() { if (!navigator) return false; // Project Spartan is not yet supported // This code detects only IE 10 and IE 11 return (navigator.userAgent.indexOf("MSIE 10") != -1) || (!!navigator.userAgent.match(/Trident\/7\./)); }; if (this.updating) { return false; }; this.AJAX = null; try { this.AJAX = new XMLHttpRequest(); } catch (e) { // Internet Explorer Browsers try { this.AJAX = new ActiveXObject("Msxml2.XMLHTTP"); } catch (e) { try { this.AJAX = new ActiveXObject("Microsoft.XMLHTTP"); } catch (e) { throw new Error("Your browser doesn't support XMLHttpRequest object"); }; }; }; if (this.AJAX == null) { return false; } else { this.onSuccess = onSuccessFunction || function () { }; this.onError = onErrorFunction || function () { }; var that = this; this.AJAX.onreadystatechange = function onreadystatechange() { if (that.AJAX.readyState == 4) { that.updating = false; if (that.AJAX.status == 200) { if (isIE10Up() && typeof(that.AJAX.response) != "string") { var response = ""; var arr = new Uint8Array(that.AJAX.response); for (var i = 0; i < arr.length; i++) response += String.fromCharCode(arr[i]); that.onSuccess(response, that.AJAX.status/*, that.AJAX.responseXML*/); } else { that.onSuccess(that.AJAX.responseText, that.AJAX.status, that.AJAX.responseXML); }; } else { that.onError(that.AJAX.responseText, that.AJAX.status, that.AJAX.responseXML); }; that.AJAX = null; }; }; this.updating = new Date(); var uri = this.urlCall + '?' + this.updating.getTime(); this.AJAX.open("POST", uri, true); //this.AJAX.setRequestHeader("Content-Length", passData.length); if (isBinary == true) { if (this.AJAX.overrideMimeType) this.AJAX.overrideMimeType('text/plain; charset=x-user-defined'); this.AJAX.setRequestHeader("Content-type", "application/octet-stream"); if (this.AJAX.sendAsBinary) { this.AJAX.sendAsBinary(passData); } else { var len = passData.length; var data = new Uint8Array(len); for (var i=0; i> 3 ) - 1; do for( var byteValue = b.buffer[ ++curByte ], startBit = precisionBits % 8 || 8, mask = 1 << startBit; mask >>= 1; ( byteValue & mask ) && ( significand += 1 / divisor ), divisor *= 2 ); while( precisionBits -= startBit ); return exponent == ( bias << 1 ) + 1 ? significand ? NaN : signal ? -Infinity : +Infinity : ( 1 + signal * -2 ) * ( exponent || significand ? !exponent ? Math.pow( 2, -bias + 1 ) * significand : Math.pow( 2, exponent - bias ) * ( 1 + significand ) : 0 ); }; BinaryParser.prototype.encodeFloat = function encodeFloat( data, precisionBits, exponentBits ){ var bias = Math.pow( 2, exponentBits - 1 ) - 1, minExp = -bias + 1, maxExp = bias, minUnnormExp = minExp - precisionBits, status = isNaN( n = parseFloat( data ) ) || n == -Infinity || n == +Infinity ? n : 0, exp = 0, len = 2 * bias + 1 + precisionBits + 3, bin = new Array( len ), signal = ( n = status !== 0 ? 0 : n ) < 0, n = Math.abs( n ), intPart = Math.floor( n ), floatPart = n - intPart, i, lastBit, rounded, j, result; for( i = len; i; bin[--i] = 0 ); for( i = bias + 2; intPart && i; bin[--i] = intPart % 2, intPart = Math.floor( intPart / 2 ) ); for( i = bias + 1; floatPart > 0 && i; ( bin[++i] = ( ( floatPart *= 2 ) >= 1 ) - 0 ) && --floatPart ); for( i = -1; ++i < len && !bin[i]; ); if( bin[( lastBit = precisionBits - 1 + ( i = ( exp = bias + 1 - i ) >= minExp && exp <= maxExp ? i + 1 : bias + 1 - ( exp = minExp - 1 ) ) ) + 1] ){ if( !( rounded = bin[lastBit] ) ) { for( j = lastBit + 2; !rounded && j < len; rounded = bin[j++] ) {}; }; for( j = lastBit + 1; rounded && --j >= 0; ( bin[j] = !bin[j] - 0 ) && ( rounded = 0 ) ){}; }; for( i = i - 2 < 0 ? -1 : i - 3; ++i < len && !bin[i]; ){}; if( ( exp = bias + 1 - i ) >= minExp && exp <= maxExp ) { ++i; } else if( exp < minExp ){ exp != bias + 1 - len && exp < minUnnormExp && this.warn( "encodeFloat::float underflow" ); i = bias + 1 - ( exp = minExp - 1 ); }; if( intPart || status !== 0 ){ this.warn( intPart ? "encodeFloat::float overflow" : "encodeFloat::" + status ); exp = maxExp + 1; i = bias + 2; if( status == -Infinity ) { signal = 1; } else if( isNaN( status ) ) bin[i] = 1; }; for( n = Math.abs( exp + bias ), j = exponentBits + 1, result = ""; --j; result = ( n % 2 ) + result, n = n >>= 1 ); for( n = 0, j = 0, i = ( result = ( signal ? "1" : "0" ) + result + bin.slice( i, i + precisionBits ).join( "" ) ).length, r = []; i; j = ( j + 1 ) % 8 ){ n += ( 1 << j ) * result.charAt( --i ); if( j == 7 ){ r[r.length] = String.fromCharCode( n ); n = 0; }; }; r[r.length] = n ? String.fromCharCode( n ) : ""; return ( this.bigEndian ? r.reverse() : r ).join( "" ); }; BinaryParser.prototype.encodeInt = function encodeInt(number, bits, signed){ var max = Math.pow(2, bits), r = []; (number >= max || number < -Math.pow(2, bits-1)) && this.warn("encodeInt::overflow") && (number = 0); number < 0 && (number += max); for(; number; r[r.length] = String.fromCharCode(number % 256), number = Math.floor(number / 256)); for(bits = -(-bits >> 3) - r.length; bits--; r[r.length] = "\0"); return (this.bigEndian ? r.reverse() : r).join(""); }; BinaryParser.prototype.decodeInt = function decodeInt(data, bits, signed){ var b = new this.Buffer(this.bigEndian, data), x = b.readBits(0, bits), max = Math.pow(2, bits); return signed && x >= max / 2 ? x - max : x; }; with({p: (BinaryParser.prototype.Buffer = function Buffer(bigEndian, buffer){ this.bigEndian = bigEndian || 0, this.buffer = [], this.setBuffer(buffer); }).prototype}){ p.readBits = function(start, length){ //shl fix: Henri Torgemane ~1996 (compressed by Jonas Raoni) function shl(a, b){ // for(++b; --b; a = ((a %= 0x7fffffff + 1) & 0x40000000) == 0x40000000 ? a * 2 : (a - 0x40000000) * 2 + 0x7fffffff + 1); for(++b; --b; a = ((a %= 0x7fffffffffff + 1) & 0x400000000000) == 0x400000000000 ? a * 2 : (a - 0x400000000000) * 2 + 0x7fffffffffff + 1); return a; }; if(start < 0 || length <= 0) return 0; this.checkBuffer(start + length); for(var offsetLeft, offsetRight = start % 8, curByte = this.buffer.length - (start >> 3) - 1, lastByte = this.buffer.length + (-(start + length) >> 3), diff = curByte - lastByte, sum = ((this.buffer[ curByte ] >> offsetRight) & ((1 << (diff ? 8 - offsetRight : length)) - 1)) + (diff && (offsetLeft = (start + length) % 8) ? (this.buffer[ lastByte++ ] & ((1 << offsetLeft) - 1)) << (diff-- << 3) - offsetRight : 0); diff; sum += shl(this.buffer[ lastByte++ ], (diff-- << 3) - offsetRight) ); return sum; }; p.setBuffer = function setBuffer(data){ if(data){ for(var l, i = l = data.length, b = this.buffer = new Array(l); i; b[l - i] = data.charCodeAt(--i) & 0xFF); // for(var l, i = l = data.length, b = this.buffer = new Array(l); i; b[l - i] = data.charCodeAt(--i)); this.bigEndian && b.reverse(); }; }; p.hasNeededBits = function hasNeededBits(neededBits){ return this.buffer.length >= -(-neededBits >> 3); }; p.checkBuffer = function checkBuffer(neededBits){ if(!this.hasNeededBits(neededBits)) { throw new Error("checkBuffer::missing bytes");}; }; }; /* DEFLATE implementation based on http://www.codeproject.com/Articles/26980/Binary-Formats-in-JavaScript-Base64-Deflate-and-UT Copyright (c) 2008 notmasteryet Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ RemObjects.ZLIB = { staticCodes:null, staticDistances:null, encodedLengthStart:new Array(3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258), encodedLengthAdditionalBits:new Array(0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0), encodedDistanceStart:new Array(1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577), encodedDistanceAdditionalBits:new Array(0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13), clenMap:new Array(16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15), buildCodes:function buildCodes(lengths) { var codes = new Array(lengths.length); var maxBits = lengths[0]; for (var i = 1; i < lengths.length; i++) { if (maxBits < lengths[i]) maxBits = lengths[i]; }; var bitLengthsCount = new Array(maxBits + 1); for (var i = 0; i <= maxBits; i++) bitLengthsCount[i] = 0; for (var i = 0; i < lengths.length; i++) { ++bitLengthsCount[lengths[i]]; }; var nextCode = new Array(maxBits + 1); var code = 0; bitLengthsCount[0] = 0; for (var bits = 1; bits <= maxBits; bits++) { code = (code + bitLengthsCount[bits - 1]) << 1; nextCode[bits] = code; }; for (var n = 0; n < codes.length; n++) { var len = lengths[n]; if (len != 0) { codes[n] = nextCode[len]; nextCode[len]++; }; }; return codes; }, initializeStaticTrees:function initializeStaticTrees() { var codes = new Array(288); var codesLengths = new Array(288); for (var i = 0; i <= 143; i++) { codes[i] = 0x0030 + i; codesLengths[i] = 8; }; for (var i = 144; i <= 255; i++) { codes[i] = 0x0190 + i - 144; codesLengths[i] = 9; }; for (var i = 256; i <= 279; i++) { codes[i] = 0x0000 + i - 256; codesLengths[i] = 7; }; for (var i = 280; i <= 287; i++) { codes[i] = 0x00C0 + i - 280; codesLengths[i] = 8; }; RemObjects.ZLIB.staticCodes = RemObjects.ZLIB.buildTree(codes, codesLengths); var distances = new Array(32); var distancesLengths = new Array(32); for (var i = 0; i <= 31; i++) { distances[i] = i; distancesLengths[i] = 5; }; RemObjects.ZLIB.staticDistances = RemObjects.ZLIB.buildTree(distances, distancesLengths); }, buildTree:function buildTree(codes, lengths) { var nonEmptyCodes = new Array(0); for (var i = 0; i < codes.length; ++i) { if (lengths[i] > 0) { var code = new Object(); code.bits = codes[i]; code.length = lengths[i]; code.index = i; nonEmptyCodes.push(code); }; }; return RemObjects.ZLIB.buildTreeBranch(nonEmptyCodes, 0, 0); }, buildTreeBranch: function buildTreeBranch(codes, prefix, prefixLength) { if (codes.length == 0) return null; var zeros = new Array(0); var ones = new Array(0); var branch = new Object(); branch.isLeaf = false; for (var i = 0; i < codes.length; ++i) { if (codes[i].length == prefixLength && codes[i].bits == prefix) { branch.isLeaf = true; branch.index = codes[i].index; break; } else { var nextBit = ((codes[i].bits >> (codes[i].length - prefixLength - 1)) & 1) > 0; if (nextBit) { ones.push(codes[i]); } else { zeros.push(codes[i]); }; }; }; if (!branch.isLeaf) { branch.zero = RemObjects.ZLIB.buildTreeBranch(zeros, (prefix << 1), prefixLength + 1); branch.one = RemObjects.ZLIB.buildTreeBranch(ones, (prefix << 1) | 1, prefixLength + 1); }; return branch; }, readDynamicTrees:function readDynamicTrees(bitReader) { var hlit = bitReader.readLSB(5) + 257; var hdist = bitReader.readLSB(5) + 1; var hclen = bitReader.readLSB(4) + 4; var clen = new Array(19); for (var i = 0; i < clen.length; ++i) clen[i] = 0; for (var i = 0; i < hclen; ++i) clen[RemObjects.ZLIB.clenMap[i]] = bitReader.readLSB(3); var clenCodes = RemObjects.ZLIB.buildCodes(clen); var clenTree = RemObjects.ZLIB.buildTree(clenCodes, clen); var lengthsSequence = new Array(0); while (lengthsSequence.length < hlit + hdist) { var p = clenTree; while (!p.isLeaf) { p = bitReader.readBit() ? p.one : p.zero; }; var code = p.index; if (code <= 15) { lengthsSequence.push(code); } else if (code == 16) { var repeat = bitReader.readLSB(2) + 3; for (var q = 0; q < repeat; ++q) lengthsSequence.push(lengthsSequence[lengthsSequence.length - 1]); } else if (code == 17) { var repeat = bitReader.readLSB(3) + 3; for (var q = 0; q < repeat; ++q) lengthsSequence.push(0); } else if (code == 18) { var repeat = bitReader.readLSB(7) + 11; for (var q = 0; q < repeat; ++q) lengthsSequence.push(0); }; }; var codesLengths = lengthsSequence.slice(0, hlit); var codes = RemObjects.ZLIB.buildCodes(codesLengths); var distancesLengths = lengthsSequence.slice(hlit, hlit + hdist); var distances = RemObjects.ZLIB.buildCodes(distancesLengths); var result = new Object(); result.codesTree = RemObjects.ZLIB.buildTree(codes, codesLengths); result.distancesTree = RemObjects.ZLIB.buildTree(distances, distancesLengths); return result; }, BitReader:function BitReader(reader) { this.bitsLength = 0; this.bits = 0; this.reader = reader; this.readBit = function () { if (this.bitsLength == 0) { var nextByte = this.reader.readByte(); if (nextByte < 0) throw new "Unexpected end of stream"; this.bits = nextByte; this.bitsLength = 8; }; var bit = (this.bits & 1) != 0; this.bits >>= 1; --this.bitsLength; return bit; }; this.align = function () { this.bitsLength = 0; }; this.readLSB = function (length) { var data = 0; for (var i = 0; i < length; ++i) { if (this.readBit()) data |= 1 << i; }; return data; }; this.readMSB = function (length) { var data = 0; for (var i = 0; i < length; ++i) { if (this.readBit()) data = (data << 1) | 1; else data <<= 1; }; return data; }; }, Inflator:function Inflator(reader) { this.reader = reader; this.bitReader = new RemObjects.ZLIB.BitReader(reader); this.buffer = new Array(0); this.bufferPosition = 0; this.state = 0; this.blockFinal = false; this.readByte = function () { while (this.bufferPosition >= this.buffer.length) { var item = this.decodeItem(); if (item == null) return -1; switch (item.itemType) { case 0: this.buffer = this.buffer.concat(item.array); break; case 2: this.buffer.push(item.symbol); break; case 3: var j = this.buffer.length - item.distance; for (var i = 0; i < item.length; i++) { this.buffer.push(this.buffer[j++]); }; break; }; }; var symbol = this.buffer[this.bufferPosition++]; if (this.bufferPosition > 0xC000) { var shift = this.buffer.length - 0x8000; if (shift > this.bufferPosition) shift = this.bufferPosition; this.buffer.splice(0, shift); this.bufferPosition -= shift; }; return symbol; }; this.decodeItem = function () { if (this.state == 2) return null; var item; if (this.state == 0) { this.blockFinal = this.bitReader.readBit(); var blockType = this.bitReader.readLSB(2); switch (blockType) { case 0: this.bitReader.align(); var len = this.bitReader.readLSB(16); var nlen = this.bitReader.readLSB(16); if ((len & ~nlen) != len) throw "Invalid block type 0 length"; item = new Object(); item.itemType = 0; item.array = new Array(len); for (var i = 0; i < len; ++i) { var nextByte = this.reader.readByte(); if (nextByte < 0) throw "Uncomplete block"; item.array[i] = nextByte; } if (this.blockFinal) this.state = 2; return item; case 1: this.codesTree = RemObjects.ZLIB.staticCodes; this.distancesTree = RemObjects.ZLIB.staticDistances; this.state = 1; break; case 2: var dynamicTrees = RemObjects.ZLIB.readDynamicTrees(this.bitReader); this.codesTree = dynamicTrees.codesTree; this.distancesTree = dynamicTrees.distancesTree; this.state = 1; break; default: throw new "Invalid block type (3)"; }; }; item = new Object(); var p = this.codesTree; while (!p.isLeaf) { p = this.bitReader.readBit() ? p.one : p.zero; }; if (p.index < 256) { item.itemType = 2; item.symbol = p.index; } else if (p.index > 256) { var lengthCode = p.index; if (lengthCode > 285) throw new "Invalid length code"; var length = RemObjects.ZLIB.encodedLengthStart[lengthCode - 257]; if (RemObjects.ZLIB.encodedLengthAdditionalBits[lengthCode - 257] > 0) { length += this.bitReader.readLSB(RemObjects.ZLIB.encodedLengthAdditionalBits[lengthCode - 257]); }; p = this.distancesTree; while (!p.isLeaf) { p = this.bitReader.readBit() ? p.one : p.zero; }; var distanceCode = p.index; var distance = RemObjects.ZLIB.encodedDistanceStart[distanceCode]; if (RemObjects.ZLIB.encodedDistanceAdditionalBits[distanceCode] > 0) { distance += this.bitReader.readLSB(RemObjects.ZLIB.encodedDistanceAdditionalBits[distanceCode]); }; item.itemType = 3; item.distance = distance; item.length = length; } else { item.itemType = 1; this.state = this.blockFinal ? 2 : 0; }; return item; }; } }; RemObjects.ZLIB.initializeStaticTrees();