diff --git a/src/ssn/extractFileStream.ts b/src/ssn/extractFileStream.ts index ff6d7e8..04f7f1c 100644 --- a/src/ssn/extractFileStream.ts +++ b/src/ssn/extractFileStream.ts @@ -4,7 +4,7 @@ import * as stream from 'stream'; import * as zlib from 'zlib'; import { ISsnFileEntry } from '../interfaces/ISsnFileEntry'; import decryptStream from './streams/decryptStream'; -import waitReadableLength from './streams/waitReadableLength'; +import readBytesFromStream from './streams/readBytesFromStream'; /** Extracts the file with the given metadata from the stream. * The stream must already start at the .zip's local file header @@ -18,12 +18,7 @@ export default async function extractFileStream(file: ISsnFileEntry, inputStream const decryptTransform = decryptStream(file.decryptionKeys); curStream = curStream.pipe(decryptTransform); //skip encryption header - const encryptionHeader = curStream.read(12); - if (encryptionHeader === null) { - //need to wait until data is ready for reading - await waitReadableLength(curStream, 12); - curStream.read(12); - } + readBytesFromStream(curStream, 12); } if (!skipDecompression) { diff --git a/src/ssn/streams/readBytesFromStream.ts b/src/ssn/streams/readBytesFromStream.ts new file mode 100644 index 0000000..6f5a490 --- /dev/null +++ b/src/ssn/streams/readBytesFromStream.ts @@ -0,0 +1,24 @@ +import * as stream from 'stream'; + +/** Returns a promise that resolves as soon as the given stream has the given number of bytes ready for reading. */ +function waitReadableLength(inputStream: stream.Readable, minLength: number): Promise { + return new Promise((resolve) => { + const interval = setInterval(() => { + if (inputStream.readableLength >= minLength) { + clearInterval(interval); + resolve(); + } + }, 100); + }); +} + +/** Reads the given number of bytes from the stream and returns them as a buffer, optionally waiting until the bytes are ready for reading. */ +export default async function readBytesFromStream(inputStream: stream.Readable, length: number): Promise { + let localFileHeader: Buffer = inputStream.read(length); + while (localFileHeader === null) { + //need to wait until data is ready for reading + await waitReadableLength(inputStream, length); + localFileHeader = inputStream.read(length); + } + return localFileHeader; +} diff --git a/src/ssn/streams/readLocalFileHeader.ts b/src/ssn/streams/readLocalFileHeader.ts index a972caf..34b56b4 100644 --- a/src/ssn/streams/readLocalFileHeader.ts +++ b/src/ssn/streams/readLocalFileHeader.ts @@ -1,17 +1,12 @@ import * as stream from 'stream'; -import waitReadableLength from './waitReadableLength'; +import readBytesFromStream from './readBytesFromStream'; /** Reads the local file header, which is included before * each stored file, and advances the stream accordingly. * Returns length of the local file header. */ export default async function readLocalFileHeader(inputStream: stream.Readable, skipAdditionalLength = false): Promise { - let localFileHeader: Buffer = inputStream.read(30); - if (localFileHeader === null) { - //need to wait until data is ready for reading - await waitReadableLength(inputStream, 30); - localFileHeader = inputStream.read(30); - } + const localFileHeader = await readBytesFromStream(inputStream, 30); //Local file header signature const magic = localFileHeader.readUInt32LE(0); @@ -27,13 +22,7 @@ export default async function readLocalFileHeader(inputStream: stream.Readable, //skip local file name and extra field const additionalLength = localFilenameSize + localExtraSize; if (skipAdditionalLength && additionalLength > 0) { - await waitReadableLength(inputStream, additionalLength); - const tmpChunk = inputStream.read(additionalLength); - if (tmpChunk === null) { - //need to wait until data is ready for reading - await waitReadableLength(inputStream, additionalLength); - inputStream.read(additionalLength); - } + await readBytesFromStream(inputStream, additionalLength); } return 30 + additionalLength; diff --git a/src/ssn/streams/waitReadableLength.ts b/src/ssn/streams/waitReadableLength.ts deleted file mode 100644 index 9a7277d..0000000 --- a/src/ssn/streams/waitReadableLength.ts +++ /dev/null @@ -1,13 +0,0 @@ -import * as stream from 'stream'; - -/** Returns a promise that resolves as soon as the given stream has the given number of bytes ready for reading. */ -export default function waitReadableLength(inputStream: stream.Readable, minLength: number): Promise { - return new Promise((resolve) => { - const interval = setInterval(() => { - if (inputStream.readableLength >= minLength) { - clearInterval(interval); - resolve(); - } - }, 100); - }); -}