streaming 7-Zip archive extractor
0

Configure Feed

Select the types of activity you want to include in your feed.

pkg-7zip / tests / container.test.ts
5.7 kB 122 lines
1import { assert, assertEquals, assertRejects } from '@std/assert'; 2 3import { ChecksumMismatchError, InvalidSignatureError, TruncatedArchiveError } from '../lib/errors.ts'; 4import { readContainer, readNextHeader, readSignatureHeader } from '../lib/container.ts'; 5import { fromUint8Array } from '../lib/reader/common.ts'; 6 7const FIXTURES = new URL('./fixtures/commons-compress/', import.meta.url); 8const LIBARCHIVE_FIXTURES = new URL('./fixtures/libarchive/', import.meta.url); 9 10const loadFixture = (name: string): Uint8Array<ArrayBuffer> => { 11 return Deno.readFileSync(new URL(name, FIXTURES)); 12}; 13 14const loadLibarchive = (name: string): Uint8Array<ArrayBuffer> => { 15 return Deno.readFileSync(new URL(name, LIBARCHIVE_FIXTURES)); 16}; 17 18Deno.test('readSignatureHeader: valid mhc-off-copy fixture', async () => { 19 const reader = fromUint8Array(loadFixture('7z-hello-mhc-off-copy.7z')); 20 const start = await readSignatureHeader(reader); 21 assertEquals(start.versionMajor, 0); 22 // nextHeader is at offset 32 + 14 = 46 (after 14 bytes of "Hello, world!\n" payload) 23 assertEquals(start.nextHeaderOffset, 14); 24 assertEquals(start.nextHeaderSize, 86); 25}); 26 27Deno.test('readSignatureHeader: rejects non-7z input', async () => { 28 const garbage = new Uint8Array(64); 29 garbage.set([0x50, 0x4b, 0x03, 0x04]); // PK\x03\x04 (zip) 30 const reader = fromUint8Array(garbage); 31 await assertRejects(() => readSignatureHeader(reader), InvalidSignatureError); 32}); 33 34Deno.test('readSignatureHeader: rejects truncated input', async () => { 35 const reader = fromUint8Array(new Uint8Array(10)); 36 await assertRejects(() => readSignatureHeader(reader), TruncatedArchiveError); 37}); 38 39Deno.test('readSignatureHeader: rejects bad StartHeader CRC', async () => { 40 const data = loadFixture('7z-hello-mhc-off-copy.7z'); 41 const clone = new Uint8Array(data); 42 clone[12] ^= 0xff; // mangle first byte of the StartHeader payload 43 const reader = fromUint8Array(clone); 44 await assertRejects(() => readSignatureHeader(reader), ChecksumMismatchError); 45}); 46 47Deno.test('readNextHeader: returns a plain Header for mhc-off-copy', async () => { 48 const reader = fromUint8Array(loadFixture('7z-hello-mhc-off-copy.7z')); 49 const start = await readSignatureHeader(reader); 50 const raw = await readNextHeader(reader, start); 51 assertEquals(raw.kind, 'header'); 52}); 53 54Deno.test('readContainer: mhc-off-copy parses to one file with one folder', async () => { 55 const reader = fromUint8Array(loadFixture('7z-hello-mhc-off-copy.7z')); 56 const container = await readContainer(reader); 57 assertEquals(container.header.files.length, 1); 58 assertEquals(container.header.files[0].name, 'Hello world.txt'); 59 assertEquals(container.header.files[0].size, 14); 60 assertEquals(container.header.files[0].hasStream, true); 61 assertEquals(container.header.files[0].isDirectory, false); 62 assert(container.header.files[0].crc !== undefined); 63 assertEquals(container.header.folders.length, 1); 64 assertEquals(container.header.folders[0].coders.length, 1); 65 // Copy method has id 0x00, single zero byte 66 assertEquals(container.header.folders[0].coders[0].methodId.length, 1); 67 assertEquals(container.header.folders[0].coders[0].methodId[0], 0x00); 68 assertEquals(container.header.pack.packSizes, [14]); 69 assertEquals(container.packBase, 32); 70}); 71 72Deno.test('readContainer: mhc-off-lzma2 parses to one file with one lzma2 coder', async () => { 73 const reader = fromUint8Array(loadFixture('7z-hello-mhc-off-lzma2.7z')); 74 const container = await readContainer(reader); 75 assertEquals(container.header.files.length, 1); 76 assertEquals(container.header.files[0].name, 'Hello world.txt'); 77 assertEquals(container.header.files[0].size, 14); 78 assertEquals(container.header.folders.length, 1); 79 const coder = container.header.folders[0].coders[0]; 80 assertEquals(coder.methodId.length, 1); 81 assertEquals(coder.methodId[0], 0x21); // LZMA2 82 // LZMA2 stores a 1-byte dictionary descriptor as its property 83 assertEquals(coder.properties.length, 1); 84}); 85 86Deno.test('readContainer: libarchive copy.7z (plain header) parses', async () => { 87 const reader = fromUint8Array(loadLibarchive('test_read_format_7zip_copy.7z')); 88 const container = await readContainer(reader); 89 assertEquals(container.header.files.length, 1); 90 assertEquals(container.header.files[0].name, 'file1'); 91 assertEquals(container.header.folders.length, 1); 92 // the copy fixture stores a single file with the Copy coder 93 assertEquals(container.header.folders[0].coders[0].methodId[0], 0x00); 94 assert(container.header.files[0].size > 0); 95}); 96 97Deno.test('readNextHeader: bla.7z carries an EncodedHeader', async () => { 98 const reader = fromUint8Array(loadFixture('bla.7z')); 99 const start = await readSignatureHeader(reader); 100 const raw = await readNextHeader(reader, start); 101 assertEquals(raw.kind, 'encoded'); 102}); 103 104Deno.test('readContainer: bla.7z decodes its encoded header', async () => { 105 const reader = fromUint8Array(loadFixture('bla.7z')); 106 const container = await readContainer(reader); 107 assert(container.header.files.length > 0); 108 assertEquals(container.header.files[0].name, 'test1.xml'); 109}); 110 111Deno.test('readContainer: mhc-off-empty has one zero-byte file and no folders', async () => { 112 // commons-compress's "empty" mhc-off fixture records a file named "empty" 113 // with no data stream (and consequently no folders or pack data). 114 const reader = fromUint8Array(loadFixture('7z-empty-mhc-off.7z')); 115 const container = await readContainer(reader); 116 assertEquals(container.header.files.length, 1); 117 assertEquals(container.header.files[0].name, 'empty'); 118 assertEquals(container.header.files[0].size, 0); 119 assertEquals(container.header.files[0].hasStream, false); 120 assertEquals(container.header.files[0].isDirectory, false); 121 assertEquals(container.header.folders.length, 0); 122});