Skip to content

Commit 675f258

Browse files
committed
Working!
1 parent 95a840a commit 675f258

3 files changed

Lines changed: 47 additions & 110 deletions

File tree

src/decode.ts

Lines changed: 46 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -1,99 +1,33 @@
1-
/// <reference path="./util/implode-decoder.d.ts" />
2-
31
import { promises as fs } from 'fs';
42
import winston from 'winston';
5-
import { FirstDifference } from './util/BufferFirstDifference';
63
import { UnexpectedValue } from './util/UnexpectedValue';
7-
import decoder from 'implode-decoder';
8-
import { decompress, constants } from 'node-pkware';
9-
import { WritableStreamBuffer } from 'stream-buffers';
10-
import { promisify } from 'util';
11-
12-
const compressedBlocks: Buffer[] = [];
13-
const decompressedBlocks: string[] = [];
14-
15-
async function decodeBlock(block: Buffer, expectedLength: number): Promise<string> {
16-
const d = decoder();
17-
18-
const res = new WritableStreamBuffer({ initialSize: expectedLength });
19-
d.pipe(res);
20-
d.end(block);
21-
22-
const newDecoder = decompress({ debug: true, outputBufferSize: expectedLength, inputBufferSize: block.length });
23-
24-
const newDecoderPromise = promisify(newDecoder);
25-
26-
const resNew = new WritableStreamBuffer({ initialSize: expectedLength });
27-
resNew.write(await newDecoderPromise(block, 'binary'));
28-
29-
resNew.end(
30-
await new Promise<Buffer>((resolve, reject) => {
31-
newDecoder._state.onInputFinished((err, data) => {
32-
if (err) reject(err);
33-
else resolve(data);
34-
});
35-
}),
4+
import { explode, stream } from 'node-pkware';
5+
import { Readable } from 'stream';
6+
const { streamToBuffer, through } = stream;
7+
8+
async function decodeBlock(block: Buffer, expectedLength: number): Promise<Buffer> {
9+
const ret = await new Promise<Buffer>(resolve =>
10+
Readable.from(block)
11+
.pipe(through(explode({ inputBufferSize: block.length, outputBufferSize: expectedLength })))
12+
.pipe(streamToBuffer(resolve)),
3613
);
3714

38-
const ret = res.getContentsAsString('ascii');
39-
const retNew = resNew.getContentsAsString('ascii');
40-
41-
if (!ret) throw new Error('Decoder returned null');
42-
if (!retNew) throw new Error('Decoder returned null');
43-
4415
if (ret.length !== expectedLength)
4516
throw new Error(`Decoder returned wrong length. Expected: ${expectedLength}. Got: ${ret.length}.`);
4617

47-
if (retNew.length !== expectedLength) {
48-
console.log('ret:', ret.substring(retNew.length - 100, retNew.length));
49-
console.log('New:', retNew.substring(retNew.length - 100));
50-
51-
console.log(newDecoder._state);
52-
53-
throw new Error(`New Decoder returned wrong length. Expected: ${expectedLength}. Got: ${retNew.length}.`);
54-
}
55-
5618
return ret;
5719
}
5820

59-
function analyzeSection(compressed: Buffer, section: number, logger: winston.Logger): void {
60-
return;
61-
62-
if (section === 0) {
63-
for (let result in compressedBlocks) {
64-
const diff = FirstDifference(compressedBlocks[result], compressed);
65-
logger.verbose(`Difference from #${result} at: ${diff ?? 'None!'}`);
66-
}
67-
68-
compressedBlocks.push(compressed);
69-
logger.info('pushed' + compressedBlocks.length);
70-
}
71-
72-
const header = Buffer.allocUnsafe(8);
73-
74-
header.writeUInt32LE(length, 0);
75-
header.writeUInt32LE(compressed.length, 4);
76-
77-
const full = Buffer.concat([header, compressed]);
78-
79-
const size = section === 0 ? 20 : 160;
80-
81-
logger.verbose(compressed.slice(0, size).toString('hex'));
82-
if (!section) logger.verbose(compressed.slice(0, size).toString());
83-
84-
if (!section) logger.verbose('Matches: ' + compressed.slice(0, 103).toString('hex'));
85-
}
86-
87-
export async function decode(filename: string, logger: winston.Logger) {
21+
export async function decode(filename: string, logger: winston.Logger, outFile = filename + '.xml'): Promise<void> {
8822
if (!filename) throw new Error('No filename provided');
8923

9024
let expectedHeader: Buffer;
9125

9226
if (filename.endsWith('.ewprj')) {
93-
logger.verbose(`Opening EWPRJ: ${filename}`);
27+
logger.silly(`Opening EWPRJ: ${filename}`);
9428
expectedHeader = Buffer.from('CompressedElectronicsWorkbenchXML');
9529
} else if (filename.endsWith('.ms14')) {
96-
logger.verbose(`Opening MultiSIM: ${filename}`);
30+
logger.silly(`Opening MultiSIM: ${filename}`);
9731
expectedHeader = Buffer.from('MSMCompressedElectronicsWorkbenchXML');
9832
} else {
9933
throw new Error(`I don't know how to parse: ${filename}`);
@@ -136,51 +70,59 @@ export async function decode(filename: string, logger: winston.Logger) {
13670
return buffer.readUIntLE(0, size);
13771
}
13872

73+
let written = 0;
74+
13975
try {
140-
let header = await read(expectedHeader.length);
76+
logger.silly(`Opening ${outFile} for output`);
77+
const outputFile = await fs.open(outFile, 'w');
14178

142-
logger.verbose('Read header successfully');
79+
try {
80+
let header = await read(expectedHeader.length);
14381

144-
if (!header.equals(expectedHeader)) {
145-
throw new UnexpectedValue('File header does not match', expectedHeader, header);
146-
}
82+
logger.silly('Read header successfully');
14783

148-
logger.verbose('Header matches as expected');
84+
if (!header.equals(expectedHeader)) {
85+
throw new UnexpectedValue('File header does not match', expectedHeader, header);
86+
}
14987

150-
const finalLength = await readNumber(8);
88+
logger.silly('Header matches as expected');
15189

152-
if (typeof finalLength == 'bigint') throw new Error('Cannot handle files this large');
90+
const finalLength = await readNumber(8);
15391

154-
logger.verbose(`Full size: ${finalLength}`);
92+
if (typeof finalLength == 'bigint') throw new Error('Cannot handle files this large');
15593

156-
let section = -1;
94+
logger.silly(`Full size: ${finalLength}`);
15795

158-
let decompressedBytesRead = 0;
96+
let section = -1;
15997

160-
while (decompressedBytesRead < finalLength) {
161-
section++;
162-
const length = await readNumber(4);
163-
const blockSize = await readNumber(4);
98+
let decompressedBytesRead = 0;
16499

165-
logger.verbose(`Section #${section} read ${blockSize} bytes, decompresses to ${length}`);
100+
while (decompressedBytesRead < finalLength) {
101+
section++;
102+
const length = await readNumber(4);
103+
const blockSize = await readNumber(4);
166104

167-
const compressedData = await read(blockSize);
105+
logger.silly(`Section #${section} read ${blockSize} bytes, decompresses to ${length}`);
168106

169-
decompressedBytesRead += length;
107+
const compressedData = await read(blockSize);
170108

171-
compressedBlocks.push(compressedData);
109+
decompressedBytesRead += length;
172110

173-
const decodedBlock = decodeBlock(compressedData, length);
111+
const decodedBlock = await decodeBlock(compressedData, length);
174112

175-
decompressedBlocks.push(await decodedBlock);
113+
written += (await outputFile.write(decodedBlock)).bytesWritten;
114+
}
176115

177-
analyzeSection(compressedData, section, logger);
116+
await Promise.all([outputFile.close(), file.close()]);
117+
118+
logger.verbose(`Wrote ${written} bytes to ${outFile}`);
119+
logger.silly(`Finished reading file: ${filename}`);
120+
} catch (e) {
121+
await outputFile.close();
122+
throw e;
178123
}
179124
} catch (e) {
180-
throw e;
181-
} finally {
182125
await file.close();
126+
throw e;
183127
}
184-
185-
logger.verbose(`Finished reading file: ${filename}`);
186128
}

src/main.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ export async function main() {
3737
}
3838
}
3939

40-
logger.info('Done');
40+
logger.silly('Done');
4141
}
4242

4343
if (require.main === module) {

src/util/implode-decoder.d.ts

Lines changed: 0 additions & 5 deletions
This file was deleted.

0 commit comments

Comments
 (0)