feat(classes.smartarchive): Support URL streams, recursive archive unpacking and filesystem export; improve ZIP/GZIP/BZIP2 robustness; CI and package metadata updates
This commit is contained in:
		| @@ -3,6 +3,6 @@ | ||||
|  */ | ||||
| export const commitinfo = { | ||||
|   name: '@push.rocks/smartarchive', | ||||
|   version: '4.1.0', | ||||
|   version: '4.2.0', | ||||
|   description: 'A library for working with archive files, providing utilities for compressing and decompressing data.' | ||||
| } | ||||
|   | ||||
| @@ -1,41 +1,44 @@ | ||||
| var BITMASK = [0, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F, 0xFF]; | ||||
| var BITMASK = [0, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff]; | ||||
|  | ||||
| // returns a function that reads bits. | ||||
| // takes a buffer iterator as input | ||||
| export function bitIterator(nextBuffer: () => Buffer) { | ||||
|     var bit = 0, byte = 0; | ||||
|     var bytes = nextBuffer(); | ||||
|     var f = function(n) { | ||||
|         if (n === null && bit != 0) {  // align to byte boundary | ||||
|             bit = 0 | ||||
|             byte++; | ||||
|             return; | ||||
|         } | ||||
|         var result = 0; | ||||
|         while(n > 0) { | ||||
|             if (byte >= bytes.length) { | ||||
|                 byte = 0; | ||||
|                 bytes = nextBuffer(); | ||||
|             } | ||||
|             var left = 8 - bit; | ||||
|             if (bit === 0 && n > 0) | ||||
|                 // @ts-ignore | ||||
|                 f.bytesRead++; | ||||
|             if (n >= left) { | ||||
|                 result <<= left; | ||||
|                 result |= (BITMASK[left] & bytes[byte++]); | ||||
|                 bit = 0; | ||||
|                 n -= left; | ||||
|             } else { | ||||
|                 result <<= n; | ||||
|                 result |= ((bytes[byte] & (BITMASK[n] << (8 - n - bit))) >> (8 - n - bit)); | ||||
|                 bit += n; | ||||
|                 n = 0; | ||||
|             } | ||||
|         } | ||||
|         return result; | ||||
|     }; | ||||
|     // @ts-ignore | ||||
|     f.bytesRead = 0; | ||||
|     return f; | ||||
| }; | ||||
|   var bit = 0, | ||||
|     byte = 0; | ||||
|   var bytes = nextBuffer(); | ||||
|   var f = function (n) { | ||||
|     if (n === null && bit != 0) { | ||||
|       // align to byte boundary | ||||
|       bit = 0; | ||||
|       byte++; | ||||
|       return; | ||||
|     } | ||||
|     var result = 0; | ||||
|     while (n > 0) { | ||||
|       if (byte >= bytes.length) { | ||||
|         byte = 0; | ||||
|         bytes = nextBuffer(); | ||||
|       } | ||||
|       var left = 8 - bit; | ||||
|       if (bit === 0 && n > 0) | ||||
|         // @ts-ignore | ||||
|         f.bytesRead++; | ||||
|       if (n >= left) { | ||||
|         result <<= left; | ||||
|         result |= BITMASK[left] & bytes[byte++]; | ||||
|         bit = 0; | ||||
|         n -= left; | ||||
|       } else { | ||||
|         result <<= n; | ||||
|         result |= | ||||
|           (bytes[byte] & (BITMASK[n] << (8 - n - bit))) >> (8 - n - bit); | ||||
|         bit += n; | ||||
|         n = 0; | ||||
|       } | ||||
|     } | ||||
|     return result; | ||||
|   }; | ||||
|   // @ts-ignore | ||||
|   f.bytesRead = 0; | ||||
|   return f; | ||||
| } | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| export class Bzip2Error extends Error { | ||||
|   public name: string = 'Bzip2Error'; | ||||
|   public message: string; | ||||
|   public stack = (new Error()).stack; | ||||
|   public stack = new Error().stack; | ||||
|  | ||||
|   constructor(messageArg: string) { | ||||
|     super(); | ||||
| @@ -10,326 +10,322 @@ export class Bzip2Error extends Error { | ||||
| } | ||||
|  | ||||
| var messageArg = { | ||||
|   Error: function(message) {throw new Bzip2Error(message);} | ||||
|   Error: function (message) { | ||||
|     throw new Bzip2Error(message); | ||||
|   }, | ||||
| }; | ||||
|  | ||||
| export class Bzip2 { | ||||
|   public Bzip2Error = Bzip2Error; | ||||
|   public crcTable = | ||||
|   [ | ||||
|    0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, | ||||
|    0x130476dc, 0x17c56b6b, 0x1a864db2, 0x1e475005, | ||||
|    0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61, | ||||
|    0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, | ||||
|    0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9, | ||||
|    0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75, | ||||
|    0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, | ||||
|    0x791d4014, 0x7ddc5da3, 0x709f7b7a, 0x745e66cd, | ||||
|    0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039, | ||||
|    0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, | ||||
|    0xbe2b5b58, 0xbaea46ef, 0xb7a96036, 0xb3687d81, | ||||
|    0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d, | ||||
|    0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, | ||||
|    0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95, | ||||
|    0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, | ||||
|    0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, | ||||
|    0x34867077, 0x30476dc0, 0x3d044b19, 0x39c556ae, | ||||
|    0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072, | ||||
|    0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, | ||||
|    0x018aeb13, 0x054bf6a4, 0x0808d07d, 0x0cc9cdca, | ||||
|    0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde, | ||||
|    0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, | ||||
|    0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1, 0x53dc6066, | ||||
|    0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba, | ||||
|    0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, | ||||
|    0xbfa1b04b, 0xbb60adfc, 0xb6238b25, 0xb2e29692, | ||||
|    0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6, | ||||
|    0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, | ||||
|    0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e, | ||||
|    0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2, | ||||
|    0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, | ||||
|    0xd5b88683, 0xd1799b34, 0xdc3abded, 0xd8fba05a, | ||||
|    0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637, | ||||
|    0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, | ||||
|    0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f, | ||||
|    0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53, | ||||
|    0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, | ||||
|    0x36194d42, 0x32d850f5, 0x3f9b762c, 0x3b5a6b9b, | ||||
|    0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff, | ||||
|    0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, | ||||
|    0xf12f560e, 0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7, | ||||
|    0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b, | ||||
|    0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, | ||||
|    0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3, | ||||
|    0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7, | ||||
|    0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, | ||||
|    0x9b3660c6, 0x9ff77d71, 0x92b45ba8, 0x9675461f, | ||||
|    0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3, | ||||
|    0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, | ||||
|    0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c, | ||||
|    0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8, | ||||
|    0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, | ||||
|    0x119b4be9, 0x155a565e, 0x18197087, 0x1cd86d30, | ||||
|    0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec, | ||||
|    0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, | ||||
|    0x2497d08d, 0x2056cd3a, 0x2d15ebe3, 0x29d4f654, | ||||
|    0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0, | ||||
|    0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, | ||||
|    0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18, | ||||
|    0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4, | ||||
|    0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, | ||||
|    0x9abc8bd5, 0x9e7d9662, 0x933eb0bb, 0x97ffad0c, | ||||
|    0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668, | ||||
|    0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4 | ||||
|   public crcTable = [ | ||||
|     0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b, | ||||
|     0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61, | ||||
|     0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, 0x4c11db70, 0x48d0c6c7, | ||||
|     0x4593e01e, 0x4152fda9, 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75, | ||||
|     0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3, | ||||
|     0x709f7b7a, 0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039, | ||||
|     0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58, 0xbaea46ef, | ||||
|     0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d, | ||||
|     0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb, | ||||
|     0xceb42022, 0xca753d95, 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, | ||||
|     0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0, | ||||
|     0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072, | ||||
|     0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x018aeb13, 0x054bf6a4, | ||||
|     0x0808d07d, 0x0cc9cdca, 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde, | ||||
|     0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08, | ||||
|     0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba, | ||||
|     0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc, | ||||
|     0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6, | ||||
|     0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, 0xe0b41de7, 0xe4750050, | ||||
|     0xe9362689, 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2, | ||||
|     0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34, | ||||
|     0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637, | ||||
|     0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, 0x4f040d56, 0x4bc510e1, | ||||
|     0x46863638, 0x42472b8f, 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53, | ||||
|     0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5, | ||||
|     0x3f9b762c, 0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff, | ||||
|     0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e, 0xf5ee4bb9, | ||||
|     0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b, | ||||
|     0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd, | ||||
|     0xcda1f604, 0xc960ebb3, 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7, | ||||
|     0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71, | ||||
|     0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3, | ||||
|     0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2, | ||||
|     0x470cdd2b, 0x43cdc09c, 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8, | ||||
|     0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e, | ||||
|     0x18197087, 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec, | ||||
|     0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a, | ||||
|     0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0, | ||||
|     0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, 0xe3a1cbc1, 0xe760d676, | ||||
|     0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4, | ||||
|     0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662, | ||||
|     0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668, | ||||
|     0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4, | ||||
|   ]; | ||||
|  | ||||
|   array = function(bytes) { | ||||
|     var bit = 0, byte = 0; | ||||
|     var BITMASK = [0, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F, 0xFF ]; | ||||
|     return function(n) { | ||||
|         var result = 0; | ||||
|         while(n > 0) { | ||||
|             var left = 8 - bit; | ||||
|             if (n >= left) { | ||||
|                 result <<= left; | ||||
|                 result |= (BITMASK[left] & bytes[byte++]); | ||||
|                 bit = 0; | ||||
|                 n -= left; | ||||
|             } else { | ||||
|                 result <<= n; | ||||
|                 result |= ((bytes[byte] & (BITMASK[n] << (8 - n - bit))) >> (8 - n - bit)); | ||||
|                 bit += n; | ||||
|                 n = 0; | ||||
|             } | ||||
|   array = function (bytes) { | ||||
|     var bit = 0, | ||||
|       byte = 0; | ||||
|     var BITMASK = [0, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff]; | ||||
|     return function (n) { | ||||
|       var result = 0; | ||||
|       while (n > 0) { | ||||
|         var left = 8 - bit; | ||||
|         if (n >= left) { | ||||
|           result <<= left; | ||||
|           result |= BITMASK[left] & bytes[byte++]; | ||||
|           bit = 0; | ||||
|           n -= left; | ||||
|         } else { | ||||
|           result <<= n; | ||||
|           result |= | ||||
|             (bytes[byte] & (BITMASK[n] << (8 - n - bit))) >> (8 - n - bit); | ||||
|           bit += n; | ||||
|           n = 0; | ||||
|         } | ||||
|         return result; | ||||
|     } | ||||
|   } | ||||
|       } | ||||
|       return result; | ||||
|     }; | ||||
|   }; | ||||
|  | ||||
|   simple = function(srcbuffer, stream) { | ||||
|   simple = function (srcbuffer, stream) { | ||||
|     var bits = this.array(srcbuffer); | ||||
|     var size = this.header(bits); | ||||
|     var ret = false; | ||||
|     var bufsize = 100000 * size; | ||||
|     var buf = new Int32Array(bufsize); | ||||
|      | ||||
|     do { | ||||
|         ret = this.decompress(bits, stream, buf, bufsize);         | ||||
|     } while(!ret); | ||||
|   } | ||||
|  | ||||
|   header = function(bits) { | ||||
|     do { | ||||
|       ret = this.decompress(bits, stream, buf, bufsize); | ||||
|     } while (!ret); | ||||
|   }; | ||||
|  | ||||
|   header = function (bits) { | ||||
|     this.byteCount = new Int32Array(256); | ||||
|     this.symToByte = new Uint8Array(256); | ||||
|     this.mtfSymbol = new Int32Array(256); | ||||
|     this.selectors = new Uint8Array(0x8000); | ||||
|    | ||||
|     if (bits(8*3) != 4348520) messageArg.Error("No magic number found"); | ||||
|    | ||||
|  | ||||
|     if (bits(8 * 3) != 4348520) messageArg.Error('No magic number found'); | ||||
|  | ||||
|     var i = bits(8) - 48; | ||||
|     if (i < 1 || i > 9) messageArg.Error("Not a BZIP archive"); | ||||
|     if (i < 1 || i > 9) messageArg.Error('Not a BZIP archive'); | ||||
|     return i; | ||||
|   }; | ||||
|  | ||||
|   decompress = function(bits, stream, buf, bufsize, streamCRC) { | ||||
|   decompress = function (bits, stream, buf, bufsize, streamCRC) { | ||||
|     var MAX_HUFCODE_BITS = 20; | ||||
|     var MAX_SYMBOLS = 258; | ||||
|     var SYMBOL_RUNA = 0; | ||||
|     var SYMBOL_RUNB = 1; | ||||
|     var GROUP_SIZE = 50; | ||||
|     var crc = 0 ^ (-1); | ||||
|      | ||||
|     for(var h = '', i = 0; i < 6; i++) h += bits(8).toString(16); | ||||
|     if (h == "177245385090") { | ||||
|       var finalCRC = bits(32)|0; | ||||
|       if (finalCRC !== streamCRC) messageArg.Error("Error in bzip2: crc32 do not match"); | ||||
|     var crc = 0 ^ -1; | ||||
|  | ||||
|     for (var h = '', i = 0; i < 6; i++) h += bits(8).toString(16); | ||||
|     if (h == '177245385090') { | ||||
|       var finalCRC = bits(32) | 0; | ||||
|       if (finalCRC !== streamCRC) | ||||
|         messageArg.Error('Error in bzip2: crc32 do not match'); | ||||
|       // align stream to byte | ||||
|       bits(null); | ||||
|       return null; // reset streamCRC for next call | ||||
|     } | ||||
|     if (h != "314159265359") messageArg.Error("eek not valid bzip data"); | ||||
|     var crcblock = bits(32)|0; // CRC code | ||||
|     if (bits(1)) messageArg.Error("unsupported obsolete version"); | ||||
|     if (h != '314159265359') messageArg.Error('eek not valid bzip data'); | ||||
|     var crcblock = bits(32) | 0; // CRC code | ||||
|     if (bits(1)) messageArg.Error('unsupported obsolete version'); | ||||
|     var origPtr = bits(24); | ||||
|     if (origPtr > bufsize) messageArg.Error("Initial position larger than buffer size"); | ||||
|     if (origPtr > bufsize) | ||||
|       messageArg.Error('Initial position larger than buffer size'); | ||||
|     var t = bits(16); | ||||
|     var symTotal = 0; | ||||
|     for (i = 0; i < 16; i++) { | ||||
|         if (t & (1 << (15 - i))) { | ||||
|             var k = bits(16); | ||||
|             for(j = 0; j < 16; j++) { | ||||
|                 if (k & (1 << (15 - j))) { | ||||
|                     this.symToByte[symTotal++] = (16 * i) + j; | ||||
|                 } | ||||
|             } | ||||
|       if (t & (1 << (15 - i))) { | ||||
|         var k = bits(16); | ||||
|         for (j = 0; j < 16; j++) { | ||||
|           if (k & (1 << (15 - j))) { | ||||
|             this.symToByte[symTotal++] = 16 * i + j; | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|    | ||||
|  | ||||
|     var groupCount = bits(3); | ||||
|     if (groupCount < 2 || groupCount > 6) messageArg.Error("another error"); | ||||
|     if (groupCount < 2 || groupCount > 6) messageArg.Error('another error'); | ||||
|     var nSelectors = bits(15); | ||||
|     if (nSelectors == 0) messageArg.Error("meh"); | ||||
|     for(var i = 0; i < groupCount; i++) this.mtfSymbol[i] = i; | ||||
|    | ||||
|     for(var i = 0; i < nSelectors; i++) { | ||||
|         for(var j = 0; bits(1); j++) if (j >= groupCount) messageArg.Error("whoops another error"); | ||||
|         var uc = this.mtfSymbol[j]; | ||||
|         for(var k: any = j-1; k>=0; k--) { | ||||
|             this.mtfSymbol[k+1] = this.mtfSymbol[k]; | ||||
|         } | ||||
|         this.mtfSymbol[0] = uc; | ||||
|         this.selectors[i] = uc; | ||||
|     if (nSelectors == 0) messageArg.Error('meh'); | ||||
|     for (var i = 0; i < groupCount; i++) this.mtfSymbol[i] = i; | ||||
|  | ||||
|     for (var i = 0; i < nSelectors; i++) { | ||||
|       for (var j = 0; bits(1); j++) | ||||
|         if (j >= groupCount) messageArg.Error('whoops another error'); | ||||
|       var uc = this.mtfSymbol[j]; | ||||
|       for (var k: any = j - 1; k >= 0; k--) { | ||||
|         this.mtfSymbol[k + 1] = this.mtfSymbol[k]; | ||||
|       } | ||||
|       this.mtfSymbol[0] = uc; | ||||
|       this.selectors[i] = uc; | ||||
|     } | ||||
|    | ||||
|  | ||||
|     var symCount = symTotal + 2; | ||||
|     var groups = []; | ||||
|     var length = new Uint8Array(MAX_SYMBOLS), | ||||
|     temp = new Uint16Array(MAX_HUFCODE_BITS+1); | ||||
|    | ||||
|       temp = new Uint16Array(MAX_HUFCODE_BITS + 1); | ||||
|  | ||||
|     var hufGroup; | ||||
|    | ||||
|     for(var j = 0; j < groupCount; j++) { | ||||
|         t = bits(5); //lengths | ||||
|         for(var i = 0; i < symCount; i++) { | ||||
|             while(true){ | ||||
|                 if (t < 1 || t > MAX_HUFCODE_BITS) messageArg.Error("I gave up a while ago on writing error messages"); | ||||
|                 if (!bits(1)) break; | ||||
|                 if (!bits(1)) t++; | ||||
|                 else t--; | ||||
|             } | ||||
|             length[i] = t; | ||||
|  | ||||
|     for (var j = 0; j < groupCount; j++) { | ||||
|       t = bits(5); //lengths | ||||
|       for (var i = 0; i < symCount; i++) { | ||||
|         while (true) { | ||||
|           if (t < 1 || t > MAX_HUFCODE_BITS) | ||||
|             messageArg.Error('I gave up a while ago on writing error messages'); | ||||
|           if (!bits(1)) break; | ||||
|           if (!bits(1)) t++; | ||||
|           else t--; | ||||
|         } | ||||
|         var  minLen,  maxLen; | ||||
|         minLen = maxLen = length[0]; | ||||
|         for(var i = 1; i < symCount; i++) { | ||||
|             if (length[i] > maxLen) maxLen = length[i]; | ||||
|             else if (length[i] < minLen) minLen = length[i]; | ||||
|         } | ||||
|         hufGroup = groups[j] = {}; | ||||
|         hufGroup.permute = new Int32Array(MAX_SYMBOLS); | ||||
|         hufGroup.limit = new Int32Array(MAX_HUFCODE_BITS + 1); | ||||
|         hufGroup.base = new Int32Array(MAX_HUFCODE_BITS + 1); | ||||
|    | ||||
|         hufGroup.minLen = minLen; | ||||
|         hufGroup.maxLen = maxLen; | ||||
|         var base = hufGroup.base; | ||||
|         var limit = hufGroup.limit; | ||||
|         var pp = 0; | ||||
|         for(var i: number = minLen; i <= maxLen; i++) | ||||
|         for(var t: any = 0; t < symCount; t++) | ||||
|         if (length[t] == i) hufGroup.permute[pp++] = t; | ||||
|         for(i = minLen; i <= maxLen; i++) temp[i] = limit[i] = 0; | ||||
|         for(i = 0; i < symCount; i++) temp[length[i]]++; | ||||
|         pp = t = 0; | ||||
|         for(i = minLen; i < maxLen; i++) { | ||||
|             pp += temp[i]; | ||||
|             limit[i] = pp - 1; | ||||
|             pp <<= 1; | ||||
|             base[i+1] = pp - (t += temp[i]); | ||||
|         } | ||||
|         limit[maxLen] = pp + temp[maxLen] - 1; | ||||
|         base[minLen] = 0; | ||||
|         length[i] = t; | ||||
|       } | ||||
|       var minLen, maxLen; | ||||
|       minLen = maxLen = length[0]; | ||||
|       for (var i = 1; i < symCount; i++) { | ||||
|         if (length[i] > maxLen) maxLen = length[i]; | ||||
|         else if (length[i] < minLen) minLen = length[i]; | ||||
|       } | ||||
|       hufGroup = groups[j] = {}; | ||||
|       hufGroup.permute = new Int32Array(MAX_SYMBOLS); | ||||
|       hufGroup.limit = new Int32Array(MAX_HUFCODE_BITS + 1); | ||||
|       hufGroup.base = new Int32Array(MAX_HUFCODE_BITS + 1); | ||||
|  | ||||
|       hufGroup.minLen = minLen; | ||||
|       hufGroup.maxLen = maxLen; | ||||
|       var base = hufGroup.base; | ||||
|       var limit = hufGroup.limit; | ||||
|       var pp = 0; | ||||
|       for (var i: number = minLen; i <= maxLen; i++) | ||||
|         for (var t: any = 0; t < symCount; t++) | ||||
|           if (length[t] == i) hufGroup.permute[pp++] = t; | ||||
|       for (i = minLen; i <= maxLen; i++) temp[i] = limit[i] = 0; | ||||
|       for (i = 0; i < symCount; i++) temp[length[i]]++; | ||||
|       pp = t = 0; | ||||
|       for (i = minLen; i < maxLen; i++) { | ||||
|         pp += temp[i]; | ||||
|         limit[i] = pp - 1; | ||||
|         pp <<= 1; | ||||
|         base[i + 1] = pp - (t += temp[i]); | ||||
|       } | ||||
|       limit[maxLen] = pp + temp[maxLen] - 1; | ||||
|       base[minLen] = 0; | ||||
|     } | ||||
|    | ||||
|     for(var i = 0; i < 256; i++) {  | ||||
|         this.mtfSymbol[i] = i; | ||||
|         this.byteCount[i] = 0; | ||||
|  | ||||
|     for (var i = 0; i < 256; i++) { | ||||
|       this.mtfSymbol[i] = i; | ||||
|       this.byteCount[i] = 0; | ||||
|     } | ||||
|     var runPos, count, symCount: number, selector; | ||||
|     runPos = count = symCount = selector = 0;     | ||||
|     while(true) { | ||||
|         if (!(symCount--)) { | ||||
|             symCount = GROUP_SIZE - 1; | ||||
|             if (selector >= nSelectors) messageArg.Error("meow i'm a kitty, that's an error"); | ||||
|             hufGroup = groups[this.selectors[selector++]]; | ||||
|             base = hufGroup.base; | ||||
|             limit = hufGroup.limit; | ||||
|     runPos = count = symCount = selector = 0; | ||||
|     while (true) { | ||||
|       if (!symCount--) { | ||||
|         symCount = GROUP_SIZE - 1; | ||||
|         if (selector >= nSelectors) | ||||
|           messageArg.Error("meow i'm a kitty, that's an error"); | ||||
|         hufGroup = groups[this.selectors[selector++]]; | ||||
|         base = hufGroup.base; | ||||
|         limit = hufGroup.limit; | ||||
|       } | ||||
|       i = hufGroup.minLen; | ||||
|       j = bits(i); | ||||
|       while (true) { | ||||
|         if (i > hufGroup.maxLen) messageArg.Error("rawr i'm a dinosaur"); | ||||
|         if (j <= limit[i]) break; | ||||
|         i++; | ||||
|         j = (j << 1) | bits(1); | ||||
|       } | ||||
|       j -= base[i]; | ||||
|       if (j < 0 || j >= MAX_SYMBOLS) messageArg.Error("moo i'm a cow"); | ||||
|       var nextSym = hufGroup.permute[j]; | ||||
|       if (nextSym == SYMBOL_RUNA || nextSym == SYMBOL_RUNB) { | ||||
|         if (!runPos) { | ||||
|           runPos = 1; | ||||
|           t = 0; | ||||
|         } | ||||
|         i = hufGroup.minLen; | ||||
|         j = bits(i); | ||||
|         while(true) { | ||||
|             if (i > hufGroup.maxLen) messageArg.Error("rawr i'm a dinosaur"); | ||||
|             if (j <= limit[i]) break; | ||||
|             i++; | ||||
|             j = (j << 1) | bits(1); | ||||
|         } | ||||
|         j -= base[i]; | ||||
|         if (j < 0 || j >= MAX_SYMBOLS) messageArg.Error("moo i'm a cow"); | ||||
|         var nextSym = hufGroup.permute[j]; | ||||
|         if (nextSym == SYMBOL_RUNA || nextSym == SYMBOL_RUNB) { | ||||
|             if (!runPos){ | ||||
|                 runPos = 1; | ||||
|                 t = 0; | ||||
|             } | ||||
|             if (nextSym == SYMBOL_RUNA) t += runPos; | ||||
|             else t += 2 * runPos; | ||||
|             runPos <<= 1; | ||||
|             continue; | ||||
|         } | ||||
|         if (runPos) { | ||||
|             runPos = 0; | ||||
|             if (count + t > bufsize) messageArg.Error("Boom."); | ||||
|             uc = this.symToByte[this.mtfSymbol[0]]; | ||||
|             this.byteCount[uc] += t; | ||||
|             while(t--) buf[count++] = uc; | ||||
|         } | ||||
|         if (nextSym > symTotal) break; | ||||
|         if (count >= bufsize) messageArg.Error("I can't think of anything. Error"); | ||||
|         i = nextSym - 1; | ||||
|         uc = this.mtfSymbol[i]; | ||||
|         for(var k: any = i-1; k>=0; k--) { | ||||
|             this.mtfSymbol[k+1] = this.mtfSymbol[k]; | ||||
|         } | ||||
|         this.mtfSymbol[0] = uc | ||||
|         uc = this.symToByte[uc]; | ||||
|         this.byteCount[uc]++; | ||||
|         buf[count++] = uc; | ||||
|         if (nextSym == SYMBOL_RUNA) t += runPos; | ||||
|         else t += 2 * runPos; | ||||
|         runPos <<= 1; | ||||
|         continue; | ||||
|       } | ||||
|       if (runPos) { | ||||
|         runPos = 0; | ||||
|         if (count + t > bufsize) messageArg.Error('Boom.'); | ||||
|         uc = this.symToByte[this.mtfSymbol[0]]; | ||||
|         this.byteCount[uc] += t; | ||||
|         while (t--) buf[count++] = uc; | ||||
|       } | ||||
|       if (nextSym > symTotal) break; | ||||
|       if (count >= bufsize) | ||||
|         messageArg.Error("I can't think of anything. Error"); | ||||
|       i = nextSym - 1; | ||||
|       uc = this.mtfSymbol[i]; | ||||
|       for (var k: any = i - 1; k >= 0; k--) { | ||||
|         this.mtfSymbol[k + 1] = this.mtfSymbol[k]; | ||||
|       } | ||||
|       this.mtfSymbol[0] = uc; | ||||
|       uc = this.symToByte[uc]; | ||||
|       this.byteCount[uc]++; | ||||
|       buf[count++] = uc; | ||||
|     } | ||||
|     if (origPtr < 0 || origPtr >= count) messageArg.Error("I'm a monkey and I'm throwing something at someone, namely you"); | ||||
|     if (origPtr < 0 || origPtr >= count) | ||||
|       messageArg.Error( | ||||
|         "I'm a monkey and I'm throwing something at someone, namely you", | ||||
|       ); | ||||
|     var j = 0; | ||||
|     for(var i = 0; i < 256; i++) { | ||||
|         k = j + this.byteCount[i]; | ||||
|         this.byteCount[i] = j; | ||||
|         j = k; | ||||
|     for (var i = 0; i < 256; i++) { | ||||
|       k = j + this.byteCount[i]; | ||||
|       this.byteCount[i] = j; | ||||
|       j = k; | ||||
|     } | ||||
|     for(var i = 0; i < count; i++) { | ||||
|         uc = buf[i] & 0xff; | ||||
|         buf[this.byteCount[uc]] |= (i << 8); | ||||
|         this.byteCount[uc]++; | ||||
|     for (var i = 0; i < count; i++) { | ||||
|       uc = buf[i] & 0xff; | ||||
|       buf[this.byteCount[uc]] |= i << 8; | ||||
|       this.byteCount[uc]++; | ||||
|     } | ||||
|     var pos = 0, current = 0, run = 0; | ||||
|     var pos = 0, | ||||
|       current = 0, | ||||
|       run = 0; | ||||
|     if (count) { | ||||
|         pos = buf[origPtr]; | ||||
|         current = (pos & 0xff); | ||||
|         pos >>= 8; | ||||
|         run = -1; | ||||
|       pos = buf[origPtr]; | ||||
|       current = pos & 0xff; | ||||
|       pos >>= 8; | ||||
|       run = -1; | ||||
|     } | ||||
|     count = count; | ||||
|     var copies, previous, outbyte; | ||||
|     while(count) { | ||||
|         count--; | ||||
|         previous = current; | ||||
|         pos = buf[pos]; | ||||
|         current = pos & 0xff; | ||||
|         pos >>= 8; | ||||
|         if (run++ == 3) { | ||||
|             copies = current; | ||||
|             outbyte = previous; | ||||
|             current = -1; | ||||
|         } else { | ||||
|             copies = 1; | ||||
|             outbyte = current; | ||||
|         } | ||||
|         while(copies--) { | ||||
|             crc = ((crc << 8) ^ this.crcTable[((crc>>24) ^ outbyte) & 0xFF])&0xFFFFFFFF; // crc32 | ||||
|             stream(outbyte); | ||||
|         } | ||||
|         if (current != previous) run = 0; | ||||
|     while (count) { | ||||
|       count--; | ||||
|       previous = current; | ||||
|       pos = buf[pos]; | ||||
|       current = pos & 0xff; | ||||
|       pos >>= 8; | ||||
|       if (run++ == 3) { | ||||
|         copies = current; | ||||
|         outbyte = previous; | ||||
|         current = -1; | ||||
|       } else { | ||||
|         copies = 1; | ||||
|         outbyte = current; | ||||
|       } | ||||
|       while (copies--) { | ||||
|         crc = | ||||
|           ((crc << 8) ^ this.crcTable[((crc >> 24) ^ outbyte) & 0xff]) & | ||||
|           0xffffffff; // crc32 | ||||
|         stream(outbyte); | ||||
|       } | ||||
|       if (current != previous) run = 0; | ||||
|     } | ||||
|    | ||||
|     crc = (crc ^ (-1)) >>> 0; | ||||
|     if ((crc|0) != (crcblock|0)) messageArg.Error("Error in bzip2: crc32 do not match"); | ||||
|     streamCRC = (crc ^ ((streamCRC << 1) | (streamCRC >>> 31))) & 0xFFFFFFFF; | ||||
|  | ||||
|     crc = (crc ^ -1) >>> 0; | ||||
|     if ((crc | 0) != (crcblock | 0)) | ||||
|       messageArg.Error('Error in bzip2: crc32 do not match'); | ||||
|     streamCRC = (crc ^ ((streamCRC << 1) | (streamCRC >>> 31))) & 0xffffffff; | ||||
|     return streamCRC; | ||||
|   }; | ||||
| }; | ||||
| } | ||||
|   | ||||
| @@ -26,7 +26,13 @@ export function unbzip2Stream() { | ||||
|         chunk.push(b); | ||||
|       }; | ||||
|  | ||||
|       streamCRC = bzip2Instance.decompress(bitReader, f, buf, bufsize, streamCRC); | ||||
|       streamCRC = bzip2Instance.decompress( | ||||
|         bitReader, | ||||
|         f, | ||||
|         buf, | ||||
|         bufsize, | ||||
|         streamCRC, | ||||
|       ); | ||||
|       if (streamCRC === null) { | ||||
|         // reset for next bzip2 header | ||||
|         blockSize = 0; | ||||
| @@ -66,7 +72,10 @@ export function unbzip2Stream() { | ||||
|           return bufferQueue.shift(); | ||||
|         }); | ||||
|       } | ||||
|       while (!broken && hasBytes - bitReader.bytesRead + 1 >= (25000 + 100000 * blockSize || 4)) { | ||||
|       while ( | ||||
|         !broken && | ||||
|         hasBytes - bitReader.bytesRead + 1 >= (25000 + 100000 * blockSize || 4) | ||||
|       ) { | ||||
|         //console.error('decompressing with', hasBytes - bitReader.bytesRead + 1, 'bytes in buffer'); | ||||
|         const result = await decompressAndPush(); | ||||
|         if (!result) { | ||||
| @@ -86,7 +95,8 @@ export function unbzip2Stream() { | ||||
|         await streamTools.push(result); | ||||
|       } | ||||
|       if (!broken) { | ||||
|         if (streamCRC !== null) this.emit('error', new Error('input stream ended prematurely')); | ||||
|         if (streamCRC !== null) | ||||
|           this.emit('error', new Error('input stream ended prematurely')); | ||||
|       } | ||||
|     }, | ||||
|   }); | ||||
|   | ||||
| @@ -5,7 +5,10 @@ export interface IAnalyzedResult { | ||||
|   fileType: plugins.fileType.FileTypeResult; | ||||
|   isArchive: boolean; | ||||
|   resultStream: plugins.smartstream.SmartDuplex; | ||||
|   decompressionStream: plugins.stream.Transform | plugins.stream.Duplex | plugins.tarStream.Extract; | ||||
|   decompressionStream: | ||||
|     | plugins.stream.Transform | ||||
|     | plugins.stream.Duplex | ||||
|     | plugins.tarStream.Extract; | ||||
| } | ||||
|  | ||||
| export class ArchiveAnalyzer { | ||||
| @@ -25,14 +28,15 @@ export class ArchiveAnalyzer { | ||||
|       'application/x-bzip2', | ||||
|       // Add other archive mime types here | ||||
|     ]); | ||||
|    | ||||
|  | ||||
|     return archiveMimeTypes.has(mimeType); | ||||
|   } | ||||
|  | ||||
|  | ||||
|   private async getDecompressionStream( | ||||
|     mimeTypeArg: plugins.fileType.FileTypeResult['mime'] | ||||
|   ):  Promise<plugins.stream.Transform | plugins.stream.Duplex | plugins.tarStream.Extract> { | ||||
|     mimeTypeArg: plugins.fileType.FileTypeResult['mime'], | ||||
|   ): Promise< | ||||
|     plugins.stream.Transform | plugins.stream.Duplex | plugins.tarStream.Extract | ||||
|   > { | ||||
|     switch (mimeTypeArg) { | ||||
|       case 'application/gzip': | ||||
|         return this.smartArchiveRef.gzipTools.getDecompressionStream(); | ||||
| @@ -51,13 +55,18 @@ export class ArchiveAnalyzer { | ||||
|   public getAnalyzedStream() { | ||||
|     let firstRun = true; | ||||
|     const resultStream = plugins.smartstream.createPassThrough(); | ||||
|     const analyzerstream = new plugins.smartstream.SmartDuplex<Buffer, IAnalyzedResult>({ | ||||
|     const analyzerstream = new plugins.smartstream.SmartDuplex< | ||||
|       Buffer, | ||||
|       IAnalyzedResult | ||||
|     >({ | ||||
|       readableObjectMode: true, | ||||
|       writeFunction: async (chunkArg: Buffer, streamtools) => { | ||||
|         if (firstRun) { | ||||
|           firstRun = false; | ||||
|           const fileType = await plugins.fileType.fileTypeFromBuffer(chunkArg); | ||||
|           const decompressionStream = await this.getDecompressionStream(fileType?.mime as any); | ||||
|           const decompressionStream = await this.getDecompressionStream( | ||||
|             fileType?.mime as any, | ||||
|           ); | ||||
|           /** | ||||
|            * analyzed stream emits once with this object | ||||
|            */ | ||||
| @@ -75,7 +84,7 @@ export class ArchiveAnalyzer { | ||||
|       finalFunction: async (tools) => { | ||||
|         resultStream.push(null); | ||||
|         return null; | ||||
|       } | ||||
|       }, | ||||
|     }); | ||||
|     return analyzerstream; | ||||
|   } | ||||
|   | ||||
| @@ -13,4 +13,4 @@ export class Bzip2Tools { | ||||
|   getDecompressionStream() { | ||||
|     return unbzip2Stream(); | ||||
|   } | ||||
| } | ||||
| } | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| import type { SmartArchive } from './classes.smartarchive.js'; | ||||
| import * as plugins from './plugins.js' | ||||
| import * as plugins from './plugins.js'; | ||||
|  | ||||
| // This class wraps fflate's gunzip in a Node.js Transform stream | ||||
| export class CompressGunzipTransform extends plugins.stream.Transform { | ||||
| @@ -7,7 +7,11 @@ export class CompressGunzipTransform extends plugins.stream.Transform { | ||||
|     super(); | ||||
|   } | ||||
|  | ||||
|   _transform(chunk: Buffer, encoding: BufferEncoding, callback: plugins.stream.TransformCallback) { | ||||
|   _transform( | ||||
|     chunk: Buffer, | ||||
|     encoding: BufferEncoding, | ||||
|     callback: plugins.stream.TransformCallback, | ||||
|   ) { | ||||
|     plugins.fflate.gunzip(chunk, (err, decompressed) => { | ||||
|       if (err) { | ||||
|         callback(err); | ||||
| @@ -26,7 +30,11 @@ export class DecompressGunzipTransform extends plugins.stream.Transform { | ||||
|     super(); | ||||
|   } | ||||
|  | ||||
|   _transform(chunk: Buffer, encoding: BufferEncoding, callback: plugins.stream.TransformCallback) { | ||||
|   _transform( | ||||
|     chunk: Buffer, | ||||
|     encoding: BufferEncoding, | ||||
|     callback: plugins.stream.TransformCallback, | ||||
|   ) { | ||||
|     // Use fflate's gunzip function to decompress the chunk | ||||
|     plugins.fflate.gunzip(chunk, (err, decompressed) => { | ||||
|       if (err) { | ||||
| @@ -41,10 +49,8 @@ export class DecompressGunzipTransform extends plugins.stream.Transform { | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| export class GzipTools { | ||||
|   constructor() { | ||||
|   } | ||||
|   constructor() {} | ||||
|  | ||||
|   public getCompressionStream() { | ||||
|     return new CompressGunzipTransform(); | ||||
|   | ||||
| @@ -6,7 +6,10 @@ import { GzipTools } from './classes.gziptools.js'; | ||||
| import { TarTools } from './classes.tartools.js'; | ||||
| import { ZipTools } from './classes.ziptools.js'; | ||||
|  | ||||
| import { ArchiveAnalyzer, type IAnalyzedResult } from './classes.archiveanalyzer.js'; | ||||
| import { | ||||
|   ArchiveAnalyzer, | ||||
|   type IAnalyzedResult, | ||||
| } from './classes.archiveanalyzer.js'; | ||||
|  | ||||
| import type { from } from '@push.rocks/smartrx/dist_ts/smartrx.plugins.rxjs.js'; | ||||
|  | ||||
| @@ -18,14 +21,19 @@ export class SmartArchive { | ||||
|     return smartArchiveInstance; | ||||
|   } | ||||
|  | ||||
|   public static async fromArchiveFile(filePathArg: string): Promise<SmartArchive> { | ||||
|   public static async fromArchiveFile( | ||||
|     filePathArg: string, | ||||
|   ): Promise<SmartArchive> { | ||||
|     const smartArchiveInstance = new SmartArchive(); | ||||
|     smartArchiveInstance.sourceFilePath = filePathArg; | ||||
|     return smartArchiveInstance; | ||||
|   } | ||||
|  | ||||
|   public static async fromArchiveStream( | ||||
|     streamArg: plugins.stream.Readable | plugins.stream.Duplex | plugins.stream.Transform | ||||
|     streamArg: | ||||
|       | plugins.stream.Readable | ||||
|       | plugins.stream.Duplex | ||||
|       | plugins.stream.Transform, | ||||
|   ): Promise<SmartArchive> { | ||||
|     const smartArchiveInstance = new SmartArchive(); | ||||
|     smartArchiveInstance.sourceStream = streamArg; | ||||
| @@ -41,13 +49,19 @@ export class SmartArchive { | ||||
|  | ||||
|   public sourceUrl: string; | ||||
|   public sourceFilePath: string; | ||||
|   public sourceStream: plugins.stream.Readable | plugins.stream.Duplex | plugins.stream.Transform; | ||||
|   public sourceStream: | ||||
|     | plugins.stream.Readable | ||||
|     | plugins.stream.Duplex | ||||
|     | plugins.stream.Transform; | ||||
|  | ||||
|   public archiveName: string; | ||||
|   public singleFileMode: boolean = false; | ||||
|  | ||||
|   public addedDirectories: string[] = []; | ||||
|   public addedFiles: (plugins.smartfile.SmartFile | plugins.smartfile.StreamFile)[] = []; | ||||
|   public addedFiles: ( | ||||
|     | plugins.smartfile.SmartFile | ||||
|     | plugins.smartfile.StreamFile | ||||
|   )[] = []; | ||||
|   public addedUrls: string[] = []; | ||||
|  | ||||
|   constructor() {} | ||||
| @@ -81,24 +95,35 @@ export class SmartArchive { | ||||
|     // return archiveStream; | ||||
|   } | ||||
|  | ||||
|   public async exportToFs(targetDir: string, fileNameArg?: string): Promise<void> { | ||||
|   public async exportToFs( | ||||
|     targetDir: string, | ||||
|     fileNameArg?: string, | ||||
|   ): Promise<void> { | ||||
|     const done = plugins.smartpromise.defer<void>(); | ||||
|     const streamFileStream = await this.exportToStreamOfStreamFiles(); | ||||
|     streamFileStream.pipe( | ||||
|       new plugins.smartstream.SmartDuplex({ | ||||
|         objectMode: true, | ||||
|         writeFunction: async (streamFileArg: plugins.smartfile.StreamFile, streamtools) => { | ||||
|         writeFunction: async ( | ||||
|           streamFileArg: plugins.smartfile.StreamFile, | ||||
|           streamtools, | ||||
|         ) => { | ||||
|           const done = plugins.smartpromise.defer<void>(); | ||||
|           console.log(streamFileArg.relativeFilePath ? streamFileArg.relativeFilePath : 'no relative path'); | ||||
|           console.log( | ||||
|             streamFileArg.relativeFilePath | ||||
|               ? streamFileArg.relativeFilePath | ||||
|               : 'no relative path', | ||||
|           ); | ||||
|           const streamFile = streamFileArg; | ||||
|           const readStream = await streamFile.createReadStream(); | ||||
|           await plugins.smartfile.fs.ensureDir(targetDir); | ||||
|           const writePath = plugins.path.join( | ||||
|             targetDir, | ||||
|             streamFile.relativeFilePath || fileNameArg | ||||
|             streamFile.relativeFilePath || fileNameArg, | ||||
|           ); | ||||
|           await plugins.smartfile.fs.ensureDir(plugins.path.dirname(writePath)); | ||||
|           const writeStream = plugins.smartfile.fsStream.createWriteStream(writePath); | ||||
|           const writeStream = | ||||
|             plugins.smartfile.fsStream.createWriteStream(writePath); | ||||
|           readStream.pipe(writeStream); | ||||
|           writeStream.on('finish', () => { | ||||
|             done.resolve(); | ||||
| @@ -108,15 +133,16 @@ export class SmartArchive { | ||||
|         finalFunction: async () => { | ||||
|           done.resolve(); | ||||
|         }, | ||||
|       }) | ||||
|       }), | ||||
|     ); | ||||
|     return done.promise; | ||||
|   } | ||||
|  | ||||
|   public async exportToStreamOfStreamFiles() { | ||||
|     const streamFileIntake = new plugins.smartstream.StreamIntake<plugins.smartfile.StreamFile>({ | ||||
|       objectMode: true, | ||||
|     }); | ||||
|     const streamFileIntake = | ||||
|       new plugins.smartstream.StreamIntake<plugins.smartfile.StreamFile>({ | ||||
|         objectMode: true, | ||||
|       }); | ||||
|     const archiveStream = await this.getArchiveStream(); | ||||
|     const createAnalyzedStream = () => this.archiveAnalyzer.getAnalyzedStream(); | ||||
|  | ||||
| @@ -125,15 +151,21 @@ export class SmartArchive { | ||||
|       plugins.smartstream.createTransformFunction<IAnalyzedResult, any>( | ||||
|         async (analyzedResultChunk) => { | ||||
|           if (analyzedResultChunk.fileType?.mime === 'application/x-tar') { | ||||
|             const tarStream = analyzedResultChunk.decompressionStream as plugins.tarStream.Extract; | ||||
|             const tarStream = | ||||
|               analyzedResultChunk.decompressionStream as plugins.tarStream.Extract; | ||||
|             tarStream.on('entry', async (header, stream, next) => { | ||||
|               if (header.type === 'directory') { | ||||
|                 console.log(`tar stream directory: ${header.name} ... skipping!`); | ||||
|                 console.log( | ||||
|                   `tar stream directory: ${header.name} ... skipping!`, | ||||
|                 ); | ||||
|                 next(); | ||||
|                 return; | ||||
|               } | ||||
|               console.log(`tar stream file: ${header.name}`); | ||||
|               const streamfile = plugins.smartfile.StreamFile.fromStream(stream, header.name); | ||||
|               const streamfile = plugins.smartfile.StreamFile.fromStream( | ||||
|                 stream, | ||||
|                 header.name, | ||||
|               ); | ||||
|               streamFileIntake.push(streamfile); | ||||
|               stream.on('end', function () { | ||||
|                 next(); // ready for next entry | ||||
| @@ -143,20 +175,30 @@ export class SmartArchive { | ||||
|               console.log('finished'); | ||||
|               streamFileIntake.signalEnd(); | ||||
|             }); | ||||
|             analyzedResultChunk.resultStream.pipe(analyzedResultChunk.decompressionStream); | ||||
|             analyzedResultChunk.resultStream.pipe( | ||||
|               analyzedResultChunk.decompressionStream, | ||||
|             ); | ||||
|           } else if (analyzedResultChunk.fileType?.mime === 'application/zip') { | ||||
|             analyzedResultChunk.resultStream | ||||
|               .pipe(analyzedResultChunk.decompressionStream) | ||||
|               .pipe(new plugins.smartstream.SmartDuplex({ | ||||
|                 objectMode: true, | ||||
|                 writeFunction: async (streamFileArg: plugins.smartfile.StreamFile, streamtools) => { | ||||
|                   streamFileIntake.push(streamFileArg); | ||||
|                 }, | ||||
|                 finalFunction: async () => { | ||||
|                   streamFileIntake.signalEnd(); | ||||
|                 } | ||||
|               })); | ||||
|           } else if (analyzedResultChunk.isArchive && analyzedResultChunk.decompressionStream) { | ||||
|               .pipe( | ||||
|                 new plugins.smartstream.SmartDuplex({ | ||||
|                   objectMode: true, | ||||
|                   writeFunction: async ( | ||||
|                     streamFileArg: plugins.smartfile.StreamFile, | ||||
|                     streamtools, | ||||
|                   ) => { | ||||
|                     streamFileIntake.push(streamFileArg); | ||||
|                   }, | ||||
|                   finalFunction: async () => { | ||||
|                     streamFileIntake.signalEnd(); | ||||
|                   }, | ||||
|                 }), | ||||
|               ); | ||||
|           } else if ( | ||||
|             analyzedResultChunk.isArchive && | ||||
|             analyzedResultChunk.decompressionStream | ||||
|           ) { | ||||
|             analyzedResultChunk.resultStream | ||||
|               .pipe(analyzedResultChunk.decompressionStream) | ||||
|               .pipe(createAnalyzedStream()) | ||||
| @@ -164,7 +206,7 @@ export class SmartArchive { | ||||
|           } else { | ||||
|             const streamFile = plugins.smartfile.StreamFile.fromStream( | ||||
|               analyzedResultChunk.resultStream, | ||||
|               analyzedResultChunk.fileType?.ext | ||||
|               analyzedResultChunk.fileType?.ext, | ||||
|             ); | ||||
|             streamFileIntake.push(streamFile); | ||||
|             streamFileIntake.signalEnd(); | ||||
| @@ -172,7 +214,7 @@ export class SmartArchive { | ||||
|         }, | ||||
|         { | ||||
|           objectMode: true, | ||||
|         } | ||||
|         }, | ||||
|       ); | ||||
|  | ||||
|     archiveStream.pipe(createAnalyzedStream()).pipe(createUnpackStream()); | ||||
|   | ||||
| @@ -18,7 +18,7 @@ export class TarTools { | ||||
|         | plugins.smartfile.StreamFile; | ||||
|       byteLength?: number; | ||||
|       filePath?: string; | ||||
|     } | ||||
|     }, | ||||
|   ): Promise<void> { | ||||
|     return new Promise<void>(async (resolve, reject) => { | ||||
|       let fileName: string | null = null; | ||||
| @@ -28,7 +28,8 @@ export class TarTools { | ||||
|       } else if (optionsArg.content instanceof plugins.smartfile.SmartFile) { | ||||
|         fileName = (optionsArg.content as plugins.smartfile.SmartFile).relative; | ||||
|       } else if (optionsArg.content instanceof plugins.smartfile.StreamFile) { | ||||
|         fileName = (optionsArg.content as plugins.smartfile.StreamFile).relativeFilePath; | ||||
|         fileName = (optionsArg.content as plugins.smartfile.StreamFile) | ||||
|           .relativeFilePath; | ||||
|       } else if (optionsArg.filePath) { | ||||
|         fileName = optionsArg.filePath; | ||||
|       } | ||||
| @@ -47,9 +48,11 @@ export class TarTools { | ||||
|         contentByteLength = await optionsArg.content.getSize(); // assuming SmartFile has getSize method | ||||
|       } else if (optionsArg.content instanceof plugins.smartfile.StreamFile) { | ||||
|         contentByteLength = await optionsArg.content.getSize(); // assuming StreamFile has getSize method | ||||
|       } else if (optionsArg.content instanceof plugins.smartstream.stream.Readable) { | ||||
|       } else if ( | ||||
|         optionsArg.content instanceof plugins.smartstream.stream.Readable | ||||
|       ) { | ||||
|         console.warn( | ||||
|           '@push.rocks/smartarchive: When streaming, it is recommended to provide byteLength, if known.' | ||||
|           '@push.rocks/smartarchive: When streaming, it is recommended to provide byteLength, if known.', | ||||
|         ); | ||||
|       } else if (optionsArg.filePath) { | ||||
|         const fileStat = await plugins.smartfile.fs.stat(optionsArg.filePath); | ||||
| @@ -63,12 +66,18 @@ export class TarTools { | ||||
|       if (Buffer.isBuffer(optionsArg.content)) { | ||||
|         content = plugins.smartstream.stream.Readable.from(optionsArg.content); | ||||
|       } else if (typeof optionsArg.content === 'string') { | ||||
|         content = plugins.smartstream.stream.Readable.from(Buffer.from(optionsArg.content)); | ||||
|         content = plugins.smartstream.stream.Readable.from( | ||||
|           Buffer.from(optionsArg.content), | ||||
|         ); | ||||
|       } else if (optionsArg.content instanceof plugins.smartfile.SmartFile) { | ||||
|         content = plugins.smartstream.stream.Readable.from(optionsArg.content.contents); | ||||
|         content = plugins.smartstream.stream.Readable.from( | ||||
|           optionsArg.content.contents, | ||||
|         ); | ||||
|       } else if (optionsArg.content instanceof plugins.smartfile.StreamFile) { | ||||
|         content = await optionsArg.content.createReadStream(); | ||||
|       } else if (optionsArg.content instanceof plugins.smartstream.stream.Readable) { | ||||
|       } else if ( | ||||
|         optionsArg.content instanceof plugins.smartstream.stream.Readable | ||||
|       ) { | ||||
|         content = optionsArg.content; | ||||
|       } | ||||
|  | ||||
| @@ -87,7 +96,7 @@ export class TarTools { | ||||
|           } else { | ||||
|             resolve(); | ||||
|           } | ||||
|         } | ||||
|         }, | ||||
|       ); | ||||
|  | ||||
|       content.pipe(entry); | ||||
| @@ -100,7 +109,10 @@ export class TarTools { | ||||
|    * @param directoryPath | ||||
|    */ | ||||
|   public async packDirectory(directoryPath: string) { | ||||
|     const fileTree = await plugins.smartfile.fs.listFileTree(directoryPath, '**/*'); | ||||
|     const fileTree = await plugins.smartfile.fs.listFileTree( | ||||
|       directoryPath, | ||||
|       '**/*', | ||||
|     ); | ||||
|     const pack = await this.getPackStream(); | ||||
|     for (const filePath of fileTree) { | ||||
|       const absolutePath = plugins.path.join(directoryPath, filePath); | ||||
|   | ||||
| @@ -1,33 +1,39 @@ | ||||
| import type { SmartArchive } from './classes.smartarchive.js'; | ||||
| import * as plugins from './plugins.js'; | ||||
|  | ||||
| class DecompressZipTransform extends plugins.smartstream.SmartDuplex<ArrayBufferLike> { | ||||
| class DecompressZipTransform extends plugins.smartstream | ||||
|   .SmartDuplex<ArrayBufferLike> { | ||||
|   private streamtools: plugins.smartstream.IStreamTools; | ||||
|   private unzipper = new plugins.fflate.Unzip(async (fileArg) => { | ||||
|     let resultBuffer: Buffer; | ||||
|     fileArg.ondata = async (flateError, dat, final) => { | ||||
|       resultBuffer? resultBuffer = Buffer.concat([resultBuffer, Buffer.from(dat)]) | ||||
|         : resultBuffer = Buffer.from(dat); | ||||
|       resultBuffer | ||||
|         ? (resultBuffer = Buffer.concat([resultBuffer, Buffer.from(dat)])) | ||||
|         : (resultBuffer = Buffer.from(dat)); | ||||
|       if (final) { | ||||
|         const streamFile = plugins.smartfile.StreamFile.fromBuffer(resultBuffer); | ||||
|         const streamFile = | ||||
|           plugins.smartfile.StreamFile.fromBuffer(resultBuffer); | ||||
|         streamFile.relativeFilePath = fileArg.name; | ||||
|         this.streamtools.push(streamFile); | ||||
|       } | ||||
|     } | ||||
|     }; | ||||
|     fileArg.start(); | ||||
|   }); | ||||
|   constructor() { | ||||
|     super({ | ||||
|       objectMode: true, | ||||
|       writeFunction: async (chunkArg, streamtoolsArg) => { | ||||
|         this.streamtools? null : this.streamtools = streamtoolsArg; | ||||
|         this.unzipper.push(Buffer.isBuffer(chunkArg) ? chunkArg : Buffer.from(chunkArg), false); | ||||
|         this.streamtools ? null : (this.streamtools = streamtoolsArg); | ||||
|         this.unzipper.push( | ||||
|           Buffer.isBuffer(chunkArg) ? chunkArg : Buffer.from(chunkArg), | ||||
|           false, | ||||
|         ); | ||||
|       }, | ||||
|       finalFunction: async () => { | ||||
|         this.unzipper.push(Buffer.from(''), true); | ||||
|         await plugins.smartdelay.delayFor(0); | ||||
|         await this.streamtools.push(null); | ||||
|       } | ||||
|       }, | ||||
|     }); | ||||
|     this.unzipper.register(plugins.fflate.UnzipInflate); | ||||
|   } | ||||
| @@ -42,7 +48,11 @@ export class CompressZipTransform extends plugins.stream.Transform { | ||||
|     this.files = {}; | ||||
|   } | ||||
|  | ||||
|   _transform(chunk: Buffer, encoding: BufferEncoding, callback: plugins.stream.TransformCallback) { | ||||
|   _transform( | ||||
|     chunk: Buffer, | ||||
|     encoding: BufferEncoding, | ||||
|     callback: plugins.stream.TransformCallback, | ||||
|   ) { | ||||
|     // Simple example: storing chunks in memory before finalizing ZIP in _flush | ||||
|     this.files['file.txt'] = new Uint8Array(chunk); | ||||
|     callback(); | ||||
| @@ -61,8 +71,7 @@ export class CompressZipTransform extends plugins.stream.Transform { | ||||
| } | ||||
|  | ||||
| export class ZipTools { | ||||
|   constructor() { | ||||
|   } | ||||
|   constructor() {} | ||||
|  | ||||
|   public getCompressionStream() { | ||||
|     return new CompressZipTransform(); | ||||
|   | ||||
| @@ -2,6 +2,6 @@ import * as plugins from './plugins.js'; | ||||
|  | ||||
| export const packageDir = plugins.path.join( | ||||
|   plugins.smartpath.get.dirnameFromImportMetaUrl(import.meta.url), | ||||
|   '../' | ||||
|   '../', | ||||
| ); | ||||
| export const nogitDir = plugins.path.join(packageDir, './.nogit'); | ||||
|   | ||||
| @@ -15,7 +15,17 @@ import * as smartstream from '@push.rocks/smartstream'; | ||||
| import * as smartrx from '@push.rocks/smartrx'; | ||||
| import * as smarturl from '@push.rocks/smarturl'; | ||||
|  | ||||
| export { smartfile, smartdelay, smartpath, smartpromise, smartrequest, smartunique, smartstream, smartrx, smarturl }; | ||||
| export { | ||||
|   smartfile, | ||||
|   smartdelay, | ||||
|   smartpath, | ||||
|   smartpromise, | ||||
|   smartrequest, | ||||
|   smartunique, | ||||
|   smartstream, | ||||
|   smartrx, | ||||
|   smarturl, | ||||
| }; | ||||
|  | ||||
| // third party scope | ||||
| import * as fileType from 'file-type'; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user