diff --git a/src/ssn/extractFileStream.ts b/src/ssn/extractFileStream.ts index 339fe11..2a5443b 100644 --- a/src/ssn/extractFileStream.ts +++ b/src/ssn/extractFileStream.ts @@ -4,12 +4,13 @@ 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'; /** 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, skipDecompression: boolean = false): stream.Readable { +export default async function extractFileStream(file: ISsnFileEntry, inputStream: stream.Readable, skipDecompression: boolean = false): Promise { let curStream = inputStream; //pipe into decryption if file is encrypted @@ -17,7 +18,12 @@ export default function extractFileStream(file: ISsnFileEntry, inputStream: stre const decryptTransform = decryptStream(file.decryptionKeys); curStream = curStream.pipe(decryptTransform); //skip encryption header - curStream.read(12); + const encryptionHeader = curStream.read(12); + if (encryptionHeader === null) { + //need to wait until data is ready for reading + await waitReadableLength(curStream, 30); + curStream.read(30); + } } if (!skipDecompression) { diff --git a/src/ssn/getManifest.ts b/src/ssn/getManifest.ts index c669274..9ab409d 100644 --- a/src/ssn/getManifest.ts +++ b/src/ssn/getManifest.ts @@ -37,7 +37,7 @@ export default async function getManifest(product: Product): Promise //Extract manifest.xml file await readLocalFileHeader(stream, true); - const patchmanifestStream = extractFileStream(firstFile, stream); + const patchmanifestStream = await extractFileStream(firstFile, stream); //Convert ArrayBuffer to string const patchmanifestXml = await streamToString(patchmanifestStream); diff --git a/src/ssn/getPatch.ts b/src/ssn/getPatch.ts index 78595ab..7a2ba19 100644 --- a/src/ssn/getPatch.ts +++ b/src/ssn/getPatch.ts @@ -40,7 +40,7 @@ export default async function getPatch(product: Product, from: number, to: numbe fileEntries.filter((file) => file.diffType === SsnDiffType.NewFile).forEach(async (file) => { try { const fileStream = await getFileFromDisks(diskFilenames, { diskStart: file.diskNumberStart, offset: file.offset, length: file.compressedSize }); - const fileContents = extractFileStream(file, fileStream, true); + const fileContents = await extractFileStream(file, fileStream, true); console.debug(file.name, file.compressedSize, await streamToArrayBuffer(fileContents)); //TODO: need to write to disk } catch (error) { @@ -52,7 +52,7 @@ export default async function getPatch(product: Product, from: number, to: numbe fileEntries.filter((file) => file.diffType === SsnDiffType.Changed).forEach(async (file) => { try { const fileStream = await getFileFromDisks(diskFilenames, { diskStart: file.diskNumberStart, offset: file.offset, length: file.compressedSize }); - const fileContents = extractFileStream(file, fileStream, true); + const fileContents = await extractFileStream(file, fileStream, true); console.debug(file.name, file.compressedSize, await streamToArrayBuffer(fileContents)); //TODO: need to apply diffing, then write to disk } catch (error) { diff --git a/src/ssn/getSolidpkg.ts b/src/ssn/getSolidpkg.ts index 51d66a3..09802d7 100644 --- a/src/ssn/getSolidpkg.ts +++ b/src/ssn/getSolidpkg.ts @@ -42,7 +42,7 @@ export default async function getSolidpkg(product: Product, from: number, to: nu //Extract metafile.solid file await readLocalFileHeader(stream, true); - const solidFileStream = extractFileStream(firstFile, stream); + const solidFileStream = await extractFileStream(firstFile, stream); const solidFileArrayBuffer = await streamToArrayBuffer(solidFileStream); const solidContents = parseBencode(new DataView(solidFileArrayBuffer.buffer)) as ISolid; diff --git a/src/ssn/streams/readLocalFileHeader.ts b/src/ssn/streams/readLocalFileHeader.ts index ad48d69..a972caf 100644 --- a/src/ssn/streams/readLocalFileHeader.ts +++ b/src/ssn/streams/readLocalFileHeader.ts @@ -1,16 +1,5 @@ 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); - }); -} +import waitReadableLength from './waitReadableLength'; /** Reads the local file header, which is included before * each stored file, and advances the stream accordingly. diff --git a/src/ssn/streams/waitReadableLength.ts b/src/ssn/streams/waitReadableLength.ts new file mode 100644 index 0000000..9a7277d --- /dev/null +++ b/src/ssn/streams/waitReadableLength.ts @@ -0,0 +1,13 @@ +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); + }); +}