ssn/src/ssn/extractFileStream.ts

54 lines
2 KiB
TypeScript

//Similar to extractFile.ts, but instead of receiving and returning an ArrayBuffer, works with Node.js streams.
import * as stream from 'stream';
import * as zlib from 'zlib';
import { ISsnFileEntry } from '../interfaces/ISsnFileEntry';
import decryptStream from './streams/decryptStream';
import streamSetMaxLength from './streams/streamSetMaxLength';
/** Extracts the file with the given metadata from the stream.
* The stream must already start at the .zip's local file header
* and must transparently span across multiple disks if necessary.
*/
export default function extractFileStream(file: ISsnFileEntry, inputStream: stream.Readable): stream.Readable {
const localFileHeader: Buffer = inputStream.read(30);
//Local file header signature
const magic = localFileHeader.readUInt32LE(0);
if (magic !== 0x04034B50) {
throw new Error(`Local file header had wrong magic; expected 0x04034B50 but got 0x${magic.toString(16).padStart(8, '0')}`);
}
//All fields in the local file header are copies of the central file header, so we can skip them.
//FIXME: Maybe we should actually read these fields to verify that they are identical?
//skip 22 bytes
const localFilenameSize = localFileHeader.readUInt16LE(26);
const localExtraSize = localFileHeader.readUInt16LE(28);
//skip local file name and extra field
inputStream.read(localFilenameSize + localExtraSize);
//-------------------------------------------------
let curStream = inputStream;
//set max length
const maxLength = streamSetMaxLength(curStream, file.compressedSize);
curStream = maxLength;
//pipe into decryption if file is encrypted
if (file.decryptionKeys !== undefined) {
const decryptTransform = decryptStream(curStream, file.decryptionKeys);
curStream = decryptTransform;
}
//pipe into decompression
const decompressTransform = zlib.createInflateRaw();
curStream.pipe(decompressTransform);
curStream = decompressTransform;
//set max length
const maxLength2 = streamSetMaxLength(curStream, file.size);
curStream = maxLength2;
return curStream;
}