diff --git a/zefie_wtvp_minisrv/app.js b/zefie_wtvp_minisrv/app.js index 9157b830..da033ffd 100644 --- a/zefie_wtvp_minisrv/app.js +++ b/zefie_wtvp_minisrv/app.js @@ -21,7 +21,7 @@ const sharp = require('sharp') const process = require('process'); const WTVSec = require(classPath + "/WTVSec.js"); const WTVSSL = require(classPath + "/WTVSSL.js"); -const WTVLzpf = require(classPath + "/WTVLzpf.js"); +const LZPF = require(classPath + "/LZPF.js"); const WTVClientCapabilities = require(classPath + "/WTVClientCapabilities.js"); const WTVClientSessionData = require(classPath + "/WTVClientSessionData.js"); const WTVMime = require(classPath + "/WTVMime.js"); @@ -1480,8 +1480,8 @@ async function sendToClient(socket, headers_obj, data = null) { case 1: // wtv-lzpf implementation headers_obj["wtv-lzpf"] = 0; - var wtvcomp = new WTVLzpf(); - data = wtvcomp.Compress(data); + var wtvcomp = new LZPF(); + data = wtvcomp.compress(data); wtvcomp = null; // Makes the garbage gods happy so it cleans up our mess break; diff --git a/zefie_wtvp_minisrv/includes/classes/LZPF.js b/zefie_wtvp_minisrv/includes/classes/LZPF.js new file mode 100644 index 00000000..655c9d8b --- /dev/null +++ b/zefie_wtvp_minisrv/includes/classes/LZPF.js @@ -0,0 +1,688 @@ +/** + * A Node.js port of the WebTV LZPF compression and expansion algorithm. + */ +class LZPF { + /** + * Initializes the Lzpf instance, setting up the necessary data tables + * and clearing the context for a new operation. + */ + constructor() { + // Static tables used by the compression and expansion algorithms. + // These are ported directly from the Python implementation. + this.tables = { + bitMask: [ + 0x00000000, 0x80000000, 0xC0000000, 0xE0000000, + 0xF0000000, 0xF8000000, 0xFC000000, 0xFE000000, + 0xFF000000, 0xFF800000, 0xFFC00000, 0xFFE00000, + 0xFFF00000, 0xFFF80000, 0xFFFC0000, 0xFFFE0000, + 0xFFFF0000, 0xFFFF8000, 0xFFFFC000, 0xFFFFE000, + 0xFFFFF000, 0xFFFFF800, 0xFFFFFC00, 0xFFFFFE00, + 0xFFFFFF00, 0xFFFFFF80, 0xFFFFFFC0, 0xFFFFFFE0, + 0xFFFFFFF0, 0xFFFFFFF8, 0xFFFFFFFC, 0xFFFFFFFE, + 0xFFFFFFFF + ], + huff_lits: [ + 0x20, 0x65, 0x0A, 0x22, 0x2F, 0x3C, 0x3E, 0x54, + 0x61, 0x69, 0x6E, 0x6F, 0x70, 0x72, 0x73, 0x74, + 0x09, 0x2E, 0x3D, 0x41, 0x45, 0x49, 0x4E, 0x4F, + 0x52, 0x63, 0x64, 0x68, 0x6C, 0x6D, 0x77, 0x2C, + 0x2D, 0x31, 0x42, 0x43, 0x44, 0x46, 0x47, 0x48, + 0x4C, 0x50, 0x53, 0x62, 0x66, 0x67, 0x75, 0x30, + 0x32, 0x34, 0x3A, 0x4D, 0x57, 0x5F, 0x6B, 0x76, + 0x79, 0x0D, 0x23, 0x27, 0x33, 0x35, 0x36, 0x37, + 0x38, 0x39, 0x55, 0x56, 0x5A, 0x78, 0x21, 0x2A, + 0x3F, 0x4B, 0x59, 0x7A, 0x26, 0x28, 0x29, 0x3B, + 0x4A, 0x6A, 0x71, 0x51, 0x58, 0x7B, 0x7C, 0x7D, + 0x7E, 0x2B, 0x24, 0x40, 0x05, 0x07, 0x08, 0x0B, + 0x17, 0x91, 0x92, 0x93, 0xC7, 0xF3, 0xFA, 0x00, + 0x01, 0x02, 0x03, 0x04, 0x06, 0x0C, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x18, + 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x25, + 0x5B, 0x5C, 0x5D, 0x5E, 0x60, 0x7F, 0x80, 0x81, + 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, + 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, 0x90, 0x94, + 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, + 0x9D, 0x9E, 0x9F, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, + 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, + 0xAD, 0xAE, 0xAF, 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, + 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, + 0xBD, 0xBE, 0xBF, 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, + 0xC5, 0xC6, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, + 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, + 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, + 0xDE, 0xDF, 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, + 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, + 0xEE, 0xEF, 0xF0, 0xF1, 0xF2, 0xF4, 0xF5, 0xF6, + 0xF7, 0xF8, 0xF9, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF + ], + parents: [ + 0x00, 0x02, 0x04, 0x08, 0x0E, 0x0E, 0x0D, 0x0A, + 0x0A, 0x07, 0x08, 0x09, 0x0C, 0x17, 0x2C, 0x4D, + 0x00, 0x00, 0x00, 0x00, + ], + // Pre-converted to signed 8-bit integers to match Python's ctypes.c_byte behavior + lit_base: [ + 0, -2, -4, -8, -14, -12, 3, 21, 37, 50, 62, 67, 71, 66, 46, 15, 103, 0, 0, 0 + ], + peekTable: [ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04 + ], + matchDecode: [ + 0x01, 0x03, 0x01, 0x03, 0x01, 0x03, 0x01, 0x03, + 0x01, 0x03, 0x01, 0x03, 0x01, 0x03, 0x01, 0x03, + 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, + 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x04, 0x06, 0x05, 0x06, 0x06, 0x06, 0x07, 0x06, + 0x08, 0x06, 0x09, 0x06, 0x0A, 0x06, 0x00, 0x00 + ], + nomatchEncode: [ + [0x0000, 0x10], [0x0001, 0x10], [0x0002, 0x10], + [0x0003, 0x10], [0x0004, 0x10], [0x009A, 0x0F], + [0x0005, 0x10], [0x009C, 0x0F], [0x009E, 0x0F], + [0x3400, 0x06], [0x7000, 0x05], [0x00A0, 0x0F], + [0x0006, 0x10], [0x0380, 0x09], [0x0007, 0x10], + [0x0008, 0x10], [0x0009, 0x10], [0x000A, 0x10], + [0x000B, 0x10], [0x000C, 0x10], [0x000D, 0x10], + [0x000E, 0x10], [0x000F, 0x10], [0x00A2, 0x0F], + [0x0010, 0x10], [0x0011, 0x10], [0x0012, 0x10], + [0x0013, 0x10], [0x0014, 0x10], [0x0015, 0x10], + [0x0016, 0x10], [0x0017, 0x10], [0xE000, 0x04], + [0x0200, 0x0A], [0x7800, 0x05], [0x0400, 0x09], + [0x00B0, 0x0E], [0x0018, 0x10], [0x0120, 0x0B], + [0x0480, 0x09], [0x0140, 0x0B], [0x0160, 0x0B], + [0x0240, 0x0A], [0x00B8, 0x0D], [0x1400, 0x07], + [0x1600, 0x07], [0x3800, 0x06], [0x8000, 0x05], + [0x0A00, 0x08], [0x1800, 0x07], [0x0B00, 0x08], + [0x0500, 0x09], [0x0C00, 0x08], [0x0580, 0x09], + [0x0600, 0x09], [0x0680, 0x09], [0x0700, 0x09], + [0x0780, 0x09], [0x0D00, 0x08], [0x0180, 0x0B], + [0x8800, 0x05], [0x3C00, 0x06], [0x9000, 0x05], + [0x0280, 0x0A], [0x00B4, 0x0E], [0x4000, 0x06], + [0x1A00, 0x07], [0x1C00, 0x07], [0x1E00, 0x07], + [0x4400, 0x06], [0x2000, 0x07], [0x2200, 0x07], + [0x2400, 0x07], [0x4800, 0x06], [0x01A0, 0x0B], + [0x02C0, 0x0A], [0x2600, 0x07], [0x0E00, 0x08], + [0x4C00, 0x06], [0x5000, 0x06], [0x2800, 0x07], + [0x00C0, 0x0C], [0x5400, 0x06], [0x2A00, 0x07], + [0x9800, 0x05], [0x0800, 0x09], [0x0880, 0x09], + [0x0F00, 0x08], [0x00D0, 0x0C], [0x0300, 0x0A], + [0x0900, 0x09], [0x0019, 0x10], [0x001A, 0x10], + [0x001B, 0x10], [0x001C, 0x10], [0x1000, 0x08], + [0x001D, 0x10], [0xA000, 0x05], [0x2C00, 0x07], + [0x5800, 0x06], [0x5C00, 0x06], [0xF000, 0x04], + [0x2E00, 0x07], [0x3000, 0x07], [0x6000, 0x06], + [0xA800, 0x05], [0x01C0, 0x0B], [0x1100, 0x08], + [0x6400, 0x06], [0x6800, 0x06], [0xB000, 0x05], + [0xB800, 0x05], [0xC000, 0x05], [0x01E0, 0x0B], + [0xC800, 0x05], [0xD000, 0x05], [0xD800, 0x05], + [0x3200, 0x07], [0x1200, 0x08], [0x6C00, 0x06], + [0x0980, 0x09], [0x1300, 0x08], [0x0340, 0x0A], + [0x00E0, 0x0C], [0x00F0, 0x0C], [0x0100, 0x0C], + [0x0110, 0x0C], [0x001E, 0x10], [0x001F, 0x10], + [0x0020, 0x10], [0x0021, 0x10], [0x0022, 0x10], + [0x0023, 0x10], [0x0024, 0x10], [0x0025, 0x10], + [0x0026, 0x10], [0x0027, 0x10], [0x0028, 0x10], + [0x0029, 0x10], [0x002A, 0x10], [0x002B, 0x10], + [0x002C, 0x10], [0x002D, 0x10], [0x002E, 0x10], + [0x002F, 0x10], [0x00A4, 0x0F], [0x00A6, 0x0F], + [0x00A8, 0x0F], [0x0030, 0x10], [0x0031, 0x10], + [0x0032, 0x10], [0x0033, 0x10], [0x0034, 0x10], + [0x0035, 0x10], [0x0036, 0x10], [0x0037, 0x10], + [0x0038, 0x10], [0x0039, 0x10], [0x003A, 0x10], + [0x003B, 0x10], [0x003C, 0x10], [0x003D, 0x10], + [0x003E, 0x10], [0x003F, 0x10], [0x0040, 0x10], + [0x0041, 0x10], [0x0042, 0x10], [0x0043, 0x10], + [0x0044, 0x10], [0x0045, 0x10], [0x0046, 0x10], + [0x0047, 0x10], [0x0048, 0x10], [0x0049, 0x10], + [0x004A, 0x10], [0x004B, 0x10], [0x004C, 0x10], + [0x004D, 0x10], [0x004E, 0x10], [0x004F, 0x10], + [0x0050, 0x10], [0x0051, 0x10], [0x0052, 0x10], + [0x0053, 0x10], [0x0054, 0x10], [0x0055, 0x10], + [0x0056, 0x10], [0x0057, 0x10], [0x0058, 0x10], + [0x0059, 0x10], [0x005A, 0x10], [0x005B, 0x10], + [0x005C, 0x10], [0x005D, 0x10], [0x005E, 0x10], + [0x005F, 0x10], [0x0060, 0x10], [0x0061, 0x10], + [0x0062, 0x10], [0x00AA, 0x0F], [0x0063, 0x10], + [0x0064, 0x10], [0x0065, 0x10], [0x0066, 0x10], + [0x0067, 0x10], [0x0068, 0x10], [0x0069, 0x10], + [0x006A, 0x10], [0x006B, 0x10], [0x006C, 0x10], + [0x006D, 0x10], [0x006E, 0x10], [0x006F, 0x10], + [0x0070, 0x10], [0x0071, 0x10], [0x0072, 0x10], + [0x0073, 0x10], [0x0074, 0x10], [0x0075, 0x10], + [0x0076, 0x10], [0x0077, 0x10], [0x0078, 0x10], + [0x0079, 0x10], [0x007A, 0x10], [0x007B, 0x10], + [0x007C, 0x10], [0x007D, 0x10], [0x007E, 0x10], + [0x007F, 0x10], [0x0080, 0x10], [0x0081, 0x10], + [0x0082, 0x10], [0x0083, 0x10], [0x0084, 0x10], + [0x0085, 0x10], [0x0086, 0x10], [0x0087, 0x10], + [0x0088, 0x10], [0x0089, 0x10], [0x008A, 0x10], + [0x008B, 0x10], [0x008C, 0x10], [0x008D, 0x10], + [0x00AC, 0x0F], [0x008E, 0x10], [0x008F, 0x10], + [0x0090, 0x10], [0x0091, 0x10], [0x0092, 0x10], + [0x0093, 0x10], [0x00AE, 0x0F], [0x0094, 0x10], + [0x0095, 0x10], [0x0096, 0x10], [0x0097, 0x10], + [0x0098, 0x10], [0x0099, 0x10] + ], + matchEncode: [ + [0x80000000, 0x01], [0x80000000, 0x03], + [0xA0000000, 0x03], [0xC0000000, 0x03], + [0xE0000000, 0x06], [0xE4000000, 0x06], + [0xE8000000, 0x06], [0xEC000000, 0x06], + [0xF0000000, 0x06], [0xF4000000, 0x06], + [0xF8000000, 0x06], [0xFC000000, 0x0B], + [0xFC200000, 0x0B], [0xFC400000, 0x0B], + [0xFC600000, 0x0B], [0xFC800000, 0x0B], + [0xFCA00000, 0x0B], [0xFCC00000, 0x0B], + [0xFCE00000, 0x0B], [0xFD000000, 0x0B], + [0xFD200000, 0x0B], [0xFD400000, 0x0B], + [0xFD600000, 0x0B], [0xFD800000, 0x0B], + [0xFDA00000, 0x0B], [0xFDC00000, 0x0B], + [0xFDE00000, 0x0B], [0xFE000000, 0x0B], + [0xFE200000, 0x0B], [0xFE400000, 0x0B], + [0xFE600000, 0x0B], [0xFE800000, 0x0B], + [0xFEA00000, 0x0B], [0xFEC00000, 0x0B], + [0xFEE00000, 0x0B], [0xFF000000, 0x0B], + [0xFF200000, 0x0B], [0xFF400000, 0x0B], + [0xFF600000, 0x0B], [0xFF800000, 0x0B], + [0xFFA00000, 0x0B], [0xFFC00000, 0x0B], + [0xFFE00000, 0x13], [0xFFE02000, 0x13], + [0xFFE04000, 0x13], [0xFFE06000, 0x13], + [0xFFE08000, 0x13], [0xFFE0A000, 0x13], + [0xFFE0C000, 0x13], [0xFFE0E000, 0x13], + [0xFFE10000, 0x13], [0xFFE12000, 0x13], + [0xFFE14000, 0x13], [0xFFE16000, 0x13], + [0xFFE18000, 0x13], [0xFFE1A000, 0x13], + [0xFFE1C000, 0x13], [0xFFE1E000, 0x13], + [0xFFE20000, 0x13], [0xFFE22000, 0x13], + [0xFFE24000, 0x13], [0xFFE26000, 0x13], + [0xFFE28000, 0x13], [0xFFE2A000, 0x13], + [0xFFE2C000, 0x13], [0xFFE2E000, 0x13], + [0xFFE30000, 0x13], [0xFFE32000, 0x13], + [0xFFE34000, 0x13], [0xFFE36000, 0x13], + [0xFFE38000, 0x13], [0xFFE3A000, 0x13], + [0xFFE3C000, 0x13], [0xFFE3E000, 0x13], + [0xFFE40000, 0x13], [0xFFE42000, 0x13], + [0xFFE44000, 0x13], [0xFFE46000, 0x13], + [0xFFE48000, 0x13], [0xFFE4A000, 0x13], + [0xFFE4C000, 0x13], [0xFFE4E000, 0x13], + [0xFFE50000, 0x13], [0xFFE52000, 0x13], + [0xFFE54000, 0x13], [0xFFE56000, 0x13], + [0xFFE58000, 0x13], [0xFFE5A000, 0x13], + [0xFFE5C000, 0x13], [0xFFE5E000, 0x13], + [0xFFE60000, 0x13], [0xFFE62000, 0x13], + [0xFFE64000, 0x13], [0xFFE66000, 0x13], + [0xFFE68000, 0x13], [0xFFE6A000, 0x13], + [0xFFE6C000, 0x13], [0xFFE6E000, 0x13], + [0xFFE70000, 0x13], [0xFFE72000, 0x13], + [0xFFE74000, 0x13], [0xFFE76000, 0x13], + [0xFFE78000, 0x13], [0xFFE7A000, 0x13], + [0xFFE7C000, 0x13], [0xFFE7E000, 0x13], + [0xFFE80000, 0x13], [0xFFE82000, 0x13], + [0xFFE84000, 0x13], [0xFFE86000, 0x13], + [0xFFE88000, 0x13], [0xFFE8A000, 0x13], + [0xFFE8C000, 0x13], [0xFFE8E000, 0x13], + [0xFFE90000, 0x13], [0xFFE92000, 0x13], + [0xFFE94000, 0x13], [0xFFE96000, 0x13], + [0xFFE98000, 0x13], [0xFFE9A000, 0x13], + [0xFFE9C000, 0x13], [0xFFE9E000, 0x13], + [0xFFEA0000, 0x13], [0xFFEA2000, 0x13], + [0xFFEA4000, 0x13], [0xFFEA6000, 0x13], + [0xFFEA8000, 0x13], [0xFFEAA000, 0x13], + [0xFFEAC000, 0x13], [0xFFEAE000, 0x13], + [0xFFEB0000, 0x13], [0xFFEB2000, 0x13], + [0xFFEB4000, 0x13], [0xFFEB6000, 0x13], + [0xFFEB8000, 0x13], [0xFFEBA000, 0x13], + [0xFFEBC000, 0x13], [0xFFEBE000, 0x13], + [0xFFEC0000, 0x13], [0xFFEC2000, 0x13], + [0xFFEC4000, 0x13], [0xFFEC6000, 0x13], + [0xFFEC8000, 0x13], [0xFFECA000, 0x13], + [0xFFECC000, 0x13], [0xFFECE000, 0x13], + [0xFFED0000, 0x13], [0xFFED2000, 0x13], + [0xFFED4000, 0x13], [0xFFED6000, 0x13], + [0xFFED8000, 0x13], [0xFFEDA000, 0x13], + [0xFFEDC000, 0x13], [0xFFEDE000, 0x13], + [0xFFEE0000, 0x13], [0xFFEE2000, 0x13], + [0xFFEE4000, 0x13], [0xFFEE6000, 0x13], + [0xFFEE8000, 0x13], [0xFFEEA000, 0x13], + [0xFFEEC000, 0x13], [0xFFEEE000, 0x13], + [0xFFEF0000, 0x13], [0xFFEF2000, 0x13], + [0xFFEF4000, 0x13], [0xFFEF6000, 0x13], + [0xFFEF8000, 0x13], [0xFFEFA000, 0x13], + [0xFFEFC000, 0x13], [0xFFEFE000, 0x13], + [0xFFF00000, 0x13], [0xFFF02000, 0x13], + [0xFFF04000, 0x13], [0xFFF06000, 0x13], + [0xFFF08000, 0x13], [0xFFF0A000, 0x13], + [0xFFF0C000, 0x13], [0xFFF0E000, 0x13], + [0xFFF10000, 0x13], [0xFFF12000, 0x13], + [0xFFF14000, 0x13], [0xFFF16000, 0x13], + [0xFFF18000, 0x13], [0xFFF1A000, 0x13], + [0xFFF1C000, 0x13], [0xFFF1E000, 0x13], + [0xFFF20000, 0x13], [0xFFF22000, 0x13], + [0xFFF24000, 0x13], [0xFFF26000, 0x13], + [0xFFF28000, 0x13], [0xFFF2A000, 0x13], + [0xFFF2C000, 0x13], [0xFFF2E000, 0x13], + [0xFFF30000, 0x13], [0xFFF32000, 0x13], + [0xFFF34000, 0x13], [0xFFF36000, 0x13], + [0xFFF38000, 0x13], [0xFFF3A000, 0x13], + [0xFFF3C000, 0x13], [0xFFF3E000, 0x13], + [0xFFF40000, 0x13], [0xFFF42000, 0x13], + [0xFFF44000, 0x13], [0xFFF46000, 0x13], + [0xFFF48000, 0x13], [0xFFF4A000, 0x13], + [0xFFF4C000, 0x13], [0xFFF4E000, 0x13], + [0xFFF50000, 0x13], [0xFFF52000, 0x13], + [0xFFF54000, 0x13], [0xFFF56000, 0x13], + [0xFFF58000, 0x13], [0xFFF5A000, 0x13], + [0xFFF5C000, 0x13], [0xFFF5E000, 0x13], + [0xFFF60000, 0x13], [0xFFF62000, 0x13], + [0xFFF64000, 0x13], [0xFFF66000, 0x13], + [0xFFF68000, 0x13], [0xFFF6A000, 0x13], + [0xFFF6C000, 0x13], [0xFFF6E000, 0x13], + [0xFFF70000, 0x13], [0xFFF72000, 0x13], + [0xFFF74000, 0x13], [0xFFF76000, 0x13], + [0xFFF78000, 0x13], [0xFFF7A000, 0x13], + [0xFFF7C000, 0x13], [0xFFF7E000, 0x13], + [0xFFF80000, 0x13], [0xFFF82000, 0x13], + [0xFFF84000, 0x13], [0xFFF86000, 0x13], + [0xFFF88000, 0x13], [0xFFF8A000, 0x13], + [0xFFF8C000, 0x13], [0xFFF8E000, 0x13], + [0xFFF90000, 0x13], [0xFFF92000, 0x13], + [0xFFF94000, 0x13], [0xFFF96000, 0x13], + [0xFFF98000, 0x13], [0xFFF9A000, 0x13], + [0xFFF9C000, 0x13], [0xFFF9E000, 0x13], + [0xFFFA0000, 0x13], [0xFFFA2000, 0x13], + [0xFFFA4000, 0x13], [0xFFFA6000, 0x13], + [0xFFFA8000, 0x13], [0xFFFAA000, 0x13], + [0xFFFAC000, 0x13], [0xFFFAE000, 0x13], + [0xFFFB0000, 0x13], [0xFFFB2000, 0x13], + [0xFFFB4000, 0x13], [0xFFFB6000, 0x13], + [0xFFFB8000, 0x13], [0xFFFBA000, 0x13], + [0xFFFBC000, 0x13], [0xFFFBE000, 0x13], + [0xFFFC0000, 0x13], [0xFFFC2000, 0x13], + [0xFFFC4000, 0x13], [0xFFFC6000, 0x13], + [0xFFFC8000, 0x13], [0xFFFCA000, 0x13], + [0xFFFCC000, 0x13], [0xFFFCE000, 0x13], + [0xFFFD0000, 0x13], [0xFFFD2000, 0x13], + [0xFFFD4000, 0x13], [0xFFFD6000, 0x13], + [0xFFFD8000, 0x13], [0xFFFDA000, 0x13], + [0xFFFDC000, 0x13], [0xFFFDE000, 0x13], + [0xFFFE0000, 0x13], [0xFFFE2000, 0x13], + [0xFFFE4000, 0x13], [0xFFFE6000, 0x13], + [0xFFFE8000, 0x13], [0xFFFEA000, 0x13], + [0xFFFEC000, 0x13], [0xFFFEE000, 0x13], + [0xFFFF0000, 0x13], [0xFFFF2000, 0x13], + [0xFFFF4000, 0x13], [0xFFFF6000, 0x13], + [0xFFFF8000, 0x13], [0xFFFFA000, 0x13], + [0xFFFFC000, 0x13], [0xFFFFE000, 0x13], + ] + }; + + this.clear(); + } + + /** + * Resets the compression/expansion context to its initial state. + * This is called automatically by the constructor and before starting a new compression or expansion. + */ + clear() { + this.context = { + current_literal: 0, + current_length: 0, + compressed_data: [], + filler_byte: 0x00, + ring_buffer: Buffer.alloc(0x2000), + flag_table: new Array(0x1000).fill(0xFFFF), + }; + } + + /** + * Encodes a literal value into the compressed data stream. + * @param {number} code_length - The number of bits in the code. + * @param {number} code - The code to be written. + */ + encodeLiteral(code_length, code) { + // JavaScript handles large integers, but we ensure 32-bit unsigned behavior for consistency + // by using the unsigned right shift operator (>>>). + this.context.current_literal |= (code >>> (this.context.current_length & 0x1F)); + this.context.current_length += code_length; + + // Write full bytes to the output buffer as they are completed. + while (this.context.current_length > 7) { + this.context.compressed_data.push((this.context.current_literal >>> 0x18) & 0xFF); + this.context.current_length -= 8; + this.context.current_literal <<= 8; + } + } + + /** + * Compresses the input data using the LZPF algorithm. + * @param {Buffer} uncompressed_data - The raw data to be compressed. + * @returns {Buffer} The compressed data. + */ + compress(uncompressed_data) { + this.clear(); + if (typeof uncompressed_data === 'string') { + uncompressed_data = Buffer.from(uncompressed_data, 'utf8'); + } + + const uncompressed_len = uncompressed_data.length; + + let i = 0; + let sum = 0; + let working_data = 0; + let flag = 0xFFFF; + let flags_index = 0; + let match_index = 0; + let type_index = 0; + + while (i < uncompressed_len) { + let code_length = -1; + let code = -1; + + const byte = uncompressed_data[i]; + this.context.ring_buffer[i & 0x1FFF] = byte; + + if (match_index > 0) { + // We are currently in a match sequence + if (byte !== this.context.ring_buffer[flag] || match_index > 0x0127) { + // Match ended, encode the match length + code_length = this.tables.matchEncode[match_index][1]; + code = this.tables.matchEncode[match_index][0]; + match_index = 0; + type_index = 3; + } else { + // Match continues + match_index += 1; + flag = (flag + 1) & 0x1FFF; + sum += byte; + working_data = ((working_data * 0x0100) + byte) | 0; // Keep as 32-bit int + i += 1; + } + } else { + // Not in a match sequence, look for one + flag = 0xFFFF; + + if (i >= 3) { + // Calculate hash to find a potential match in the flag table + flags_index = ((working_data >>> 0x0B) ^ working_data) & 0x0FFF; + flag = this.context.flag_table[flags_index]; + this.context.flag_table[flags_index] = i & 0x1FFF; + } else { + type_index += 1; + } + + if (flag === 0xFFFF) { + // No match found, encode as a literal + code_length = this.tables.nomatchEncode[byte][1]; + code = this.tables.nomatchEncode[byte][0] << 0x10; + } else if (byte === this.context.ring_buffer[flag]) { + // A match has started + match_index = 1; + flag = (flag + 1) & 0x1FFF; + type_index = 4; + } else { + // No match found, encode as a literal + code_length = this.tables.nomatchEncode[byte][1] + 1; + code = this.tables.nomatchEncode[byte][0] << 0x0F; + } + + sum += byte; + working_data = ((working_data * 0x0100) + byte) | 0; // Keep as 32-bit int + i += 1; + } + + if (code_length > 0) { + this.encodeLiteral(code_length, code); + } + } + + // Finalize the stream + if (type_index === 2) { + this.encodeLiteral(0x10, 0x00990000); + } else if (type_index >= 3) { + if (type_index === 4) { + const code_length = this.tables.matchEncode[match_index][1]; + const code = this.tables.matchEncode[match_index][0]; + this.encodeLiteral(code_length, code); + } + + flags_index = ((working_data >>> 0x0B) ^ working_data) & 0x0FFF; + flag = this.context.flag_table[flags_index]; + if (flag === 0xFFFF) { + this.encodeLiteral(0x10, 0x00990000); + } else { + this.encodeLiteral(0x11, 0x004c8000); + } + } + + // Encode checksum + sum &= 0xFFFF; + this.encodeLiteral(0x08, (sum << 0x10)); + this.encodeLiteral(0x08, (sum << 0x18)); + + // Write any remaining bits and the filler byte + if (this.context.current_length !== 0) { + this.context.compressed_data.push(this.context.current_literal >>> 0x18); + } + this.context.compressed_data.push(this.context.filler_byte); + + return Buffer.from(this.context.compressed_data); + } + + /** + * Expands data compressed with the LZPF algorithm. + * @param {Buffer} compressed_data - The compressed data. + * @returns {Buffer} The expanded (original) data. + */ + expand(compressed_data) { + this.clear(); + const uncompressed_data = []; + let block = 0; + let flags = 0xFFFF; + let iii = 0; // uncompressed data index + + for (let i = 0; i < compressed_data.length; i++) { + const byte = compressed_data[i]; + + this.context.current_literal |= (byte << (0x18 - (this.context.current_length & 0x1f))); + this.context.current_length += 8; + + while (this.context.current_length >= 0x13) { + // Check the high bit to determine if it's a match or a literal + if ((this.context.current_literal & 0x80000000) !== 0 && flags !== 0xFFFF) { + // It's a match + const match = this.readMatch(); + let ring_buffer_index = flags; + for (let ii = 0; ii < match; ii++) { + const matched_byte = this.context.ring_buffer[ring_buffer_index & 0x1FFF]; + uncompressed_data.push(matched_byte); + this.context.ring_buffer[iii & 0x1FFF] = matched_byte; + iii++; + block = ((block << 8) | matched_byte) | 0; + ring_buffer_index++; + } + } else { + // It's a literal, decode it + let byte = 0; + if (flags === 0xFFFF) { + byte = this.huffDecodeLiteralNoFlags(); + } else { + byte = this.huffDecodeLiteral(); + } + + if (byte !== null) { + uncompressed_data.push(byte); + this.context.ring_buffer[iii & 0x1FFF] = byte; + iii++; + block = ((block << 8) | byte) | 0; + } else { + // End of stream marker found + return Buffer.from(uncompressed_data); + } + } + + if (uncompressed_data.length >= 3) { + const flags_index = ((block >>> 0x0B) ^ block) & 0xFFF; + flags = this.context.flag_table[flags_index]; + this.context.flag_table[flags_index] = uncompressed_data.length; + + if (uncompressed_data.length === 3) { + break; + } + } + } + } + return Buffer.from(uncompressed_data); + } + + /** + * Reads and decodes a match length from the bitstream. + * @returns {number} The length of the match. + */ + readMatch() { + let match = 0; + const width_index = (this.context.current_literal >>> 0x19) & 0x3E; + let data_width = this.tables.matchDecode[width_index + 1]; + + if (data_width === 0) { + if ((this.context.current_literal & 0x3e00000) === 0x3e00000) { + match = ((this.context.current_literal >>> 0x0D) & 0xFF) + 0x2A; + data_width = 0x13; + } else { + match = ((this.context.current_literal & 0x3e00000) >>> 0x15) + 0x0B; + data_width = 0x0B; + } + } else { + match = this.tables.matchDecode[width_index]; + } + + this.context.current_literal <<= (data_width & 0x1F); + this.context.current_length -= data_width; + + return match; + } + + /** + * Decodes a Huffman-encoded literal from the bitstream (when no flags are set). + * @returns {number|null} The decoded byte, or null if end of stream. + */ + huffDecodeLiteralNoFlags() { + let code = 0; + let data_width = this.tables.peekTable[this.context.current_literal >>> 0x17]; + + if (data_width === 0) { + code = this.context.current_literal >>> 0x16; + data_width = 0x0A; + while (code < this.tables.parents[data_width]) { + data_width++; + code = this.context.current_literal >>> (0x20 - (data_width & 0x1F)); + } + } else { + code = (this.context.current_literal & this.tables.bitMask[data_width]) >>> (0x20 - (data_width & 0x1F)); + } + + this.context.current_literal <<= (data_width & 0x1F); + this.context.current_length -= data_width; + + if (code === 0x99 && data_width === 0x10) { + return null; // End of stream marker + } else { + return this.tables.huff_lits[(code + this.tables.lit_base[data_width])]; + } + } + + /** + * Decodes a Huffman-encoded literal from the bitstream (when flags are set). + * @returns {number|null} The decoded byte, or null if end of stream. + */ + huffDecodeLiteral() { + let code = 0; + let data_width = this.tables.peekTable[this.context.current_literal >>> 0x16]; + + if (data_width === 0) { + code = this.context.current_literal >>> 0x15; + data_width = 0x0A; + while (code < this.tables.parents[data_width]) { + data_width++; + code = this.context.current_literal >>> (0x1F - (data_width & 0x1F)); + } + } else { + code = (this.context.current_literal & this.tables.bitMask[(data_width + 1)]) >>> (0x1F - (data_width & 0x1F)); + } + + this.context.current_literal <<= ((data_width + 1) & 0x1F); + this.context.current_length -= (data_width + 1); + + if (code === 0x99 && data_width === 0x10) { + return null; // End of stream marker + } else { + return this.tables.huff_lits[(code + this.tables.lit_base[data_width])]; + } + } +} + +module.exports = LZPF; \ No newline at end of file diff --git a/zefie_wtvp_minisrv/includes/classes/WTVLzpf.js b/zefie_wtvp_minisrv/includes/classes/WTVLzpf.js deleted file mode 100644 index 3cdf16cc..00000000 --- a/zefie_wtvp_minisrv/includes/classes/WTVLzpf.js +++ /dev/null @@ -1,522 +0,0 @@ -/** - * Pure-JS implementation of WebTV's LZPF compression - * - * This compression algorithm is based on LZP by Charles Bloom and was originally written for server to client communication by Andy McFadden - * This uses a (static) Huffman dictionary that was tuned for character occurances in a typical HTML page at the time (around 1996-1997). - * - * Andy McFadden: - * https://fadden.com/ - * LZP: - * https://cbloom.com/src/index_lz.html - * https://en.wikibooks.org/wiki/Data_Compression/Dictionary_compression#LZP - * - * I wouldn't recommend using LZPF on anything but HTML and other text-based data (unless the data has many repeating bytes) - * LZPF can be replaced with gzip for LC2 and newer boxes. Classic is stuck with LZPF. - * - * Reverse engineered and ported by: Eric MacDonald (eMac) - * Modified By: zefie -**/ - -class WTVLzpf { - // Note: currentlty doesn't offer optimal streaming support but this is good enough to meet perf demands at the scale we're at. - - current_bit_length = 0; - current_bits = 0; - ring_bufer_index = 0xFFFF; - working_data = 0; - match_index = 0; - compression_mode = 0; - checksum = 0; - filler_byte = 0x20 - hash_table = new Uint16Array(0x1000) - ring_buffer = new Uint8Array(0x2000) - encoded_data = []; - - /** - * This is used to encode (one-byte) literals with no previous tracked occurence. - * - * - Bytes with best compression: SPACE and LF and e"/<>Tainoprst - * - Bytes with good compression: TAB and ,-.1=ABCDEFGHILNOPRSbcdfghlmuw - * - Bytes that don't change the length of the bit stream: 024:MW_kvy - * - The rest will increase the length of bit stream - * - * I don't know what process they used to build this table. I assume they - * frequency-scanned a bunch of HTML files they had. - * - * Using Windows-1252 (based off of ISO-8859-1) chracter encoding to fill in this table. Didn't - * seem like they used a different table for Japan builds (ISO-2022-JP). - **/ - nomatchEncode = [ - /* [FLATTENED HUFFMAN CODE, CODE BIT LENGTH] */ - [0x0000, 0x10] /* NUL */, [0x0001, 0x10] /* SOH */, [0x0002, 0x10] /* STX */, - [0x0003, 0x10] /* ETX */, [0x0004, 0x10] /* EOT */, [0x009A, 0x0F] /* ENQ */, - [0x0005, 0x10] /* ACK */, [0x009C, 0x0F] /* BEL */, [0x009E, 0x0F] /* BS */, - [0x3400, 0x06] /* TAB */, [0x7000, 0x05] /* LF */, [0x00A0, 0x0F] /* VT */, - [0x0006, 0x10] /* FF */, [0x0380, 0x09] /* CR */, [0x0007, 0x10] /* SO */, - [0x0008, 0x10] /* SI */, [0x0009, 0x10] /* DLE */, [0x000A, 0x10] /* DC1 */, - [0x000B, 0x10] /* DC2 */, [0x000C, 0x10] /* DC3 */, [0x000D, 0x10] /* DC4 */, - [0x000E, 0x10] /* NAK */, [0x000F, 0x10] /* SYN */, [0x00A2, 0x0F] /* BTB */, - [0x0010, 0x10] /* CAN */, [0x0011, 0x10] /* EM */, [0x0012, 0x10] /* SUB */, - [0x0013, 0x10] /* ESC */, [0x0014, 0x10] /* FS */, [0x0015, 0x10] /* GS */, - [0x0016, 0x10] /* RS */, [0x0017, 0x10] /* US */, [0xE000, 0x04] /* SPACE */, - [0x0200, 0x0A] /* ! */, [0x7800, 0x05] /* " */, [0x0400, 0x09] /* # */, - [0x00B0, 0x0E] /* $ */, [0x0018, 0x10] /* % */, [0x0120, 0x0B] /* & */, - [0x0480, 0x09] /* ' */, [0x0140, 0x0B] /* ( */, [0x0160, 0x0B] /* ) */, - [0x0240, 0x0A] /* * */, [0x00B8, 0x0D] /* + */, [0x1400, 0x07] /* , */, - [0x1600, 0x07] /* - */, [0x3800, 0x06] /* . */, [0x8000, 0x05] /* / */, - [0x0A00, 0x08] /* 0 */, [0x1800, 0x07] /* 1 */, [0x0B00, 0x08] /* 2 */, - [0x0500, 0x09] /* 3 */, [0x0C00, 0x08] /* 4 */, [0x0580, 0x09] /* 5 */, - [0x0600, 0x09] /* 6 */, [0x0680, 0x09] /* 7 */, [0x0700, 0x09] /* 8 */, - [0x0780, 0x09] /* 9 */, [0x0D00, 0x08] /* : */, [0x0180, 0x0B] /* ; */, - [0x8800, 0x05] /* < */, [0x3C00, 0x06] /* = */, [0x9000, 0x05] /* > */, - [0x0280, 0x0A] /* ? */, [0x00B4, 0x0E] /* @ */, [0x4000, 0x06] /* A */, - [0x1A00, 0x07] /* B */, [0x1C00, 0x07] /* C */, [0x1E00, 0x07] /* D */, - [0x4400, 0x06] /* E */, [0x2000, 0x07] /* F */, [0x2200, 0x07] /* G */, - [0x2400, 0x07] /* H */, [0x4800, 0x06] /* I */, [0x01A0, 0x0B] /* J */, - [0x02C0, 0x0A] /* K */, [0x2600, 0x07] /* L */, [0x0E00, 0x08] /* M */, - [0x4C00, 0x06] /* N */, [0x5000, 0x06] /* O */, [0x2800, 0x07] /* P */, - [0x00C0, 0x0C] /* Q */, [0x5400, 0x06] /* R */, [0x2A00, 0x07] /* S */, - [0x9800, 0x05] /* T */, [0x0800, 0x09] /* U */, [0x0880, 0x09] /* V */, - [0x0F00, 0x08] /* W */, [0x00D0, 0x0C] /* X */, [0x0300, 0x0A] /* Y */, - [0x0900, 0x09] /* Z */, [0x0019, 0x10] /* [ */, [0x001A, 0x10] /* \ */, - [0x001B, 0x10] /* ] */, [0x001C, 0x10] /* ^ */, [0x1000, 0x08] /* _ */, - [0x001D, 0x10] /* ` */, [0xA000, 0x05] /* a */, [0x2C00, 0x07] /* b */, - [0x5800, 0x06] /* c */, [0x5C00, 0x06] /* d */, [0xF000, 0x04] /* e */, - [0x2E00, 0x07] /* f */, [0x3000, 0x07] /* g */, [0x6000, 0x06] /* h */, - [0xA800, 0x05] /* i */, [0x01C0, 0x0B] /* j */, [0x1100, 0x08] /* k */, - [0x6400, 0x06] /* l */, [0x6800, 0x06] /* m */, [0xB000, 0x05] /* n */, - [0xB800, 0x05] /* o */, [0xC000, 0x05] /* p */, [0x01E0, 0x0B] /* q */, - [0xC800, 0x05] /* r */, [0xD000, 0x05] /* s */, [0xD800, 0x05] /* t */, - [0x3200, 0x07] /* u */, [0x1200, 0x08] /* v */, [0x6C00, 0x06] /* w */, - [0x0980, 0x09] /* x */, [0x1300, 0x08] /* y */, [0x0340, 0x0A] /* z */, - [0x00E0, 0x0C] /* { */, [0x00F0, 0x0C] /* | */, [0x0100, 0x0C] /* } */, - [0x0110, 0x0C] /* ~ */, [0x001E, 0x10] /* DEL */, [0x001F, 0x10] /* € */, - [0x0020, 0x10] /* */, [0x0021, 0x10] /* ‚ */, [0x0022, 0x10] /* ƒ */, - [0x0023, 0x10] /* „ */, [0x0024, 0x10] /* … */, [0x0025, 0x10] /* † */, - [0x0026, 0x10] /* ‡ */, [0x0027, 0x10] /* ˆ */, [0x0028, 0x10] /* ‰ */, - [0x0029, 0x10] /* Š */, [0x002A, 0x10] /* ‹ */, [0x002B, 0x10] /* Œ */, - [0x002C, 0x10] /* */, [0x002D, 0x10] /* Ž */, [0x002E, 0x10] /* */, - [0x002F, 0x10] /* */, [0x00A4, 0x0F] /* ‘ */, [0x00A6, 0x0F] /* ’ */, - [0x00A8, 0x0F] /* “ */, [0x0030, 0x10] /* ” */, [0x0031, 0x10] /* • */, - [0x0032, 0x10] /* – */, [0x0033, 0x10] /* — */, [0x0034, 0x10] /* ˜ */, - [0x0035, 0x10] /* ™ */, [0x0036, 0x10] /* š */, [0x0037, 0x10] /* › */, - [0x0038, 0x10] /* œ */, [0x0039, 0x10] /* */, [0x003A, 0x10] /* ž */, - [0x003B, 0x10] /* Ÿ */, [0x003C, 0x10] /* NBSP*/, [0x003D, 0x10] /* ¡ */, - [0x003E, 0x10] /* ¢ */, [0x003F, 0x10] /* £ */, [0x0040, 0x10] /* ¤ */, - [0x0041, 0x10] /* ¥ */, [0x0042, 0x10] /* ¦ */, [0x0043, 0x10] /* § */, - [0x0044, 0x10] /* ¨ */, [0x0045, 0x10] /* © */, [0x0046, 0x10] /* ª */, - [0x0047, 0x10] /* « */, [0x0048, 0x10] /* ¬ */, [0x0049, 0x10] /* SHY */, - [0x004A, 0x10] /* ® */, [0x004B, 0x10] /* ¯ */, [0x004C, 0x10] /* ° */, - [0x004D, 0x10] /* ± */, [0x004E, 0x10] /* ² */, [0x004F, 0x10] /* ³ */, - [0x0050, 0x10] /* ´ */, [0x0051, 0x10] /* µ */, [0x0052, 0x10] /* ¶ */, - [0x0053, 0x10] /* · */, [0x0054, 0x10] /* ¸ */, [0x0055, 0x10] /* ¹ */, - [0x0056, 0x10] /* º */, [0x0057, 0x10] /* » */, [0x0058, 0x10] /* ¼ */, - [0x0059, 0x10] /* ½ */, [0x005A, 0x10] /* ¾ */, [0x005B, 0x10] /* ¿ */, - [0x005C, 0x10] /* À */, [0x005D, 0x10] /* Á */, [0x005E, 0x10] /*  */, - [0x005F, 0x10] /* à */, [0x0060, 0x10] /* Ä */, [0x0061, 0x10] /* Å */, - [0x0062, 0x10] /* Æ */, [0x00AA, 0x0F] /* Ç */, [0x0063, 0x10] /* È */, - [0x0064, 0x10] /* É */, [0x0065, 0x10] /* Ê */, [0x0066, 0x10] /* Ë */, - [0x0067, 0x10] /* Ì */, [0x0068, 0x10] /* Í */, [0x0069, 0x10] /* Î */, - [0x006A, 0x10] /* Ï */, [0x006B, 0x10] /* Ð */, [0x006C, 0x10] /* Ñ */, - [0x006D, 0x10] /* Ò */, [0x006E, 0x10] /* Ó */, [0x006F, 0x10] /* Ô */, - [0x0070, 0x10] /* Õ */, [0x0071, 0x10] /* Ö */, [0x0072, 0x10] /* × */, - [0x0073, 0x10] /* Ø */, [0x0074, 0x10] /* Ù */, [0x0075, 0x10] /* Ú */, - [0x0076, 0x10] /* Û */, [0x0077, 0x10] /* Ü */, [0x0078, 0x10] /* Ý */, - [0x0079, 0x10] /* Þ */, [0x007A, 0x10] /* ß */, [0x007B, 0x10] /* à */, - [0x007C, 0x10] /* á */, [0x007D, 0x10] /* â */, [0x007E, 0x10] /* ã */, - [0x007F, 0x10] /* ä */, [0x0080, 0x10] /* å */, [0x0081, 0x10] /* æ */, - [0x0082, 0x10] /* ç */, [0x0083, 0x10] /* è */, [0x0084, 0x10] /* é */, - [0x0085, 0x10] /* ê */, [0x0086, 0x10] /* ë */, [0x0087, 0x10] /* ì */, - [0x0088, 0x10] /* í */, [0x0089, 0x10] /* î */, [0x008A, 0x10] /* ï */, - [0x008B, 0x10] /* ð */, [0x008C, 0x10] /* ñ */, [0x008D, 0x10] /* ò */, - [0x00AC, 0x0F] /* ó */, [0x008E, 0x10] /* ô */, [0x008F, 0x10] /* õ */, - [0x0090, 0x10] /* ö */, [0x0091, 0x10] /* ÷ */, [0x0092, 0x10] /* ø */, - [0x0093, 0x10] /* ù */, [0x00AE, 0x0F] /* ú */, [0x0094, 0x10] /* û */, - [0x0095, 0x10] /* ü */, [0x0096, 0x10] /* ý */, [0x0097, 0x10] /* þ */, - [0x0098, 0x10] /* ÿ */, [0x0099, 0x10] - ]; - - - /** - * This is the table that reduces the size based on repeated patterns in the file. - * - * When we find a byte match in the ring buffer we use this table to encode the length of the matched bytes. - * - * - These are intentionally 32-bit. The leftmost flag bit is 1 in each of these to tell the decoder to use match decoding. - * - LZP hash bits are used to encode the position where the matched bytes start. - * - We're allowed to match up to 298 bytes before we can't encode more (we need an entry in this table for each byte more). - * - We can reach for matches 65KB behind the current LZ cursor (65KB is the ring buffer size and highest a 16-bit hash can reach). - **/ - matchEncode = [ - /* [MATCH CODE, MATCH CODE BIT LENGTH] */ - [0x80000000, 0x01], [0x80000000, 0x03], - [0xA0000000, 0x03], [0xC0000000, 0x03], - [0xE0000000, 0x06], [0xE4000000, 0x06], - [0xE8000000, 0x06], [0xEC000000, 0x06], - [0xF0000000, 0x06], [0xF4000000, 0x06], - [0xF8000000, 0x06], [0xFC000000, 0x0B], - [0xFC200000, 0x0B], [0xFC400000, 0x0B], - [0xFC600000, 0x0B], [0xFC800000, 0x0B], - [0xFCA00000, 0x0B], [0xFCC00000, 0x0B], - [0xFCE00000, 0x0B], [0xFD000000, 0x0B], - [0xFD200000, 0x0B], [0xFD400000, 0x0B], - [0xFD600000, 0x0B], [0xFD800000, 0x0B], - [0xFDA00000, 0x0B], [0xFDC00000, 0x0B], - [0xFDE00000, 0x0B], [0xFE000000, 0x0B], - [0xFE200000, 0x0B], [0xFE400000, 0x0B], - [0xFE600000, 0x0B], [0xFE800000, 0x0B], - [0xFEA00000, 0x0B], [0xFEC00000, 0x0B], - [0xFEE00000, 0x0B], [0xFF000000, 0x0B], - [0xFF200000, 0x0B], [0xFF400000, 0x0B], - [0xFF600000, 0x0B], [0xFF800000, 0x0B], - [0xFFA00000, 0x0B], [0xFFC00000, 0x0B], - [0xFFE00000, 0x13], [0xFFE02000, 0x13], - [0xFFE04000, 0x13], [0xFFE06000, 0x13], - [0xFFE08000, 0x13], [0xFFE0A000, 0x13], - [0xFFE0C000, 0x13], [0xFFE0E000, 0x13], - [0xFFE10000, 0x13], [0xFFE12000, 0x13], - [0xFFE14000, 0x13], [0xFFE16000, 0x13], - [0xFFE18000, 0x13], [0xFFE1A000, 0x13], - [0xFFE1C000, 0x13], [0xFFE1E000, 0x13], - [0xFFE20000, 0x13], [0xFFE22000, 0x13], - [0xFFE24000, 0x13], [0xFFE26000, 0x13], - [0xFFE28000, 0x13], [0xFFE2A000, 0x13], - [0xFFE2C000, 0x13], [0xFFE2E000, 0x13], - [0xFFE30000, 0x13], [0xFFE32000, 0x13], - [0xFFE34000, 0x13], [0xFFE36000, 0x13], - [0xFFE38000, 0x13], [0xFFE3A000, 0x13], - [0xFFE3C000, 0x13], [0xFFE3E000, 0x13], - [0xFFE40000, 0x13], [0xFFE42000, 0x13], - [0xFFE44000, 0x13], [0xFFE46000, 0x13], - [0xFFE48000, 0x13], [0xFFE4A000, 0x13], - [0xFFE4C000, 0x13], [0xFFE4E000, 0x13], - [0xFFE50000, 0x13], [0xFFE52000, 0x13], - [0xFFE54000, 0x13], [0xFFE56000, 0x13], - [0xFFE58000, 0x13], [0xFFE5A000, 0x13], - [0xFFE5C000, 0x13], [0xFFE5E000, 0x13], - [0xFFE60000, 0x13], [0xFFE62000, 0x13], - [0xFFE64000, 0x13], [0xFFE66000, 0x13], - [0xFFE68000, 0x13], [0xFFE6A000, 0x13], - [0xFFE6C000, 0x13], [0xFFE6E000, 0x13], - [0xFFE70000, 0x13], [0xFFE72000, 0x13], - [0xFFE74000, 0x13], [0xFFE76000, 0x13], - [0xFFE78000, 0x13], [0xFFE7A000, 0x13], - [0xFFE7C000, 0x13], [0xFFE7E000, 0x13], - [0xFFE80000, 0x13], [0xFFE82000, 0x13], - [0xFFE84000, 0x13], [0xFFE86000, 0x13], - [0xFFE88000, 0x13], [0xFFE8A000, 0x13], - [0xFFE8C000, 0x13], [0xFFE8E000, 0x13], - [0xFFE90000, 0x13], [0xFFE92000, 0x13], - [0xFFE94000, 0x13], [0xFFE96000, 0x13], - [0xFFE98000, 0x13], [0xFFE9A000, 0x13], - [0xFFE9C000, 0x13], [0xFFE9E000, 0x13], - [0xFFEA0000, 0x13], [0xFFEA2000, 0x13], - [0xFFEA4000, 0x13], [0xFFEA6000, 0x13], - [0xFFEA8000, 0x13], [0xFFEAA000, 0x13], - [0xFFEAC000, 0x13], [0xFFEAE000, 0x13], - [0xFFEB0000, 0x13], [0xFFEB2000, 0x13], - [0xFFEB4000, 0x13], [0xFFEB6000, 0x13], - [0xFFEB8000, 0x13], [0xFFEBA000, 0x13], - [0xFFEBC000, 0x13], [0xFFEBE000, 0x13], - [0xFFEC0000, 0x13], [0xFFEC2000, 0x13], - [0xFFEC4000, 0x13], [0xFFEC6000, 0x13], - [0xFFEC8000, 0x13], [0xFFECA000, 0x13], - [0xFFECC000, 0x13], [0xFFECE000, 0x13], - [0xFFED0000, 0x13], [0xFFED2000, 0x13], - [0xFFED4000, 0x13], [0xFFED6000, 0x13], - [0xFFED8000, 0x13], [0xFFEDA000, 0x13], - [0xFFEDC000, 0x13], [0xFFEDE000, 0x13], - [0xFFEE0000, 0x13], [0xFFEE2000, 0x13], - [0xFFEE4000, 0x13], [0xFFEE6000, 0x13], - [0xFFEE8000, 0x13], [0xFFEEA000, 0x13], - [0xFFEEC000, 0x13], [0xFFEEE000, 0x13], - [0xFFEF0000, 0x13], [0xFFEF2000, 0x13], - [0xFFEF4000, 0x13], [0xFFEF6000, 0x13], - [0xFFEF8000, 0x13], [0xFFEFA000, 0x13], - [0xFFEFC000, 0x13], [0xFFEFE000, 0x13], - [0xFFF00000, 0x13], [0xFFF02000, 0x13], - [0xFFF04000, 0x13], [0xFFF06000, 0x13], - [0xFFF08000, 0x13], [0xFFF0A000, 0x13], - [0xFFF0C000, 0x13], [0xFFF0E000, 0x13], - [0xFFF10000, 0x13], [0xFFF12000, 0x13], - [0xFFF14000, 0x13], [0xFFF16000, 0x13], - [0xFFF18000, 0x13], [0xFFF1A000, 0x13], - [0xFFF1C000, 0x13], [0xFFF1E000, 0x13], - [0xFFF20000, 0x13], [0xFFF22000, 0x13], - [0xFFF24000, 0x13], [0xFFF26000, 0x13], - [0xFFF28000, 0x13], [0xFFF2A000, 0x13], - [0xFFF2C000, 0x13], [0xFFF2E000, 0x13], - [0xFFF30000, 0x13], [0xFFF32000, 0x13], - [0xFFF34000, 0x13], [0xFFF36000, 0x13], - [0xFFF38000, 0x13], [0xFFF3A000, 0x13], - [0xFFF3C000, 0x13], [0xFFF3E000, 0x13], - [0xFFF40000, 0x13], [0xFFF42000, 0x13], - [0xFFF44000, 0x13], [0xFFF46000, 0x13], - [0xFFF48000, 0x13], [0xFFF4A000, 0x13], - [0xFFF4C000, 0x13], [0xFFF4E000, 0x13], - [0xFFF50000, 0x13], [0xFFF52000, 0x13], - [0xFFF54000, 0x13], [0xFFF56000, 0x13], - [0xFFF58000, 0x13], [0xFFF5A000, 0x13], - [0xFFF5C000, 0x13], [0xFFF5E000, 0x13], - [0xFFF60000, 0x13], [0xFFF62000, 0x13], - [0xFFF64000, 0x13], [0xFFF66000, 0x13], - [0xFFF68000, 0x13], [0xFFF6A000, 0x13], - [0xFFF6C000, 0x13], [0xFFF6E000, 0x13], - [0xFFF70000, 0x13], [0xFFF72000, 0x13], - [0xFFF74000, 0x13], [0xFFF76000, 0x13], - [0xFFF78000, 0x13], [0xFFF7A000, 0x13], - [0xFFF7C000, 0x13], [0xFFF7E000, 0x13], - [0xFFF80000, 0x13], [0xFFF82000, 0x13], - [0xFFF84000, 0x13], [0xFFF86000, 0x13], - [0xFFF88000, 0x13], [0xFFF8A000, 0x13], - [0xFFF8C000, 0x13], [0xFFF8E000, 0x13], - [0xFFF90000, 0x13], [0xFFF92000, 0x13], - [0xFFF94000, 0x13], [0xFFF96000, 0x13], - [0xFFF98000, 0x13], [0xFFF9A000, 0x13], - [0xFFF9C000, 0x13], [0xFFF9E000, 0x13], - [0xFFFA0000, 0x13], [0xFFFA2000, 0x13], - [0xFFFA4000, 0x13], [0xFFFA6000, 0x13], - [0xFFFA8000, 0x13], [0xFFFAA000, 0x13], - [0xFFFAC000, 0x13], [0xFFFAE000, 0x13], - [0xFFFB0000, 0x13], [0xFFFB2000, 0x13], - [0xFFFB4000, 0x13], [0xFFFB6000, 0x13], - [0xFFFB8000, 0x13], [0xFFFBA000, 0x13], - [0xFFFBC000, 0x13], [0xFFFBE000, 0x13], - [0xFFFC0000, 0x13], [0xFFFC2000, 0x13], - [0xFFFC4000, 0x13], [0xFFFC6000, 0x13], - [0xFFFC8000, 0x13], [0xFFFCA000, 0x13], - [0xFFFCC000, 0x13], [0xFFFCE000, 0x13], - [0xFFFD0000, 0x13], [0xFFFD2000, 0x13], - [0xFFFD4000, 0x13], [0xFFFD6000, 0x13], - [0xFFFD8000, 0x13], [0xFFFDA000, 0x13], - [0xFFFDC000, 0x13], [0xFFFDE000, 0x13], - [0xFFFE0000, 0x13], [0xFFFE2000, 0x13], - [0xFFFE4000, 0x13], [0xFFFE6000, 0x13], - [0xFFFE8000, 0x13], [0xFFFEA000, 0x13], - [0xFFFEC000, 0x13], [0xFFFEE000, 0x13], - [0xFFFF0000, 0x13], [0xFFFF2000, 0x13], - [0xFFFF4000, 0x13], [0xFFFF6000, 0x13], - [0xFFFF8000, 0x13], [0xFFFFA000, 0x13], - [0xFFFFC000, 0x13], [0xFFFFE000, 0x13], - // We never should select these. These were in the original executable so including them here. - [0x00000000, 0x00], [0x00000000, 0x00] - ]; - - /** - * Initialize the Lzpf class. - * - * @returns {undefined} - */ - constructor() { - this.reset(); - } - - /** - * Sets starting values for the compression algorithm. - * - * @returns {undefined} - */ - reset() { - this.current_bit_length = 0; - this.current_bits = 0; - this.ring_bufer_index = 0xFFFF; - this.working_data = 0; - this.match_index = 0; - this.compression_mode = 0; - this.checksum = 0; - this.ring_buffer.fill(this.filler_byte, 0, 0x2000) - this.hash_table.fill(0xFFFF, 0, 0x1000); - this.encoded_data = []; - } - - /** - * Appends a byte to the end of the compressed byte array. Re-allocates as needed - * - * @param byte {Number} char code of the byte to be added. - * - * @returns {undefined} - */ - AddByte(byte) { - this.encoded_data.push(byte); - } - - /** - * Add bits onto the compressed bit stream. - * - * When we reach 8 bits we push a byte onto the compressed byte array. - * - * @param bits {Number} bits to add - * @param bit_length {Number} bit length - * - * @returns {undefined} - */ - AddBits(bits, bit_length) { - this.current_bits |= bits >>> (this.current_bit_length & 0x1F); - this.current_bit_length += bit_length; - - while (this.current_bit_length > 7) { - this.AddByte((this.current_bits >>> 0x18) & 0xFF); - - this.current_bit_length -= 8; - this.current_bits = (this.current_bits << 8) & 0xFFFFFFFF; - } - } - - /** - * Starts a compression stream - * - * @returns {undefined} Lzpf compression data - */ - Begin() { - this.reset(); - } - - /** - * Encode a block of data. Used for streamed chunks. - * - * @param unencoded_data {Buffer} data to encode - * @param compress_data {Boolean} compress data - * - * @returns {Buffer} Lzpf encoded data - */ - EncodeBlock(unencoded_data, compress_data) { - this.encoded_data = []; - var uncompressed_len = unencoded_data.byteLength; - - var i = 0; - var hash_index = 0; - while (i < uncompressed_len) { - var code_length = -1; - var code = -1; - - var byte = unencoded_data.readUInt8(i); - this.ring_buffer[i & 0x1FFF] = byte; - - if (this.match_index > 0) { - // Cozy time - if (byte != this.ring_buffer[this.ring_bufer_index] || this.match_index > 0x0127) { - // End of matching. Either we no longer match or we reached out limit. - code_length = this.matchEncode[this.match_index][1]; - code = this.matchEncode[this.match_index][0]; - this.match_index = 0; - this.compression_mode = 3; - } else { - // Previous iteration found a match so we continue matching until we can't. - this.match_index = (this.match_index + 1) & 0x1FFF; - this.ring_bufer_index = (this.ring_bufer_index + 1) & 0x1FFF; - this.checksum = (this.checksum + byte) & 0xFFFF; - this.working_data = ((this.working_data * 0x0100) + byte) & 0xFFFFFFFF; - i++; - } - } else { - this.ring_bufer_index = 0xFFFF; - - if (i >= 3) { - // Start recoding data so we can lookup matches. - hash_index = (this.working_data >>> 0x0B ^ this.working_data) & 0x0FFF; - this.ring_bufer_index = this.hash_table[hash_index]; - this.hash_table[hash_index] = i & 0x1FFF; - } else { - // The first three uncompressed bytes aren't used for the matching algorithm. - this.compression_mode++; - } - - if (this.ring_bufer_index == 0xFFFF) { - // We never seen this byte before so we encode it with our Huffman table. - code_length = this.nomatchEncode[byte][1]; - code = this.nomatchEncode[byte][0] << 0x10; - } else if (byte == this.ring_buffer[this.ring_bufer_index] && compress_data) { - // Wow dude, a match has been found. Let's switch get our own room in the next iteration to see if we match further. - this.match_index = 1; - this.ring_bufer_index = (this.ring_bufer_index + 1) & 0x1FFF; - this.compression_mode = 4; - } else { - // We've seen these bytes before but the index in the ring buffer doesn't match so we revert to our neat Huffman table - // We add 1 flag bit of 0 to account for the fact we've had a hash table hit but no hit in the ring buffer. - code_length = this.nomatchEncode[byte][1] + 1; - code = this.nomatchEncode[byte][0] << 0x0F; - } - - this.checksum = (this.checksum + byte) & 0xFFFF; - // We work on a 2-byte context so we store the last two bytes so we can do cool lookups with it - this.working_data = ((this.working_data * 0x0100) + byte) & 0xFFFFFFFF; - i++; - } - - if (code_length > 0) { - this.AddBits(code, code_length); - } - } - } - - /** - * Ends a compression stream. - * - * @param compression_mode {Number} the end type used to finalize - * - * @returns {Buffer} Lzpf compression data - */ - Finish() { - var code_length = -1; - var code = -1; - - if (this.compression_mode == 2) { - this.AddBits(0x00990000, 0x10); - } else if (this.compression_mode >= 3) { - if (this.compression_mode == 4) { - code_length = this.matchEncode[this.match_index][1]; - code = this.matchEncode[this.match_index][0]; - this.AddBits(code, code_length); - } - - var hash_index = (this.working_data >>> 0x0B ^ this.working_data) & 0x0FFF; - var ring_bufer_index = this.hash_table[hash_index]; - if (ring_bufer_index == 0xFFFF) { - this.AddBits(0x00990000, 0x10); - } else { - this.AddBits(0x004C8000, 0x11); - } - } - - // Add checksum bits - this.AddBits((this.checksum << 0x10) & 0xFFFFFFFF, 0x08); - this.AddBits((this.checksum << 0x18) & 0xFFFFFFFF, 0x08); - - // If we have leftover bits then add it. - if (this.current_bit_length > 0) { - this.AddByte((this.current_bits >>> 0x18) & 0xFF); - } - - this.AddByte(this.filler_byte); - - return Buffer.from(this.encoded_data); - } - - /** - * Converts the data to a Javascript Buffer object - * - * @param data {String|Buffer} Data to convert - * - * @returns {Buffer} Javascript Buffer object - */ - ConvertToBuffer(data) { - data = new Buffer.from(data.toString('binary')); - return data; - } - - /** - * Compress data using WebTV's Lzpf compression algorithm and adds the footer to the end. - * - * @param uncompressed_data {String|Buffer} data to compress - * - * @returns {Buffer} Lzpf compression data - */ - Compress(uncompressed_data) { - uncompressed_data = this.ConvertToBuffer(uncompressed_data); - this.Begin(); - this.EncodeBlock(uncompressed_data, true); - return this.Finish(); - } -} - -module.exports = WTVLzpf; diff --git a/zefie_wtvp_minisrv/includes/classes/WTVMime.js b/zefie_wtvp_minisrv/includes/classes/WTVMime.js index 3f6bf5e6..30658099 100644 --- a/zefie_wtvp_minisrv/includes/classes/WTVMime.js +++ b/zefie_wtvp_minisrv/includes/classes/WTVMime.js @@ -64,7 +64,7 @@ class WTVMime { // should we bother to compress? var content_type = ""; if (typeof (headers_obj) == 'string') content_type = headers_obj; - else content_type = (typeof (headers_obj["wtv-modern-content-type"]) != 'undefined') ? headers_obj["wtv-modern-content-type"] : headers_obj["Content-Type"]; + else content_type = (typeof (headers_obj["wtv-modern-content-type"]) != 'undefined') ? headers_obj["wtv-modern-content-type"] : headers_obj["Content-type"]; if (content_type) { // both lzpf and gzip diff --git a/zefie_wtvp_minisrv/test_lzpf.js b/zefie_wtvp_minisrv/test_lzpf.js index f171bb85..00054001 100644 --- a/zefie_wtvp_minisrv/test_lzpf.js +++ b/zefie_wtvp_minisrv/test_lzpf.js @@ -1,17 +1,28 @@ -const LZPF = require("./includes/classes/WTVLzpf.js") +const LZPF = require("./includes/classes/LZPF.js") +const LZPF2 = require("./includes/classes/WTVLzpf.js"); const lzpf = new LZPF(); +const lzpf2 = new LZPF2(); const testString = "This is a test string to compress and decompress"; // Compress -const compressed = lzpf.Compress(testString); +const compressed = lzpf.compress(testString); console.log("Original data:", testString); -console.log("Compressed data (hex):", compressed.toString('hex')); +console.log("Compressed data (hex) :", compressed.toString('hex')); + +// compress with LZPF2 +const compressed2 = lzpf2.Compress(testString); +console.log("Compressed data with LZPF2 (hex):", compressed2.toString('hex')); + // Decompress with diagnostics -const decompressed = lzpf.Decompress(compressed); +const decompressed = lzpf.expand(compressed); console.log("Decompressed:", decompressed.toString()); +// Decompress LZPF2 +const decompressed2 = lzpf.expand(compressed2); +console.log("Decompressed LZPF2:", decompressed2.toString()); + // Compare console.log("Original length:", testString.length); console.log("Decompressed length:", decompressed.length);