function StateMachine(worker, video, isGL) { this.table = [ { name: "RESET ", bits: 0, next0: START, next1: START, func: "reset" }, { name: "START ", bits: 1, next0: PIXELS, next1: CMD, func: "no_op" }, { name: "PIXELS ", bits: 1, next0: PIXFAN, next1: PIXLRU1, func: "no_op" }, { name: "PIXLRU1 ", bits: 1, next0: PIXELS, next1: PIXRPT1, func: "pixcodex" }, { name: "PIXLRU0 ", bits: 1, next0: PIXELS, next1: PIXRPT1, func: "pixcodex" }, { name: "PIXCODE1 ", bits: 1, next0: PIXRPT, next1: PIXRPT, func: "pixcodex" }, { name: "PIXCODE2 ", bits: 2, next0: PIXRPT, next1: PIXRPT, func: "pixcodex" }, { name: "PIXCODE3 ", bits: 3, next0: PIXRPT, next1: PIXRPT, func: "pixcodex" }, { name: "PIXGREY ", bits: 4, next0: PIXRPT, next1: PIXRPT, func: "pixgrey" }, { name: "PIXRGBR ", bits: 4, next0: PIXRGBG, next1: PIXRGBG, func: "pixrgbr" }, { name: "PIXRPT ", bits: 1, next0: PIXELS, next1: PIXRPT1, func: "no_op" }, { name: "PIXRPT1 ", bits: 1, next0: PIXDUP, next1: PIXRPTSTD1, func: "no_op" }, { name: "PIXRPTSTD1 ", bits: 3, next0: PIXELS, next1: PIXELS, func: "pixrptstd1" }, { name: "PIXRPTSTD2 ", bits: 3, next0: PIXELS, next1: PIXELS, func: "pixrptstd2" }, { name: "PIXRPTNSTD ", bits: 8, next0: PIXELS, next1: PIXELS, func: "pixrptnstd" }, { name: "CMD ", bits: 1, next0: CMD0, next1: MOVEXY0, func: "no_op" }, { name: "CMD0 ", bits: 1, next0: CMDX, next1: EXTCMD, func: "no_op" }, { name: "MOVEXY0 ", bits: 7, next0: MOVEXY1, next1: MOVEXY1, func: "movexy0" }, { name: "EXTCMD ", bits: 1, next0: BLKRPT, next1: EXTCMD1, func: "no_op" }, { name: "CMDX ", bits: 1, next0: MOVESHORTX, next1: MOVELONGX, func: "no_op" }, { name: "MOVESHORTX ", bits: 3, next0: START, next1: START, func: "moveshortx" }, { name: "MOVELONGX ", bits: 7, next0: START, next1: START, func: "movelongx" }, { name: "BLKRPT ", bits: 1, next0: BLKDUP, next1: BLKRPT1, func: "no_op" }, { name: "EXTCMD1 ", bits: 1, next0: EXTCMD2, next1: FIRMWARE, func: "no_op" }, { name: "FIRMWARE ", bits: 8, next0: CORP, next1: CORP, func: "firmware" }, { name: "EXTCMD2 ", bits: 1, next0: MODE0, next1: TIMEOUT, func: "no_op" }, { name: "MODE0 ", bits: 7, next0: MODE1, next1: MODE1, func: "movexy0" }, { name: "TIMEOUT ", bits: 0, next0: START, next1: START, func: "timeout" }, { name: "BLKRPT1 ", bits: 1, next0: BLKRPTSTD, next1: BLKRPTNSTD, func: "no_op" }, { name: "BLKRPTSTD ", bits: 3, next0: START, next1: START, func: "blkrptstd" }, { name: "BLKRPTNSTD ", bits: 7, next0: START, next1: START, func: "blkrptnstd" }, { name: "PIXFAN ", bits: 1, next0: PIXSPEC, next1: PIXCODE, func: "no_op" }, { name: "PIXCODE4 ", bits: 4, next0: PIXRPT, next1: PIXRPT, func: "pixcodex" }, { name: "PIXDUP ", bits: 0, next0: PIXELS, next1: PIXELS, func: "pixdup" }, { name: "BLKDUP ", bits: 0, next0: START, next1: START, func: "blkdup" }, { name: "PIXCODE ", bits: 0, next0: PIXCODE, next1: PIXCODE, func: "pixcode" }, { name: "PIXSPEC ", bits: 1, next0: PIXGREY, next1: PIXRGB, func: "no_op" }, { name: "EXIT ", bits: 0, next0: EXIT, next1: EXIT, func: "exit" }, { name: "LATCHED ", bits: 1, next0: LATCHED, next1: LATCHED, func: "latched" }, { name: "MOVEXY1 ", bits: 7, next0: START, next1: START, func: "movexy1" }, { name: "MODE1 ", bits: 7, next0: MODE2, next1: MODE2, func: "mode1" }, { name: "PIXRGBG ", bits: 4, next0: PIXRGBB, next1: PIXRGBB, func: "pixrgbg" }, { name: "PIXRGBB ", bits: 4, next0: PIXRPT, next1: PIXRPT, func: "pixrgbb" }, { name: "HUNT ", bits: 1, next0: HUNT, next1: RESET, func: "hunt" }, { name: "PRINT0 ", bits: 8, next0: PRINT1, next1: PRINT1, func: "print0" }, { name: "PRINT1 ", bits: 8, next0: PRINT1, next1: PRINT1, func: "print1" }, { name: "CORP ", bits: 1, next0: START, next1: FIRMWARE, func: "corp" }, { name: "MODE2 ", bits: 4, next0: START, next1: START, func: "mode2" }, { name: "PIXRGB ", bits: 12, next0: PIXRPT, next1: PIXRPT, func: "pixrgb" } ], this.decoder_state = RESET, this.next_state = RESET, this.zero_count = 0, this.count_bytes = 0, this.ib_acc = 0, this.ib_bcnt = 0, this.sizex = 50, this.sizey = 37.5, this.blockwidth = 16, this.blockheight = 16, this.red = this.green = this.blue = 0, this.alpha = 255, this.ashift = 24, this.rshift = 20, this.gshift = 12, this.bshift = 4, this.video = video, this.stm_latched = !1, this.debug_state = !1, this.newx = this.newy = 0, this.sizex = 0, this.sizey = 0, this.sizey1 = 0, this.pixel_count = 0, this.block_count = 0, this.lastx = 0, this.lasty = 0, this.fatal_count = 0, this.timeout_count = -1, this.cmd_idx = 0, this.cmd_buf = [], this.print_chan = 0, this.print_buf = [], this.cache = new ColorCache(), this.pixels = null, this.cipher = "", this.licensed_irc = !1, this.licensed_murc = !1, this.licensed_playback = !1, this.licensed_scripted_vm = !1, this.vm_url_floppy_connected = !1, this.vm_url_cdrom_connected = !1, this.vm_applet_floppy_connected = !1, this.vm_applet_cdrom_connected = !1, this.half_height_capable = !1, this.process_header = function(cmd_buf) { this.set_bitspercolor(cmd_buf[0]), this.set_encryption(cmd_buf[1]), this.set_licensed(cmd_buf[2]), this.set_flags(cmd_buf[3]); }, this.set_licensed = function(lic) { this.licensed_irc = 1 == (1 & lic), this.licensed_playback = 2 == (2 & lic), this.licensed_murc = 4 == (4 & lic), this.licensed_scripted_vm = 8 == (8 & lic), video.notify_license({ irc: this.licensed_irc, playback: this.licensed_playback, murc: this.licensed_murc }); }, this.set_flags = function(flags) { this.vm_url_floppy_connected = 2 == (2 & flags), this.vm_url_floppy_connected && video.vm_change({ isFloppy: !0, isURL: !0, isConnected: !0 }), this.vm_url_cdrom_connected = 4 == (4 & flags), this.vm_url_cdrom_connected && video.vm_change({ isFloppy: !1, isURL: !0, isConnected: !0 }), this.half_height_capable = 8 == (8 & flags); }, this.set_encryption = function(encryption) { switch (encryption) { case 1: this.cipher = "RC4"; break; case 2: this.cipher = "AES"; break; case 3: this.cipher = "AES-256"; break; case 0: default: this.cipher = ""; } }, this.set_bitspercolor = function(bpc) { bpc = 5 - (3 & bpc), this.table[PIXGREY].bits = bpc, this.table[PIXRGBR].bits = bpc, this.table[PIXRGBG].bits = bpc, this.table[PIXRGBB].bits = bpc, this.table[PIXRGB].bits = 3 * bpc, this.rshift = 24 - 3 * bpc, this.gshift = 16 - 2 * bpc, this.bshift = 8 - bpc, this.cscale = bpc, this.bmask = (1 << bpc) - 1, this.gmask = this.bmask << bpc, this.rmask = this.gmask << bpc; }, this.set_halfheight = function(hh) { hh ? (this.table[MOVELONGX].bits = 8, this.table[MOVEXY0].bits = 8, this.table[MOVEXY1].bits = 8, this.table[BLKRPTNSTD].bits = 8, this.blockheight = 8) : (this.table[MOVELONGX].bits = 7, this.table[MOVEXY0].bits = 7, this.table[MOVEXY1].bits = 7, this.table[BLKRPTNSTD].bits = 7, this.blockheight = 16), this.pixels = this.new_pixels(); }, this.intmode = function() { this.new_pixels = this.new_pixels_intmode, this.store_pixel = this.store_pixel_intmode, this.pixels = this.new_pixels(); }, this.new_pixels_imagedata = function() { return this.context.createImageData(this.blockwidth, this.blockheight); }, this.imagemode = function(context) { this.context = context, context ? this.new_pixels = this.new_pixels_imagedata : this.new_pixels = this.new_pixels_orig, this.store_pixel = this.store_pixel_imagedata, this.pixels = this.new_pixels(); }, this.reset = function(code) { this.cache.reset(), this.pixel_count = 0, this.block_count = 0, this.lastx = 0, this.lasty = 0, this.fatal_count = 0, this.timeout_count = -1, this.red = this.green = this.blue = 0, this.table[PIXFAN].next1 = PIXCODE; }, this.moveshortx = function(code) { code += this.lastx + 1, this.lastx = code; }, this.movelongx = function(code) { this.lastx = code; }, this.movexy0 = function(code) { this.newx = code; }, this.movexy1 = function(code) { this.newy = code, this.lastx = this.newx, this.lasty = this.newy; }, this.pixcode = function(code) { this.next_state = this.cache.pixcode; }, this.pixcodex = function(code) { 1 === this.cache.active ? code = 0 : this.decoder_state === PIXLRU0 ? code = 0 : this.decoder_state === PIXLRU1 ? code = 1 : code && (code += 1); var color = this.cache.find(code); color ? this.store_pixel(color, 1) : this.next_state = LATCHED; }, this.pixrgb = function(code) { var color = code << 1 | 1, ret = this.cache.lru(color); this.table[PIXFAN].next1 = this.cache.pixcode, ret || this.store_pixel(color, 1); }, this.pixrgbr = function(code) { this.red = code; }, this.pixrgbg = function(code) { this.green = code; }, this.pixrgbb = function(code) { this.blue = code; var r = this.red << this.rshift, g = this.green << this.gshift, b = this.blue << this.bshift, a = this.alpha << this.ashift, color = r | g | b | a, ret = this.cache.lru(color); this.table[PIXFAN].next1 = this.cache.pixcode, ret ? this.count_bytes > 6 : this.store_pixel(color, 1); }, this.pixgrey = function(code) { var color = (code << 2 * this.cscale | code << this.cscale | code) << 1 | 1, ret = this.cache.lru(color); this.table[PIXFAN].next1 = this.cache.pixcode, ret ? this.count_bytes > 6 : this.store_pixel(color, 1); }, this.pixrptstd1 = function(code) { 7 == code ? this.next_state = PIXRPTNSTD : 6 == code ? this.next_state = PIXRPTSTD2 : this.store_pixel(this.last_color, code + 2); }, this.pixrptstd2 = function(code) { code += 8, this.pixrptnstd(code); }, this.pixrptnstd = function(code) { this.decoder_state == PIXRPTNSTD && 16 > code, this.store_pixel(this.last_color, code); }, this.pixdup = function(code) { this.store_pixel(this.last_color, 1); }, this.timeout = function(code) { this.timeout_count == this.count_bytes - 1 && (this.next_state = LATCHED), this.getbit(7 & this.ib_bcnt), this.timeout_count = this.count_bytes; }, this.firmware = function(code) { 0 == this.cmd_idx ? this.cmd_buf = [] : this.cmd_buf.push(this.cmd_last), this.cmd_idx++, this.cmd_last = code; }, this.corp = function(code) { 0 == code && (1 == this.cmd_last ? this.next_state = EXIT : 2 == this.cmd_last ? this.next_state = PRINT0 : 3 == this.cmd_last ? this.cmd_idx : 4 == this.cmd_last ? video.power_change("ON") : 5 == this.cmd_last ? (this.newx = 50, this.newy = 38, this.video.clear(), video.power_change("OFF")) : 6 == this.cmd_last ? (this.video.clear(), this.video.show_text(-1, "Video Suspended")) : 7 == this.cmd_last || 8 == this.cmd_last || (9 == this.cmd_last ? 7 & this.ib_bcnt && this.getbit(7 & this.ib_bcnt) : 10 == this.cmd_last ? (this.video.clear(), this.video.show_text(-1, "Session Acquired by another user")) : 11 == this.cmd_last ? this.set_bitspercolor(this.cmd_buf[0]) : 12 == this.cmd_last || (13 == this.cmd_last ? this.process_header(this.cmd_buf) : 16 == this.cmd_last ? this.video.send_ack() : 128 == this.cmd_last)), this.cmd_idx = 0); }, this.print0 = function(code) { this.print_chan = code, this.print_buf = []; }, this.print1 = function(code) { code ? this.print_buf.push(String.fromCharCode(code)) : (this.video.show_text(this.print_chan, this.print_buf.join("")), this.next_state = START); }, this.latched = function(code) { 0 == this.fatal_count && (this.debugx = this.lastx, this.debugy = this.lasty), 40 == this.fatal_count && this.video.refresh(), this.fatal_count += 1, 12e4 == this.fatal_count ? this.video.refresh() : 12e6 == this.fatal_count && (this.fatal_count = 41, this.video.refresh()); }, this.blkdup = function(code) { this.next_block(1); }, this.blkrptstd = function(code) { code += 2, this.next_block(code); }, this.blkrptnstd = function(code) { this.next_block(code); }, this.mode1 = function(code) { (0 == this.newx || 0 == code) && (this.newx = 50, code = 38, this.video.clear()), this.sizex = this.newx, this.sizey = code; }, this.mode2 = function(code) { this.lastx = 0, this.lasty = 0, this.pixel_count = 0, this.sizey1 = code, x = 16 * this.sizex, y = 16 * this.sizey + this.sizey1, this.cache.reset(), this.video.set_size(x, y), this.set_halfheight(x > 1616 ? !0 : !1); }, this.hunt = function(code) { this.next_state != this.decoder_state && (this.ib_bcnt = 0, this.ib_acc = 0, this.zero_count = 0, this.count_bytes = 0); }, this.exit = function(code) { this.halt = !0; }, this.no_op = function(code) {}, this.process = function(data) { for (var i = 0; i < data.length; i++) { this.addbits(255 & data[i]); for (var loop = !0; loop && this.decoder_state !== EXIT; ) { this.decoder_state > this.table.length; var entry = this.table[this.decoder_state], getlen = entry.bits; if (getlen > this.ib_bcnt) break; var code = this.getbit(getlen); !this.stm_latched && this.debug_state, this.stm_latched = this.decoder_state === LATCHED; var n = code ? "next1" : "next0"; this.next_state = this.table[this.decoder_state][n]; var f = entry.func; if (this[f](code), this.next_state === PIXELS && this.pixel_count === this.blockheight * this.blockwidth && (this.next_block(1), this.cache.prune(), this.table[PIXFAN].next1 = this.cache.pixcode), this.decoder_state === this.next_state && this.decoder_state !== PRINT1 && this.decoder_state !== LATCHED && this.decoder_state !== HUNT) return 1; this.decoder_state = this.next_state; } } return 0; }, this.process_buffer = function(new_bits) { this.addbits_buffer(new_bits); for (var loop = !0; loop && this.decoder_state !== EXIT; ) { this.decoder_state > this.table.length; var entry = this.table[this.decoder_state], getlen = entry.bits; if (getlen > this.ib_bcnt) break; var code = this.getbit(getlen); !this.stm_latched && this.debug_state, this.stm_latched = this.decoder_state == LATCHED; var n = code ? "next1" : "next0"; this.next_state = this.table[this.decoder_state][n]; var f = entry.func; if (this[f](code), this.next_state == PIXELS && this.pixel_count == this.blockheight * this.blockwidth && (this.next_block(1), this.cache.prune(), this.table[PIXFAN].next1 = this.cache.pixcode), this.decoder_state == this.next_state && this.decoder_state != PRINT1 && this.decoder_state != LATCHED && this.decoder_state != HUNT) return 1; this.decoder_state = this.next_state; } return 0; }, this.store_pixel = function(color, count) { for (var p = 3 * this.pixel_count, i = 0; count > i; i++) { if (!(this.pixel_count < this.blockwidth * this.blockheight)) return void (this.next_state = LATCHED); this.pixels[p++] = String.fromCharCode(255 & color), this.pixels[p++] = String.fromCharCode(color >> 8 & 255), this.pixels[p++] = String.fromCharCode(color >> 16 & 255), this.pixel_count += 1; } this.last_color = color; }, this.store_pixel_intmode = function(color, count) { var col = color; this.pixels.fill(col, this.pixel_count, this.pixel_count + count), this.pixel_count += count, this.last_color = color; }, this.store_pixel_imagedata = function(color, count) { for (var col = color >> 1, p = 4 * this.pixel_count, i = 0; count > i; i++) { if (!(this.pixel_count < this.blockwidth * this.blockheight)) return void (this.next_state = LATCHED); this.pixels[p++] = (col & this.rmask) << this.rshift >> 16, this.pixels[p++] = (col & this.gmask) << this.gshift >> 8, this.pixels[p++] = (col & this.bmask) << this.bshift, this.pixels[p++] = 255, this.pixel_count += 1; } this.last_color = color; }, this.next_block = function(count) { this.next_state = START, this.pixel_count = 0; for (var w = this.blockwidth, h = this.blockheight, startx = this.lastx, starty = this.lasty, areah = h, i = 0; count > i; i++) { var x0 = this.lastx * w, y0 = this.lasty * h; this.video.blit(x0, y0, w, h, this.pixels), this.lastx += 1, this.lastx > this.sizex && (this.lastx = this.sizex - this.lastx, this.lasty += 1, this.lasty > this.sizey && (this.lasty = 0), startx = this.lastx, areah += h), this.block_count += 1; } this.video.render(startx * w, starty * h, w * count, areah); }, this.new_pixels_imagedata = function() { return this.context.createImageData(this.blockwidth, this.blockheight); }, this.new_pixels_intmode = function() { return new Uint16Array(this.blockwidth * this.blockheight); }, this.new_pixels_orig = function() { return new Uint8Array(this.blockwidth * this.blockheight * 4); }, this.getbit = function(length) { if (0 == length) return 0; var temp = this.ib_acc & (1 << length) - 1; return this.ib_bcnt -= length, this.ib_acc >>= length, temp = temp >> 8 & 255 | temp << 8 & 65280, temp = temp >> 4 & 3855 | temp << 4 & 61680, temp = temp >> 2 & 13107 | temp << 2 & 52428, temp = temp >> 1 & 21845 | temp << 1 & 43690, temp >>= 16 - length; }, this.addbits = function(bits) { return this.zero_count += RIGHT[bits], this.count_bytes += 1, this.ib_acc |= bits << this.ib_bcnt, this.ib_bcnt += 8, this.count_bytes % 1e3 == 0, this.zero_count > 30 ? (this.decoder_state == LATCHED && this.fatal_count < 40, this.decoder_state = this.next_state = HUNT, this.ib_bcnt = 8, 4) : (0 != bits && (this.zero_count = LEFT[bits]), 0); }, this.setvideo = function(dvc_video) { this.video = dvc_video; }; }