| 1 | /** |
| 2 | * @fileoverview Script Compiler / Decompiler / Runner |
| 3 | * @author Ylian Saint-Hilaire |
| 4 | * @version v0.1.0e |
| 5 | */ |
| 6 | |
| 7 | // Core functions |
| 8 | script_functionTable1 = ['nop', 'jump', 'set', 'print', 'dialog', 'getitem', 'substr', 'indexof', 'split', 'join', 'length', 'jsonparse', 'jsonstr', 'add', 'substract', 'parseint', 'wsbatchenum', 'wsput', 'wscreate', 'wsdelete', 'wsexec', 'scriptspeed', 'wssubscribe', 'wsunsubscribe', 'readchar', 'signwithdummyca']; |
| 9 | |
| 10 | // functions of type ARG1 = func(ARG2, ARG3, ARG4, ARG5, ARG6) |
| 11 | script_functionTable2 = ['encodeuri', 'decodeuri', 'passwordcheck', 'atob', 'btoa', 'hex2str', 'str2hex', 'random', 'md5', 'maketoarray', 'readshort', 'readshortx', 'readint', 'readsint', 'readintx', 'shorttostr', 'shorttostrx', 'inttostr', 'inttostrx']; |
| 12 | |
| 13 | // functions of type ARG1 = func(ARG2, ARG3, ARG4, ARG5, ARG6) |
| 14 | script_functionTableX2 = [encodeURI, decodeURI, passwordcheck, window.atob.bind(window), window.btoa.bind(window), hex2rstr, rstr2hex, random, rstr_md5, MakeToArray, ReadShort, ReadShortX, ReadInt, ReadSInt, ReadIntX, ShortToStr, ShortToStrX, IntToStr, IntToStrX]; |
| 15 | |
| 16 | // Optional functions of type ARG1 = func(ARG2, ARG3, ARG4, ARG5, ARG6) |
| 17 | script_functionTable3 = ['pullsystemstatus', 'pulleventlog', 'pullauditlog', 'pullcertificates', 'pullwatchdog', 'pullsystemdefense', 'pullhardware', 'pulluserinfo', 'pullremoteaccess', 'highlightblock', 'disconnect', 'getsidstring', 'getsidbytearray']; |
| 18 | |
| 19 | // Optional functions of type ARG1 = func(ARG2, ARG3, ARG4, ARG5, ARG6) |
| 20 | script_functionTableX3 = [ |
| 21 | PullSystemStatus |
| 22 | , |
| 23 | // ###BEGIN###{EventLog} |
| 24 | PullEventLog |
| 25 | // ###END###{EventLog} |
| 26 | , |
| 27 | // ###BEGIN###{AuditLog} |
| 28 | PullAuditLog |
| 29 | // ###END###{AuditLog} |
| 30 | , |
| 31 | // ###BEGIN###{Certificates} |
| 32 | PullCertificates |
| 33 | // ###END###{Certificates} |
| 34 | , |
| 35 | // ###BEGIN###{AgentPresence} |
| 36 | PullWatchdog |
| 37 | // ###END###{AgentPresence} |
| 38 | , |
| 39 | // ###BEGIN###{SystemDefense} |
| 40 | PullSystemDefense |
| 41 | // ###END###{SystemDefense} |
| 42 | , |
| 43 | // ###BEGIN###{HardwareInfo} |
| 44 | PullHardware |
| 45 | // ###END###{HardwareInfo} |
| 46 | , |
| 47 | PullUserInfo |
| 48 | , |
| 49 | // ###BEGIN###{RemoteAccess} |
| 50 | PullRemoteAccess |
| 51 | // ###END###{RemoteAccess} |
| 52 | , |
| 53 | // ###BEGIN###{Scripting-Editor} |
| 54 | script_HighlightBlock |
| 55 | // ###END###{Scripting-Editor} |
| 56 | , |
| 57 | // ###BEGIN###{ComputerSelector} |
| 58 | disconnect |
| 59 | // ###END###{ComputerSelector} |
| 60 | , |
| 61 | function (runner, x) { return GetSidString(x); } |
| 62 | , |
| 63 | function (runner, x) { return GetSidByteArray(x); } |
| 64 | ]; |
| 65 | |
| 66 | // Setup the script state |
| 67 | function script_setup(binary, startvars) { |
| 68 | var obj = { startvars:startvars }; |
| 69 | if (binary.length < 6) { console.error('Invalid script length'); return null; } // Script must have at least 6 byte header |
| 70 | if (ReadInt(binary, 0) != 0x247D2945) { console.error('Invalid binary script'); return null; } // Check the script magic header |
| 71 | if (ReadShort(binary, 4) > 1) { console.error('Unsupported script version'); return null; } // Check the script version |
| 72 | obj.script = binary.substring(6); |
| 73 | // obj.onStep; |
| 74 | // obj.onConsole; |
| 75 | |
| 76 | // Reset the script to the start |
| 77 | obj.reset = function (stepspeed) { |
| 78 | obj.stop(); |
| 79 | obj.ip = 0; |
| 80 | obj.variables = startvars; |
| 81 | obj.state = 1; |
| 82 | } |
| 83 | |
| 84 | // Start the script |
| 85 | obj.start = function (stepspeed) { |
| 86 | obj.stop(); |
| 87 | obj.stepspeed = stepspeed; |
| 88 | if (stepspeed > 0) { obj.timer = setInterval(function () { obj.step() }, stepspeed); } |
| 89 | } |
| 90 | |
| 91 | // Stop the script |
| 92 | obj.stop = function () { |
| 93 | if (obj.timer != null) { clearInterval(obj.timer); } |
| 94 | obj.timer = null; |
| 95 | obj.stepspeed = 0; |
| 96 | } |
| 97 | |
| 98 | // function used to load and store variable values |
| 99 | obj.getVar = function (name) { if (name == undefined) return undefined; return obj.getVarEx(name.split('.'), obj.variables); } |
| 100 | obj.getVarEx = function (name, val) { try { if (name == undefined) return undefined; if (name.length == 0) return val; return obj.getVarEx(name.slice(1), val[name[0]]); } catch (e) { return null; } } |
| 101 | obj.setVar = function (name, val) { obj.setVarEx(name.split('.'), obj.variables, val); } |
| 102 | obj.setVarEx = function (name, vars, val) { if (name.length == 1) { vars[name[0]] = val; } else { obj.setVarEx(name.slice(1), vars[name[0]], val); } } |
| 103 | |
| 104 | // Run the script one step forward |
| 105 | obj.step = function () { |
| 106 | if (obj.state != 1) return; |
| 107 | if (obj.ip < obj.script.length) { |
| 108 | var cmdid = ReadShort(obj.script, obj.ip); |
| 109 | var cmdlen = ReadShort(obj.script, obj.ip + 2); |
| 110 | var argcount = ReadShort(obj.script, obj.ip + 4); |
| 111 | var argptr = obj.ip + 6; |
| 112 | var args = []; |
| 113 | |
| 114 | // Clear all temp variables (This is optional) |
| 115 | for (var i in obj.variables) { if (i.startsWith('__')) { delete obj.variables[i]; } } |
| 116 | |
| 117 | // Loop on each argument, moving forward by the argument length each time |
| 118 | for (var i = 0; i < argcount; i++) { |
| 119 | var arglen = ReadShort(obj.script, argptr); |
| 120 | var argval = obj.script.substring(argptr + 2, argptr + 2 + arglen); |
| 121 | var argtyp = argval.charCodeAt(0); |
| 122 | argval = argval.substring(1); |
| 123 | if (argtyp < 2) { |
| 124 | // Get the value and replace all {var} with variable values |
| 125 | while (argval.split("{").length > 1) { var t = argval.split("{").pop().split("}").shift(); argval = argval.replace('{' + t + '}', obj.getVar(t)); } |
| 126 | if (argtyp == 1) { obj.variables['__' + i] = decodeURI(argval); argval = '__' + i; } // If argtyp is 1, this is a literal. Store in temp variable. |
| 127 | args.push(argval); |
| 128 | } |
| 129 | if (argtyp == 2 || argtyp == 3) { |
| 130 | obj.variables['__' + i] = ReadSInt(argval, 0); |
| 131 | args.push('__' + i); |
| 132 | } |
| 133 | argptr += (2 + arglen); |
| 134 | } |
| 135 | |
| 136 | // Move instruction pointer forward by command size |
| 137 | obj.ip += cmdlen; |
| 138 | |
| 139 | // Get all variable values |
| 140 | var argsval = []; |
| 141 | for (var i = 0; i < 10; i++) { argsval.push(obj.getVar(args[i])); } |
| 142 | var storeInArg0; |
| 143 | |
| 144 | try { |
| 145 | if (cmdid < 10000) { |
| 146 | // Lets run the actual command |
| 147 | switch (cmdid) { |
| 148 | case 0: // nop |
| 149 | break; |
| 150 | case 1: // jump(label) or jump(label, a, compare, b) |
| 151 | if (argsval[2]) { |
| 152 | if ( |
| 153 | (argsval[2] == '<' && argsval[1] < argsval[3]) || |
| 154 | (argsval[2] == '<=' && argsval[1] <= argsval[3]) || |
| 155 | (argsval[2] == '!=' && argsval[1] != argsval[3]) || |
| 156 | (argsval[2] == '=' && argsval[1] == argsval[3]) || |
| 157 | (argsval[2] == '>=' && argsval[1] >= argsval[3]) || |
| 158 | (argsval[2] == '>' && argsval[1] > argsval[3]) |
| 159 | ) { obj.ip = argsval[0]; } |
| 160 | } else { |
| 161 | obj.ip = argsval[0]; // Set the instruction pointer to the new location in the script |
| 162 | } |
| 163 | break; |
| 164 | case 2: // set(variable, value) |
| 165 | if (args[1] == undefined) delete obj.variables[args[0]]; else obj.setVar(args[0], argsval[1]); |
| 166 | break; |
| 167 | case 3: // print(message) |
| 168 | if (obj.onConsole) { obj.onConsole(obj.toString(argsval[0]), obj); } else { console.log(obj.toString(argsval[0])); } |
| 169 | // Q(obj.consoleid).value += () + '\n'); Q(obj.console).scrollTop = Q(obj.console).scrollHeight; |
| 170 | break; |
| 171 | case 4: // dialog(title, content, buttons) |
| 172 | obj.state = 2; |
| 173 | obj.dialog = true; |
| 174 | setDialogMode(11, argsval[0], argsval[2], obj.xxStepDialogOk, argsval[1], obj); |
| 175 | break; |
| 176 | case 5: // getitem(a, b, c) |
| 177 | for (var i in argsval[1]) { if (argsval[1][i][argsval[2]] == argsval[3]) { storeInArg0 = i; } }; |
| 178 | break; |
| 179 | case 6: // substr(variable_dest, variable_src, index, len) |
| 180 | storeInArg0 = argsval[1].substr(argsval[2], argsval[3]); |
| 181 | break; |
| 182 | case 7: // indexOf(variable_dest, variable_src, index, len) |
| 183 | storeInArg0 = argsval[1].indexOf(argsval[2]); |
| 184 | break; |
| 185 | case 8: // split(variable_dest, variable_src, separator) |
| 186 | storeInArg0 = argsval[1].split(argsval[2]); |
| 187 | break; |
| 188 | case 9: // join(variable_dest, variable_src, separator) |
| 189 | storeInArg0 = argsval[1].join(argsval[2]); |
| 190 | break; |
| 191 | case 10: // length(variable_dest, variable_src) |
| 192 | storeInArg0 = argsval[1].length; |
| 193 | break; |
| 194 | case 11: // jsonparse(variable_dest, json) |
| 195 | storeInArg0 = JSON.parse(argsval[1]); |
| 196 | break; |
| 197 | case 12: // jsonstr(variable_dest, variable_src) |
| 198 | storeInArg0 = JSON.stringify(argsval[1]); |
| 199 | break; |
| 200 | case 13: // add(variable_dest, variable_src, value) |
| 201 | storeInArg0 = (argsval[1] + argsval[2]); |
| 202 | break; |
| 203 | case 14: // substract(variable_dest, variable_src, value) |
| 204 | storeInArg0 = (argsval[1] - argsval[2]); |
| 205 | break; |
| 206 | case 15: // parseInt(variable_dest, variable_src) |
| 207 | storeInArg0 = parseInt(argsval[1]); |
| 208 | break; |
| 209 | case 16: // wsbatchenum(name, objectList) |
| 210 | obj.state = 2; |
| 211 | obj.amtstack.BatchEnum(argsval[0], argsval[1], obj.xxWsmanReturn, obj); |
| 212 | break; |
| 213 | case 17: // wsput(name, args) |
| 214 | obj.state = 2; |
| 215 | obj.amtstack.Put(argsval[0], argsval[1], obj.xxWsmanReturn, obj); |
| 216 | break; |
| 217 | case 18: // wscreate(name, args) |
| 218 | obj.state = 2; |
| 219 | obj.amtstack.Create(argsval[0], argsval[1], obj.xxWsmanReturn, obj); |
| 220 | break; |
| 221 | case 19: // wsdelete(name, args) |
| 222 | obj.state = 2; |
| 223 | obj.amtstack.Delete(argsval[0], argsval[1], obj.xxWsmanReturn, obj); |
| 224 | break; |
| 225 | case 20: // wsexec(name, method, args, selectors) |
| 226 | obj.state = 2; |
| 227 | obj.amtstack.Exec(argsval[0], argsval[1], argsval[2], obj.xxWsmanReturn, obj, 0, argsval[3]); |
| 228 | break; |
| 229 | case 21: // Script Speed |
| 230 | obj.stepspeed = argsval[0]; |
| 231 | if (obj.timer != null) { clearInterval(obj.timer); obj.timer = setInterval(function () { obj.step() }, obj.stepspeed); } |
| 232 | break; |
| 233 | case 22: // wssubscribe(name, delivery, url, selectors, opaque, user, pass) |
| 234 | obj.state = 2; |
| 235 | obj.amtstack.Subscribe(argsval[0], argsval[1], argsval[2], obj.xxWsmanReturn, obj, 0, argsval[3], argsval[4], argsval[5], argsval[6]); |
| 236 | break; |
| 237 | case 23: // wsunsubscribe(name, selectors) |
| 238 | obj.state = 2; |
| 239 | obj.amtstack.UnSubscribe(argsval[0], obj.xxWsmanReturn, obj, 0, argsval[1]); |
| 240 | break; |
| 241 | case 24: // readchar(str, pos) |
| 242 | console.log(argsval[1], argsval[2], argsval[1].charCodeAt(argsval[2])); |
| 243 | storeInArg0 = argsval[1].charCodeAt(argsval[2]); |
| 244 | break; |
| 245 | case 25: // signWithDummyCa |
| 246 | // ###BEGIN###{Certificates} |
| 247 | obj.state = 2; |
| 248 | // DERKey, xxCaPrivateKey, certattributes, issuerattributes |
| 249 | amtcert_signWithCaKey(argsval[0], null, argsval[1], { 'CN': 'Untrusted Root Certificate' }, obj.xxSignWithDummyCaReturn); |
| 250 | // ###END###{Certificates} |
| 251 | break; |
| 252 | default: { |
| 253 | obj.state = 9; |
| 254 | console.error("Script Error, unknown command: " + cmdid); |
| 255 | } |
| 256 | } |
| 257 | } else { |
| 258 | if (cmdid < 20000) { |
| 259 | // functions of type ARG1 = func(ARG2, ARG3, ARG4, ARG5, ARG6) |
| 260 | storeInArg0 = script_functionTableX2[cmdid - 10000](argsval[1], argsval[2], argsval[3], argsval[4], argsval[5], argsval[6]); |
| 261 | } else { |
| 262 | // Optional functions of type ARG1 = func(ARG2, ARG3, ARG4, ARG5, ARG6) |
| 263 | if (script_functionTableX3 && script_functionTableX3[cmdid - 20000]) { |
| 264 | storeInArg0 = script_functionTableX3[cmdid - 20000](obj, argsval[1], argsval[2], argsval[3], argsval[4], argsval[5], argsval[6]); // Note that optional calls start with "obj" as first argument. |
| 265 | } |
| 266 | } |
| 267 | } |
| 268 | |
| 269 | if (storeInArg0 != undefined) obj.setVar(args[0], storeInArg0); |
| 270 | } catch (e) { |
| 271 | if (typeof e == 'object') { e = e.message; } |
| 272 | obj.setVar('_exception', e); |
| 273 | } |
| 274 | } |
| 275 | |
| 276 | if (obj.state == 1 && obj.ip >= obj.script.length) { obj.state = 0; obj.stop(); } |
| 277 | if (obj.onStep) obj.onStep(obj); |
| 278 | return obj; |
| 279 | } |
| 280 | |
| 281 | obj.xxStepDialogOk = function (button) { |
| 282 | obj.variables['DialogSelect'] = button; |
| 283 | obj.state = 1; |
| 284 | obj.dialog = false; |
| 285 | if (obj.onStep) obj.onStep(obj); |
| 286 | } |
| 287 | |
| 288 | // ###BEGIN###{**ClosureAdvancedMode} |
| 289 | obj.xxWsmanReturnFix = function (x) { |
| 290 | if (!x || x == null) return; |
| 291 | if (x.Header) { x['Header'] = x.Header; delete x.Header; } |
| 292 | if (x.Body) { x['Body'] = x.Body; delete x.Body; } |
| 293 | if (x.Responses) { x['Responses'] = x.Responses; delete x.Responses; } |
| 294 | if (x.Response) { x['Response'] = x.Response; delete x.Response; } |
| 295 | if (x.ReturnValueStr) { x['ReturnValueStr'] = x.ReturnValueStr; delete x.ReturnValueStr; } |
| 296 | } |
| 297 | // ###END###{**ClosureAdvancedMode} |
| 298 | |
| 299 | obj.xxWsmanReturn = function (stack, name, responses, status) { |
| 300 | // ###BEGIN###{**ClosureAdvancedMode} |
| 301 | // This is required when Google Closure is used |
| 302 | if (responses) { |
| 303 | obj.xxWsmanReturnFix(responses); |
| 304 | for (var i in responses) { |
| 305 | obj.xxWsmanReturnFix(responses[i]); |
| 306 | for (var j in responses[i]) { obj.xxWsmanReturnFix(responses[i][j]); } |
| 307 | } |
| 308 | } |
| 309 | // ###END###{**ClosureAdvancedMode} |
| 310 | obj.setVar(name, responses); |
| 311 | obj.setVar('wsman_result', status); |
| 312 | obj.setVar('wsman_result_str', ((httpErrorTable[status]) ? (httpErrorTable[status]) : ('Error #' + status))); |
| 313 | obj.state = 1; |
| 314 | if (obj.onStep) obj.onStep(obj); |
| 315 | } |
| 316 | |
| 317 | // ###BEGIN###{Certificates} |
| 318 | obj.xxSignWithDummyCaReturn = function (cert) { |
| 319 | obj.setVar('signed_cert', btoa(_arrayBufferToString(cert))); |
| 320 | obj.state = 1; |
| 321 | if (obj.onStep) obj.onStep(obj); |
| 322 | } |
| 323 | // ###END###{Certificates} |
| 324 | |
| 325 | obj.toString = function (x) { if (typeof x == 'object') return JSON.stringify(x); return x; } |
| 326 | |
| 327 | obj.reset(); |
| 328 | return obj; |
| 329 | } |
| 330 | |
| 331 | // Argument types: 0 = Variable, 1 = String, 2 = Integer, 3 = Label |
| 332 | function script_compile(script, onmsg) { |
| 333 | var r = '', scriptlines = script.split('\n'), labels = {}, labelswap = [], swaps = []; |
| 334 | // Go thru each script line and encode it |
| 335 | for (var i in scriptlines) { |
| 336 | var scriptline = scriptlines[i]; |
| 337 | if (scriptline.startsWith('##SWAP ')) { var x = scriptline.split(' '); if (x.length == 3) { swaps[x[1]] = x[2]; } } // Add a swap instance |
| 338 | if (scriptline[0] == '#' || scriptline.length == 0) continue; // Skip comments & blank lines |
| 339 | for (var x in swaps) { scriptline = scriptline.split(x).join(swaps[x]); } // Apply all swaps |
| 340 | var keywords = scriptline.match(/"[^"]*"|[^\s"]+/g); |
| 341 | if (keywords.length == 0) continue; // Skip blank lines |
| 342 | if (scriptline[0] == ':') { labels[keywords[0].toUpperCase()] = r.length; continue; } // Mark a label position |
| 343 | var funcIndex = script_functionTable1.indexOf(keywords[0].toLowerCase()); |
| 344 | if (funcIndex == -1) { funcIndex = script_functionTable2.indexOf(keywords[0].toLowerCase()); if (funcIndex >= 0) funcIndex += 10000; } |
| 345 | if (funcIndex == -1) { funcIndex = script_functionTable3.indexOf(keywords[0].toLowerCase()); if (funcIndex >= 0) funcIndex += 20000; } // Optional methods |
| 346 | if (funcIndex == -1) { if (onmsg) { onmsg("Unabled to compile, unknown command: " + keywords[0]); } return ''; } |
| 347 | // Encode CommandId, CmdSize, ArgCount, Arg1Len, Arg1, Arg2Len, Arg2... |
| 348 | var cmd = ShortToStr(keywords.length - 1); |
| 349 | for (var j in keywords) { |
| 350 | if (j == 0) continue; |
| 351 | if (keywords[j][0] == ':') { |
| 352 | labelswap.push([keywords[j], r.length + cmd.length + 7]); // Add a label swap |
| 353 | cmd += ShortToStr(5) + String.fromCharCode(3) + IntToStr(0xFFFFFFFF); // Put an empty label |
| 354 | } else { |
| 355 | var argint = parseInt(keywords[j]); |
| 356 | if (argint == keywords[j]) { |
| 357 | cmd += ShortToStr(5) + String.fromCharCode(2) + IntToStr(argint); |
| 358 | } else { |
| 359 | if (keywords[j][0] == '"' && keywords[j][keywords[j].length - 1] == '"') { |
| 360 | cmd += ShortToStr(keywords[j].length - 1) + String.fromCharCode(1) + keywords[j].substring(1, keywords[j].length - 1); |
| 361 | } else { |
| 362 | cmd += ShortToStr(keywords[j].length + 1) + String.fromCharCode(0) + keywords[j]; |
| 363 | } |
| 364 | } |
| 365 | } |
| 366 | } |
| 367 | cmd = ShortToStr(funcIndex) + ShortToStr(cmd.length + 4) + cmd; |
| 368 | r += cmd; |
| 369 | } |
| 370 | // Perform all the needed label swaps |
| 371 | for (i in labelswap) { |
| 372 | var label = labelswap[i][0].toUpperCase(), position = labelswap[i][1], target = labels[label]; |
| 373 | if (target == undefined) { if (onmsg) { onmsg("Unabled to compile, unknown label: " + label); } return ''; } |
| 374 | r = r.substr(0, position) + IntToStr(target) + r.substr(position + 4); |
| 375 | } |
| 376 | return IntToStr(0x247D2945) + ShortToStr(1) + r; |
| 377 | } |
| 378 | |
| 379 | // Decompile the script, intended for debugging only |
| 380 | function script_decompile(binary, onecmd) { |
| 381 | var r = '', ptr = 6, labelcount = 0, labels = {}; |
| 382 | if (onecmd >= 0) { |
| 383 | ptr = onecmd; // If we are decompiling just one command, set the ptr to that command. |
| 384 | } else { |
| 385 | if (binary.length < 6) { return '# Invalid script length'; } |
| 386 | var magic = ReadInt(binary, 0); |
| 387 | var version = ReadShort(binary, 4); |
| 388 | if (magic != 0x247D2945) { return '# Invalid binary script: ' + magic; } |
| 389 | if (version != 1) { return '# Invalid script version'; } |
| 390 | } |
| 391 | // Loop on each command, moving forward by the command length each time. |
| 392 | while (ptr < binary.length) { |
| 393 | var cmdid = ReadShort(binary, ptr); |
| 394 | var cmdlen = ReadShort(binary, ptr + 2); |
| 395 | var argcount = ReadShort(binary, ptr + 4); |
| 396 | var argptr = ptr + 6; |
| 397 | var argstr = ''; |
| 398 | if (!(onecmd >= 0)) r += ":label" + (ptr - 6) + "\n"; |
| 399 | // Loop on each argument, moving forward by the argument length each time |
| 400 | for (var i = 0; i < argcount; i++) { |
| 401 | var arglen = ReadShort(binary, argptr); |
| 402 | var argval = binary.substring(argptr + 2, argptr + 2 + arglen); |
| 403 | var argtyp = argval.charCodeAt(0); |
| 404 | if (argtyp == 0) { argstr += ' ' + argval.substring(1); } // Variable |
| 405 | else if (argtyp == 1) { argstr += ' \"' + argval.substring(1) + '\"'; } // String |
| 406 | else if (argtyp == 2) { argstr += ' ' + ReadInt(argval, 1); } // Integer |
| 407 | else if (argtyp == 3) { // Label |
| 408 | var target = ReadInt(argval, 1); |
| 409 | var label = labels[target]; |
| 410 | if (!label) { label = ":label" + target; labels[label] = target; } |
| 411 | argstr += ' ' + label; |
| 412 | } |
| 413 | argptr += (2 + arglen); |
| 414 | } |
| 415 | // Go in the script function table to decode the function |
| 416 | if (cmdid < 10000) { |
| 417 | r += script_functionTable1[cmdid] + argstr + "\n"; |
| 418 | } else { |
| 419 | if (cmdid >= 20000) { |
| 420 | r += script_functionTable3[cmdid - 20000] + argstr + "\n"; // Optional methods |
| 421 | } else { |
| 422 | r += script_functionTable2[cmdid - 10000] + argstr + "\n"; |
| 423 | } |
| 424 | } |
| 425 | ptr += cmdlen; |
| 426 | if (onecmd >= 0) return r; // If we are decompiling just one command, exit now |
| 427 | } |
| 428 | // Remove all unused labels |
| 429 | var scriptlines = r.split('\n'); |
| 430 | r = ''; |
| 431 | for (var i in scriptlines) { |
| 432 | var line = scriptlines[i]; |
| 433 | if (line[0] != ':') { r += line + '\n'; } else { if (labels[line]) { r += line + '\n'; } } |
| 434 | } |
| 435 | return r; |
| 436 | } |