@etothepii/satisfactory-file-parser 0.0.9 → 0.0.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +2 -2
- package/build/index.d.ts +0 -4
- package/build/index.js +0 -7
- package/build/parser/blueprint-reader.d.ts +0 -18
- package/build/parser/blueprint-reader.js +0 -128
- package/build/parser/blueprint-writer.d.ts +0 -21
- package/build/parser/blueprint-writer.js +0 -64
- package/build/parser/byte/alignment.enum.d.ts +0 -4
- package/build/parser/byte/alignment.enum.js +0 -5
- package/build/parser/byte/byte-reader.class.d.ts +0 -38
- package/build/parser/byte/byte-reader.class.js +0 -128
- package/build/parser/byte/byte-writer.class.d.ts +0 -38
- package/build/parser/byte/byte-writer.class.js +0 -146
- package/build/parser/error/parser.error.d.ts +0 -12
- package/build/parser/error/parser.error.js +0 -21
- package/build/parser/parser.d.ts +0 -44
- package/build/parser/parser.js +0 -81
- package/build/parser/satisfactory/blueprint/blueprint.d.ts +0 -20
- package/build/parser/satisfactory/blueprint/blueprint.js +0 -1
- package/build/parser/satisfactory/level.class.d.ts +0 -21
- package/build/parser/satisfactory/level.class.js +0 -144
- package/build/parser/satisfactory/objects/DataFields.d.ts +0 -13
- package/build/parser/satisfactory/objects/DataFields.js +0 -245
- package/build/parser/satisfactory/objects/ObjectReference.d.ts +0 -9
- package/build/parser/satisfactory/objects/ObjectReference.js +0 -13
- package/build/parser/satisfactory/objects/Property.d.ts +0 -270
- package/build/parser/satisfactory/objects/Property.js +0 -1119
- package/build/parser/satisfactory/objects/SaveComponent.d.ts +0 -16
- package/build/parser/satisfactory/objects/SaveComponent.js +0 -27
- package/build/parser/satisfactory/objects/SaveEntity.d.ts +0 -25
- package/build/parser/satisfactory/objects/SaveEntity.js +0 -66
- package/build/parser/satisfactory/objects/SaveObject.d.ts +0 -14
- package/build/parser/satisfactory/objects/SaveObject.js +0 -25
- package/build/parser/satisfactory/satisfactory-save.class.d.ts +0 -57
- package/build/parser/satisfactory/satisfactory-save.class.js +0 -7
- package/build/parser/satisfactory/static-data.d.ts +0 -7
- package/build/parser/satisfactory/static-data.js +0 -1
- package/build/parser/satisfactory/structs/util.types.d.ts +0 -40
- package/build/parser/satisfactory/structs/util.types.js +0 -75
- package/build/parser/save-reader.d.ts +0 -43
- package/build/parser/save-reader.js +0 -243
- package/build/parser/save-writer.d.ts +0 -22
- package/build/parser/save-writer.js +0 -114
package/package.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@etothepii/satisfactory-file-parser",
|
|
3
3
|
"author": "etothepii",
|
|
4
|
-
"version": "0.0.
|
|
4
|
+
"version": "0.0.10",
|
|
5
5
|
"description": "A file parser for satisfactory files. Includes save files and blueprint files.",
|
|
6
|
-
"main": "
|
|
6
|
+
"main": "index.js",
|
|
7
7
|
"keywords": [
|
|
8
8
|
"satisfactory",
|
|
9
9
|
"save",
|
package/build/index.d.ts
DELETED
package/build/index.js
DELETED
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
// types & classes for convenience
|
|
2
|
-
export { Level } from './parser/satisfactory/level.class';
|
|
3
|
-
export * from './parser/satisfactory/satisfactory-save.class';
|
|
4
|
-
// errors
|
|
5
|
-
export * from './parser/error/parser.error';
|
|
6
|
-
// facade
|
|
7
|
-
export { SaveParser } from './parser/parser';
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { ByteReader } from "./byte/byte-reader.class";
|
|
2
|
-
import { BlueprintConfig, BlueprintHeader } from "./satisfactory/blueprint/blueprint";
|
|
3
|
-
import { SaveComponent } from "./satisfactory/objects/SaveComponent";
|
|
4
|
-
import { SaveEntity } from "./satisfactory/objects/SaveEntity";
|
|
5
|
-
import { ChunkCompressionInfo } from "./satisfactory/satisfactory-save.class";
|
|
6
|
-
export declare class BlueprintReader extends ByteReader {
|
|
7
|
-
compressionInfo: ChunkCompressionInfo;
|
|
8
|
-
constructor(bluePrintBuffer: ArrayBuffer);
|
|
9
|
-
static ReadHeader(reader: ByteReader): BlueprintHeader;
|
|
10
|
-
inflateChunks(): any;
|
|
11
|
-
static ParseObjects(reader: ByteReader): (SaveEntity | SaveComponent)[];
|
|
12
|
-
}
|
|
13
|
-
export declare class BlueprintConfigReader extends ByteReader {
|
|
14
|
-
bluePrintConfigBuffer: ArrayBuffer;
|
|
15
|
-
constructor(bluePrintConfigBuffer: ArrayBuffer);
|
|
16
|
-
parse: () => BlueprintConfig;
|
|
17
|
-
static ParseConfig(reader: ByteReader): BlueprintConfig;
|
|
18
|
-
}
|
|
@@ -1,128 +0,0 @@
|
|
|
1
|
-
import Pako from "pako";
|
|
2
|
-
import { Alignment } from "./byte/alignment.enum";
|
|
3
|
-
import { ByteReader } from "./byte/byte-reader.class";
|
|
4
|
-
import { ParserError } from "./error/parser.error";
|
|
5
|
-
import { Level } from "./satisfactory/level.class";
|
|
6
|
-
import { ParseCol4RGBA, ParseVec3 } from "./satisfactory/structs/util.types";
|
|
7
|
-
export class BlueprintReader extends ByteReader {
|
|
8
|
-
constructor(bluePrintBuffer) {
|
|
9
|
-
super(bluePrintBuffer, Alignment.LITTLE_ENDIAN);
|
|
10
|
-
this.compressionInfo = {
|
|
11
|
-
packageFileTag: 0,
|
|
12
|
-
maxChunkContentSize: 0,
|
|
13
|
-
chunkHeaderSize: 48
|
|
14
|
-
};
|
|
15
|
-
}
|
|
16
|
-
static ReadHeader(reader) {
|
|
17
|
-
const unk = reader.readBytes(3 * 4); // 02 00 00 00, 24 00 00 00, 7F 3B 03 00 - always
|
|
18
|
-
const positionThingOrWhat = ParseVec3(reader); // 04 00 00 00, 04 00 00 00, 04 00 00 00 - always
|
|
19
|
-
// list of item costs.
|
|
20
|
-
let itemTypeCount = reader.readInt32();
|
|
21
|
-
const itemCosts = new Array(itemTypeCount).fill(['', 0]);
|
|
22
|
-
for (let i = 0; i < itemTypeCount; i++) {
|
|
23
|
-
let indexOrWhat = reader.readInt32();
|
|
24
|
-
let itemPathName = reader.readString();
|
|
25
|
-
let itemCount = reader.readInt32();
|
|
26
|
-
itemCosts[i] = [itemPathName, itemCount];
|
|
27
|
-
}
|
|
28
|
-
// list of recipes
|
|
29
|
-
let recipeCount = reader.readInt32();
|
|
30
|
-
const recipeRefs = new Array(recipeCount).fill('');
|
|
31
|
-
for (let i = 0; i < recipeCount; i++) {
|
|
32
|
-
let indexOrWhat = reader.readInt32();
|
|
33
|
-
const recipeName = reader.readString();
|
|
34
|
-
recipeRefs[i] = recipeName;
|
|
35
|
-
}
|
|
36
|
-
return {
|
|
37
|
-
recipeReferences: recipeRefs,
|
|
38
|
-
itemCosts
|
|
39
|
-
};
|
|
40
|
-
}
|
|
41
|
-
inflateChunks() {
|
|
42
|
-
// free memory
|
|
43
|
-
this.fileBuffer = this.fileBuffer.slice(this.currentByte);
|
|
44
|
-
this.handledByte = 0;
|
|
45
|
-
this.currentByte = 0;
|
|
46
|
-
this.maxByte = this.fileBuffer.byteLength;
|
|
47
|
-
let currentChunks = [];
|
|
48
|
-
let totalUncompressedBodySize = 0;
|
|
49
|
-
// read while we can handle
|
|
50
|
-
while (this.handledByte < this.maxByte) {
|
|
51
|
-
// Read chunk info size...
|
|
52
|
-
let chunkHeader = new DataView(this.fileBuffer.slice(0, this.compressionInfo.chunkHeaderSize));
|
|
53
|
-
this.currentByte = this.compressionInfo.chunkHeaderSize;
|
|
54
|
-
this.handledByte += this.compressionInfo.chunkHeaderSize;
|
|
55
|
-
if (this.compressionInfo.packageFileTag <= 0) {
|
|
56
|
-
this.compressionInfo.packageFileTag = chunkHeader.getUint32(0, this.alignment === Alignment.LITTLE_ENDIAN);
|
|
57
|
-
}
|
|
58
|
-
if (this.compressionInfo.maxChunkContentSize <= 0) {
|
|
59
|
-
this.compressionInfo.maxChunkContentSize = chunkHeader.getInt32(8, this.alignment === Alignment.LITTLE_ENDIAN); //00 00 02 00 = 131072
|
|
60
|
-
}
|
|
61
|
-
const chunkCompressedLength = chunkHeader.getInt32(32, this.alignment === Alignment.LITTLE_ENDIAN);
|
|
62
|
-
const chunkUncompressedLength = chunkHeader.getInt32(40, this.alignment === Alignment.LITTLE_ENDIAN);
|
|
63
|
-
totalUncompressedBodySize += chunkUncompressedLength;
|
|
64
|
-
const currentChunkSize = chunkCompressedLength;
|
|
65
|
-
let currentChunk = this.fileBuffer.slice(this.currentByte, this.currentByte + currentChunkSize);
|
|
66
|
-
this.handledByte += currentChunkSize;
|
|
67
|
-
this.currentByte += currentChunkSize;
|
|
68
|
-
// Free memory from previous chunk...
|
|
69
|
-
this.fileBuffer = this.fileBuffer.slice(this.currentByte);
|
|
70
|
-
this.currentByte = 0;
|
|
71
|
-
try {
|
|
72
|
-
// Inflate current chunk
|
|
73
|
-
let currentInflatedChunk = null;
|
|
74
|
-
currentInflatedChunk = Pako.inflate(currentChunk);
|
|
75
|
-
currentChunks.push(currentInflatedChunk);
|
|
76
|
-
}
|
|
77
|
-
catch (err) {
|
|
78
|
-
throw new ParserError('ParserError', 'An error occurred while calling pako inflate.' + err);
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
//TODO we can get rid of file buffer here.
|
|
82
|
-
// Create one big chunk out of the little chunks
|
|
83
|
-
let newChunkLength = currentChunks.map(cc => cc.length).reduce((prev, cur) => prev + cur);
|
|
84
|
-
const bigWholeChunk = new Uint8Array(newChunkLength);
|
|
85
|
-
let currentLength = 0;
|
|
86
|
-
for (let i = 0; i < currentChunks.length; i++) {
|
|
87
|
-
bigWholeChunk.set(currentChunks[i], currentLength);
|
|
88
|
-
currentLength += currentChunks[i].length;
|
|
89
|
-
}
|
|
90
|
-
// reset reader on this body content.
|
|
91
|
-
this.currentByte = 0;
|
|
92
|
-
this.maxByte = bigWholeChunk.buffer.byteLength;
|
|
93
|
-
this.bufferView = new DataView(bigWholeChunk.buffer);
|
|
94
|
-
return {
|
|
95
|
-
newChunkLength,
|
|
96
|
-
numChunks: currentChunks.length,
|
|
97
|
-
inflatedData: bigWholeChunk
|
|
98
|
-
};
|
|
99
|
-
}
|
|
100
|
-
static ParseObjects(reader) {
|
|
101
|
-
const totalBodyRestSize = reader.readInt32();
|
|
102
|
-
// object headers
|
|
103
|
-
const objectHeadersBinarySize = reader.readInt32();
|
|
104
|
-
let objects = [];
|
|
105
|
-
Level.ReadObjectHeaders(reader, objects, () => { });
|
|
106
|
-
// objects contents
|
|
107
|
-
Level.ReadObjectContents(reader, objects, 0, () => { });
|
|
108
|
-
return objects;
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
export class BlueprintConfigReader extends ByteReader {
|
|
112
|
-
constructor(bluePrintConfigBuffer) {
|
|
113
|
-
super(bluePrintConfigBuffer, Alignment.LITTLE_ENDIAN);
|
|
114
|
-
this.bluePrintConfigBuffer = bluePrintConfigBuffer;
|
|
115
|
-
this.parse = () => BlueprintConfigReader.ParseConfig(this);
|
|
116
|
-
}
|
|
117
|
-
static ParseConfig(reader) {
|
|
118
|
-
const unk = reader.readInt32(); // unknown, seems to always be 02.
|
|
119
|
-
const description = reader.readString();
|
|
120
|
-
const unk3 = reader.readInt32(); // iconID. default is 0x0E03 = 782
|
|
121
|
-
const colorMaybe = ParseCol4RGBA(reader); // LinearColor, which is 4x float32 as RGBA
|
|
122
|
-
return {
|
|
123
|
-
description,
|
|
124
|
-
color: colorMaybe,
|
|
125
|
-
iconID: unk3
|
|
126
|
-
};
|
|
127
|
-
}
|
|
128
|
-
}
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import { SaveComponent } from "../parser/satisfactory/objects/SaveComponent";
|
|
2
|
-
import { SaveEntity } from "../parser/satisfactory/objects/SaveEntity";
|
|
3
|
-
import { ChunkCompressionInfo } from "../parser/satisfactory/satisfactory-save.class";
|
|
4
|
-
import { ByteWriter } from "./byte/byte-writer.class";
|
|
5
|
-
import { BlueprintConfig, BlueprintHeader } from "./satisfactory/blueprint/blueprint";
|
|
6
|
-
export declare class BlueprintWriter extends ByteWriter {
|
|
7
|
-
constructor();
|
|
8
|
-
static SerializeHeader(writer: ByteWriter, header: BlueprintHeader): void;
|
|
9
|
-
generateChunks(compressionInfo: ChunkCompressionInfo, posAfterHeader: number, onBinaryBeforeCompressing: (binary: ArrayBuffer) => void, onHeader: (header: Uint8Array) => void, onChunk: (chunk: Uint8Array) => void, onFinish: (summary: {
|
|
10
|
-
errors: string[];
|
|
11
|
-
chunkSummary: {
|
|
12
|
-
uncompressedSize: number;
|
|
13
|
-
compressedSize: number;
|
|
14
|
-
}[];
|
|
15
|
-
}) => void): void;
|
|
16
|
-
static SerializeObjects(writer: ByteWriter, objects: (SaveEntity | SaveComponent)[]): void;
|
|
17
|
-
}
|
|
18
|
-
export declare class BlueprintConfigWriter extends ByteWriter {
|
|
19
|
-
constructor();
|
|
20
|
-
static SerializeConfig(writer: ByteWriter, config: BlueprintConfig): void;
|
|
21
|
-
}
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
import { Level } from "../parser/satisfactory/level.class";
|
|
2
|
-
import { SerializeCol4RGBA } from "../parser/satisfactory/structs/util.types";
|
|
3
|
-
import { Alignment } from "./byte/alignment.enum";
|
|
4
|
-
import { ByteWriter } from "./byte/byte-writer.class";
|
|
5
|
-
import { ParserError } from "./error/parser.error";
|
|
6
|
-
import { SaveWriter } from "./save-writer";
|
|
7
|
-
export class BlueprintWriter extends ByteWriter {
|
|
8
|
-
constructor() {
|
|
9
|
-
super(Alignment.LITTLE_ENDIAN);
|
|
10
|
-
}
|
|
11
|
-
static SerializeHeader(writer, header) {
|
|
12
|
-
writer.writeInt32(2); // unknown, seems to always be 02.
|
|
13
|
-
writer.writeInt32(36); // TODO - unknown what it is, but its constant so far.
|
|
14
|
-
writer.writeInt32(211839); // TODO - unknown what it is, but its constant so far.
|
|
15
|
-
// TODO - whatever those are, but they are constant so far.
|
|
16
|
-
writer.writeInt32(4);
|
|
17
|
-
writer.writeInt32(4);
|
|
18
|
-
writer.writeInt32(4);
|
|
19
|
-
// list of item costs.
|
|
20
|
-
writer.writeInt32(header.itemCosts.length);
|
|
21
|
-
for (const itemCost of header.itemCosts) {
|
|
22
|
-
writer.writeInt32(0); //TODO: unk or what
|
|
23
|
-
writer.writeString(itemCost[0]);
|
|
24
|
-
writer.writeInt32(itemCost[1]);
|
|
25
|
-
}
|
|
26
|
-
// list of recipes.
|
|
27
|
-
writer.writeInt32(header.recipeReferences.length);
|
|
28
|
-
for (const recipeReference of header.recipeReferences) {
|
|
29
|
-
writer.writeInt32(0); //TODO: unk or what
|
|
30
|
-
writer.writeString(recipeReference);
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
generateChunks(compressionInfo, posAfterHeader, onBinaryBeforeCompressing, onHeader, onChunk, onFinish) {
|
|
34
|
-
if (posAfterHeader <= 0) {
|
|
35
|
-
throw new ParserError('ParserError', 'seems like this buffer has no header. Please write the header first before you can generate chunks.');
|
|
36
|
-
}
|
|
37
|
-
// send plain header first.
|
|
38
|
-
const header = new Uint8Array(this.bufferArray.slice(0, posAfterHeader));
|
|
39
|
-
onHeader(header);
|
|
40
|
-
// create save body
|
|
41
|
-
this.bufferArray = this.bufferArray.slice(posAfterHeader);
|
|
42
|
-
SaveWriter.GenerateCompressedChunksFromData(this.bufferArray, compressionInfo, onBinaryBeforeCompressing, onChunk, onFinish, this.alignment);
|
|
43
|
-
}
|
|
44
|
-
static SerializeObjects(writer, objects) {
|
|
45
|
-
// object headers
|
|
46
|
-
const headersLenIndicator = writer.getBufferPosition();
|
|
47
|
-
writer.writeInt32(0);
|
|
48
|
-
Level.SerializeObjectHeaders(writer, objects);
|
|
49
|
-
writer.writeBinarySizeFromPosition(headersLenIndicator, headersLenIndicator + 4);
|
|
50
|
-
// objects contents
|
|
51
|
-
Level.SerializeObjectContents(writer, objects, 0);
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
export class BlueprintConfigWriter extends ByteWriter {
|
|
55
|
-
constructor() {
|
|
56
|
-
super(Alignment.LITTLE_ENDIAN);
|
|
57
|
-
}
|
|
58
|
-
static SerializeConfig(writer, config) {
|
|
59
|
-
writer.writeInt32(2); // unknown, seems to always be 02.
|
|
60
|
-
writer.writeString(config.description);
|
|
61
|
-
writer.writeInt32(config.iconID);
|
|
62
|
-
SerializeCol4RGBA(writer, config.color);
|
|
63
|
-
}
|
|
64
|
-
}
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import { Alignment } from "./alignment.enum";
|
|
2
|
-
export declare abstract class ByteReader {
|
|
3
|
-
protected bufferView: DataView;
|
|
4
|
-
protected fileBuffer: ArrayBuffer;
|
|
5
|
-
protected alignment: Alignment;
|
|
6
|
-
protected currentByte: number;
|
|
7
|
-
protected handledByte: number;
|
|
8
|
-
protected maxByte: number;
|
|
9
|
-
protected lastStrRead: number;
|
|
10
|
-
constructor(fileBuffer: ArrayBuffer, alignment: Alignment);
|
|
11
|
-
/**
|
|
12
|
-
* Resets the reader on the given arraybuffer to start from the beginning.
|
|
13
|
-
* @param newFileBuffer the new array buffer to be read.
|
|
14
|
-
*/
|
|
15
|
-
reset(newFileBuffer: ArrayBuffer): void;
|
|
16
|
-
skipBytes(byteLength?: number): void;
|
|
17
|
-
readByte(): number;
|
|
18
|
-
readBytes(count: number): Uint8Array;
|
|
19
|
-
readHex(hexLength: number): string;
|
|
20
|
-
readInt8(): number;
|
|
21
|
-
readUint8(): number;
|
|
22
|
-
readUint16(): number;
|
|
23
|
-
readInt32(): number;
|
|
24
|
-
readUint32(): number;
|
|
25
|
-
readLong(): bigint;
|
|
26
|
-
readFloat(): number;
|
|
27
|
-
readDouble(): number;
|
|
28
|
-
protected getStringInfo(): {
|
|
29
|
-
payload: string;
|
|
30
|
-
counter: number;
|
|
31
|
-
};
|
|
32
|
-
getBufferPosition: () => number;
|
|
33
|
-
getBufferSlice: (begin: number, end: number | undefined) => ArrayBuffer;
|
|
34
|
-
getBufferProgress: () => number;
|
|
35
|
-
getBufferLength: () => number;
|
|
36
|
-
getBuffer: () => ArrayBuffer;
|
|
37
|
-
readString(): string;
|
|
38
|
-
}
|
|
@@ -1,128 +0,0 @@
|
|
|
1
|
-
import { Alignment } from "./alignment.enum";
|
|
2
|
-
export class ByteReader {
|
|
3
|
-
constructor(fileBuffer, alignment) {
|
|
4
|
-
this.currentByte = 0;
|
|
5
|
-
this.handledByte = 0;
|
|
6
|
-
this.maxByte = 0;
|
|
7
|
-
this.lastStrRead = 0;
|
|
8
|
-
this.getBufferPosition = () => this.currentByte;
|
|
9
|
-
this.getBufferSlice = (begin, end) => this.bufferView.buffer.slice(begin, end);
|
|
10
|
-
this.getBufferProgress = () => this.currentByte / this.bufferView.buffer.byteLength;
|
|
11
|
-
this.getBufferLength = () => this.bufferView.buffer.byteLength;
|
|
12
|
-
this.getBuffer = () => this.bufferView.buffer;
|
|
13
|
-
this.alignment = alignment;
|
|
14
|
-
this.reset(fileBuffer);
|
|
15
|
-
}
|
|
16
|
-
/**
|
|
17
|
-
* Resets the reader on the given arraybuffer to start from the beginning.
|
|
18
|
-
* @param newFileBuffer the new array buffer to be read.
|
|
19
|
-
*/
|
|
20
|
-
reset(newFileBuffer) {
|
|
21
|
-
this.fileBuffer = newFileBuffer;
|
|
22
|
-
this.bufferView = new DataView(newFileBuffer, 0, Math.min(102400, this.fileBuffer.byteLength));
|
|
23
|
-
this.maxByte = newFileBuffer.byteLength;
|
|
24
|
-
this.currentByte = 0;
|
|
25
|
-
this.handledByte = 0;
|
|
26
|
-
}
|
|
27
|
-
/*
|
|
28
|
-
* Byte Manipulation
|
|
29
|
-
*/
|
|
30
|
-
skipBytes(byteLength = 1) {
|
|
31
|
-
this.currentByte += byteLength;
|
|
32
|
-
}
|
|
33
|
-
readByte() {
|
|
34
|
-
// TODO can i not just readByte() ??
|
|
35
|
-
return parseInt(this.bufferView.getUint8(this.currentByte++).toString());
|
|
36
|
-
}
|
|
37
|
-
readBytes(count) {
|
|
38
|
-
return new Uint8Array(new Array(count).fill(0).map(pl => this.bufferView.getUint8(this.currentByte++)));
|
|
39
|
-
}
|
|
40
|
-
readHex(hexLength) {
|
|
41
|
-
let hexPart = [];
|
|
42
|
-
for (let i = 0; i < hexLength; i++) {
|
|
43
|
-
let currentHex = String.fromCharCode(this.bufferView.getUint8(this.currentByte++));
|
|
44
|
-
hexPart.push(currentHex);
|
|
45
|
-
}
|
|
46
|
-
return hexPart.join('');
|
|
47
|
-
}
|
|
48
|
-
readInt8() {
|
|
49
|
-
let data = this.bufferView.getInt8(this.currentByte++);
|
|
50
|
-
return data;
|
|
51
|
-
}
|
|
52
|
-
readUint8() {
|
|
53
|
-
let data = this.bufferView.getUint8(this.currentByte++);
|
|
54
|
-
return data;
|
|
55
|
-
}
|
|
56
|
-
readUint16() {
|
|
57
|
-
let data = this.bufferView.getUint16(this.currentByte, this.alignment === Alignment.LITTLE_ENDIAN);
|
|
58
|
-
this.currentByte += 2;
|
|
59
|
-
return data;
|
|
60
|
-
}
|
|
61
|
-
readInt32() {
|
|
62
|
-
let data = this.bufferView.getInt32(this.currentByte, this.alignment === Alignment.LITTLE_ENDIAN);
|
|
63
|
-
this.currentByte += 4;
|
|
64
|
-
return data;
|
|
65
|
-
}
|
|
66
|
-
readUint32() {
|
|
67
|
-
let data = this.bufferView.getUint32(this.currentByte, this.alignment === Alignment.LITTLE_ENDIAN);
|
|
68
|
-
this.currentByte += 4;
|
|
69
|
-
return data;
|
|
70
|
-
}
|
|
71
|
-
readLong() {
|
|
72
|
-
let data = this.bufferView.getBigInt64(this.currentByte, this.alignment === Alignment.LITTLE_ENDIAN);
|
|
73
|
-
this.currentByte += 8;
|
|
74
|
-
return data;
|
|
75
|
-
}
|
|
76
|
-
readFloat() {
|
|
77
|
-
let data = this.bufferView.getFloat32(this.currentByte, this.alignment === Alignment.LITTLE_ENDIAN);
|
|
78
|
-
this.currentByte += 4;
|
|
79
|
-
return data;
|
|
80
|
-
}
|
|
81
|
-
readDouble() {
|
|
82
|
-
let data = this.bufferView.getFloat64(this.currentByte, this.alignment === Alignment.LITTLE_ENDIAN);
|
|
83
|
-
this.currentByte += 8;
|
|
84
|
-
return data;
|
|
85
|
-
}
|
|
86
|
-
getStringInfo() {
|
|
87
|
-
let payload = '';
|
|
88
|
-
let counter = this.currentByte;
|
|
89
|
-
try {
|
|
90
|
-
let strLength = this.bufferView.getInt32(this.currentByte, this.alignment === Alignment.LITTLE_ENDIAN);
|
|
91
|
-
counter += 4;
|
|
92
|
-
payload = new Array(strLength - 1).fill('').map(c => String.fromCharCode(this.bufferView.getUint8(counter++))).join('');
|
|
93
|
-
}
|
|
94
|
-
catch (error) { }
|
|
95
|
-
this.currentByte -= counter;
|
|
96
|
-
return { payload, counter };
|
|
97
|
-
}
|
|
98
|
-
readString() {
|
|
99
|
-
let strLength = this.readInt32();
|
|
100
|
-
this.lastStrRead = strLength;
|
|
101
|
-
let startBytes = this.currentByte;
|
|
102
|
-
if (strLength === 0) {
|
|
103
|
-
return '';
|
|
104
|
-
}
|
|
105
|
-
// Range error!
|
|
106
|
-
if (strLength > (this.bufferView.buffer.byteLength - this.currentByte)) {
|
|
107
|
-
let errorMessage = `Cannot read string of length ${strLength} at position ${this.currentByte} as it exceeds the end at ${this.bufferView.buffer.byteLength}`;
|
|
108
|
-
throw new Error(errorMessage);
|
|
109
|
-
}
|
|
110
|
-
// it uses UTF16 if text is non-ascii, even if it would fit into UTF8.
|
|
111
|
-
if (strLength < 0) {
|
|
112
|
-
const string = new Array(-strLength - 1).fill('').map(c => String.fromCharCode(this.readUint16()));
|
|
113
|
-
this.currentByte += 2;
|
|
114
|
-
return string.join('');
|
|
115
|
-
}
|
|
116
|
-
//default UTF-8
|
|
117
|
-
try {
|
|
118
|
-
const string = new Array(strLength - 1).fill('').map(c => String.fromCharCode(this.readUint8()));
|
|
119
|
-
this.currentByte += 1;
|
|
120
|
-
return string.join('');
|
|
121
|
-
}
|
|
122
|
-
catch (error) {
|
|
123
|
-
let errorMessage = `Cannot read UTF8 string of length ${strLength} at position ${this.currentByte}.`;
|
|
124
|
-
console.log(errorMessage, error);
|
|
125
|
-
throw error;
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
}
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import { Alignment } from "./alignment.enum";
|
|
2
|
-
export declare abstract class ByteWriter {
|
|
3
|
-
protected alignment: Alignment;
|
|
4
|
-
protected bufferArray: ArrayBuffer;
|
|
5
|
-
protected bufferView: DataView;
|
|
6
|
-
protected currentByte: number;
|
|
7
|
-
constructor(alignment: Alignment, bufferSize?: number);
|
|
8
|
-
skipBytes(count?: number): void;
|
|
9
|
-
jumpTo(pos: number): void;
|
|
10
|
-
writeByte(value: number): void;
|
|
11
|
-
writeBytesArray(bytes: number[]): void;
|
|
12
|
-
writeBytes(bytes: Uint8Array): void;
|
|
13
|
-
writeInt8(value: number): void;
|
|
14
|
-
writeUint8(value: number): void;
|
|
15
|
-
writeInt16(value: number): void;
|
|
16
|
-
writeUint16(value: number): void;
|
|
17
|
-
writeInt32(value: number): void;
|
|
18
|
-
writeUint32(value: number): void;
|
|
19
|
-
writeInt64(value: bigint): void;
|
|
20
|
-
writeUint64(value: bigint): void;
|
|
21
|
-
writeFloat(value: number): void;
|
|
22
|
-
writeDouble(value: number): void;
|
|
23
|
-
writeString(value: string): void;
|
|
24
|
-
static IsASCIICompatible: (value: string) => boolean;
|
|
25
|
-
getBufferPosition: () => number;
|
|
26
|
-
getBufferSlice: (start: number, end?: number) => ArrayBuffer;
|
|
27
|
-
writeBinarySizeFromPosition(lenIndicatorPos: number, start: number): void;
|
|
28
|
-
/**
|
|
29
|
-
* automatically extends the current buffer if the given space exceeds the available rest capacity of the current buffer.
|
|
30
|
-
* @param countNeededBytes the needed space
|
|
31
|
-
* @param factor how big the appended buffer should be in comparison to the current one. Values >= 1 make sense.
|
|
32
|
-
*/
|
|
33
|
-
protected extendBufferIfNeeded(countNeededBytes: number, factor?: number): void;
|
|
34
|
-
protected truncateBuffer(): void;
|
|
35
|
-
endWriting(): ArrayBuffer;
|
|
36
|
-
static ToInt32(num: number): Uint8Array;
|
|
37
|
-
static AppendBuffer(buffer1: ArrayBuffer, buffer2: ArrayBuffer): ArrayBuffer;
|
|
38
|
-
}
|
|
@@ -1,146 +0,0 @@
|
|
|
1
|
-
import { Alignment } from "./alignment.enum";
|
|
2
|
-
class ByteWriter {
|
|
3
|
-
constructor(alignment, bufferSize = 500) {
|
|
4
|
-
this.getBufferPosition = () => this.currentByte;
|
|
5
|
-
this.getBufferSlice = (start, end) => this.bufferArray.slice(start, end);
|
|
6
|
-
this.alignment = alignment;
|
|
7
|
-
this.bufferArray = new ArrayBuffer(bufferSize);
|
|
8
|
-
this.bufferView = new DataView(this.bufferArray);
|
|
9
|
-
this.currentByte = 0;
|
|
10
|
-
}
|
|
11
|
-
/*
|
|
12
|
-
* Byte Manipulation
|
|
13
|
-
*/
|
|
14
|
-
skipBytes(count = 1) {
|
|
15
|
-
this.extendBufferIfNeeded(count);
|
|
16
|
-
this.currentByte += count;
|
|
17
|
-
}
|
|
18
|
-
jumpTo(pos) {
|
|
19
|
-
const count = pos - this.getBufferPosition();
|
|
20
|
-
this.skipBytes(count);
|
|
21
|
-
}
|
|
22
|
-
writeByte(value) {
|
|
23
|
-
this.extendBufferIfNeeded(1);
|
|
24
|
-
this.bufferView.setUint8(this.currentByte, value);
|
|
25
|
-
this.currentByte += 1;
|
|
26
|
-
}
|
|
27
|
-
writeBytesArray(bytes) {
|
|
28
|
-
this.writeBytes(new Uint8Array(bytes));
|
|
29
|
-
}
|
|
30
|
-
writeBytes(bytes) {
|
|
31
|
-
this.extendBufferIfNeeded(bytes.length);
|
|
32
|
-
bytes.forEach(byte => this.bufferView.setUint8(this.currentByte++, byte));
|
|
33
|
-
}
|
|
34
|
-
writeInt8(value) {
|
|
35
|
-
this.extendBufferIfNeeded(1);
|
|
36
|
-
this.bufferView.setInt8(this.currentByte, value);
|
|
37
|
-
this.currentByte += 1;
|
|
38
|
-
}
|
|
39
|
-
writeUint8(value) {
|
|
40
|
-
this.writeByte(value);
|
|
41
|
-
}
|
|
42
|
-
writeInt16(value) {
|
|
43
|
-
this.extendBufferIfNeeded(2);
|
|
44
|
-
this.bufferView.setInt16(this.currentByte, value, this.alignment === Alignment.LITTLE_ENDIAN);
|
|
45
|
-
this.currentByte += 2;
|
|
46
|
-
}
|
|
47
|
-
writeUint16(value) {
|
|
48
|
-
this.extendBufferIfNeeded(2);
|
|
49
|
-
this.bufferView.setUint16(this.currentByte, value, this.alignment === Alignment.LITTLE_ENDIAN);
|
|
50
|
-
this.currentByte += 2;
|
|
51
|
-
}
|
|
52
|
-
writeInt32(value) {
|
|
53
|
-
this.extendBufferIfNeeded(4);
|
|
54
|
-
this.bufferView.setInt32(this.currentByte, value, this.alignment === Alignment.LITTLE_ENDIAN);
|
|
55
|
-
this.currentByte += 4;
|
|
56
|
-
}
|
|
57
|
-
writeUint32(value) {
|
|
58
|
-
this.extendBufferIfNeeded(4);
|
|
59
|
-
this.bufferView.setUint32(this.currentByte, value, this.alignment === Alignment.LITTLE_ENDIAN);
|
|
60
|
-
this.currentByte += 4;
|
|
61
|
-
}
|
|
62
|
-
writeInt64(value) {
|
|
63
|
-
this.extendBufferIfNeeded(8);
|
|
64
|
-
this.bufferView.setBigInt64(this.currentByte, value, this.alignment === Alignment.LITTLE_ENDIAN);
|
|
65
|
-
this.currentByte += 8;
|
|
66
|
-
}
|
|
67
|
-
writeUint64(value) {
|
|
68
|
-
this.extendBufferIfNeeded(8);
|
|
69
|
-
this.bufferView.setBigUint64(this.currentByte, value, this.alignment === Alignment.LITTLE_ENDIAN);
|
|
70
|
-
this.currentByte += 8;
|
|
71
|
-
}
|
|
72
|
-
writeFloat(value) {
|
|
73
|
-
this.extendBufferIfNeeded(4);
|
|
74
|
-
this.bufferView.setFloat32(this.currentByte, value, this.alignment === Alignment.LITTLE_ENDIAN);
|
|
75
|
-
this.currentByte += 4;
|
|
76
|
-
}
|
|
77
|
-
writeDouble(value) {
|
|
78
|
-
this.extendBufferIfNeeded(8);
|
|
79
|
-
this.bufferView.setFloat64(this.currentByte, value, this.alignment === Alignment.LITTLE_ENDIAN);
|
|
80
|
-
this.currentByte += 8;
|
|
81
|
-
}
|
|
82
|
-
writeString(value) {
|
|
83
|
-
if (value.length === 0) {
|
|
84
|
-
this.writeInt32(0);
|
|
85
|
-
return;
|
|
86
|
-
}
|
|
87
|
-
// if it's safe to use ASCII, use UTF8.
|
|
88
|
-
if (ByteWriter.IsASCIICompatible(value)) {
|
|
89
|
-
this.writeInt32(value.length + 1);
|
|
90
|
-
for (let i = 0; i < value.length; i++) {
|
|
91
|
-
this.writeByte(value.charCodeAt(i));
|
|
92
|
-
}
|
|
93
|
-
this.writeUint8(0);
|
|
94
|
-
}
|
|
95
|
-
// write UTF16
|
|
96
|
-
else {
|
|
97
|
-
this.writeInt32(-value.length - 1);
|
|
98
|
-
for (let i = 0; i < value.length; i++) {
|
|
99
|
-
this.writeUint16(value.charCodeAt(i));
|
|
100
|
-
}
|
|
101
|
-
this.writeUint16(0);
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
writeBinarySizeFromPosition(lenIndicatorPos, start) {
|
|
105
|
-
const after = this.getBufferPosition();
|
|
106
|
-
const writtenBytes = after - start;
|
|
107
|
-
this.jumpTo(lenIndicatorPos);
|
|
108
|
-
this.writeInt32(writtenBytes);
|
|
109
|
-
this.jumpTo(after);
|
|
110
|
-
}
|
|
111
|
-
/**
|
|
112
|
-
* automatically extends the current buffer if the given space exceeds the available rest capacity of the current buffer.
|
|
113
|
-
* @param countNeededBytes the needed space
|
|
114
|
-
* @param factor how big the appended buffer should be in comparison to the current one. Values >= 1 make sense.
|
|
115
|
-
*/
|
|
116
|
-
extendBufferIfNeeded(countNeededBytes, factor = 1.5) {
|
|
117
|
-
if (this.currentByte + countNeededBytes > this.bufferView.byteLength) {
|
|
118
|
-
this.bufferArray = ByteWriter.AppendBuffer(this.bufferArray, new ArrayBuffer(factor * this.bufferArray.byteLength));
|
|
119
|
-
this.bufferView = new DataView(this.bufferArray);
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
truncateBuffer() {
|
|
123
|
-
this.bufferArray = this.bufferArray.slice(0, this.currentByte);
|
|
124
|
-
}
|
|
125
|
-
endWriting() {
|
|
126
|
-
this.truncateBuffer();
|
|
127
|
-
return this.bufferArray;
|
|
128
|
-
}
|
|
129
|
-
static ToInt32(num) {
|
|
130
|
-
return new Uint8Array([
|
|
131
|
-
(num & 0xff000000) >> 24,
|
|
132
|
-
(num & 0x00ff0000) >> 16,
|
|
133
|
-
(num & 0x0000ff00) >> 8,
|
|
134
|
-
(num & 0x000000ff)
|
|
135
|
-
]);
|
|
136
|
-
}
|
|
137
|
-
static AppendBuffer(buffer1, buffer2) {
|
|
138
|
-
var tmp = new Uint8Array(buffer1.byteLength + buffer2.byteLength);
|
|
139
|
-
tmp.set(new Uint8Array(buffer1), 0);
|
|
140
|
-
tmp.set(new Uint8Array(buffer2), buffer1.byteLength);
|
|
141
|
-
return tmp.buffer;
|
|
142
|
-
}
|
|
143
|
-
;
|
|
144
|
-
}
|
|
145
|
-
ByteWriter.IsASCIICompatible = (value) => /^[\x00-\x7F]*$/.test(value);
|
|
146
|
-
export { ByteWriter };
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
export declare class ParserError extends Error {
|
|
2
|
-
constructor(name: string, message: string);
|
|
3
|
-
}
|
|
4
|
-
export declare class UnsupportedVersionError extends ParserError {
|
|
5
|
-
constructor(message?: string);
|
|
6
|
-
}
|
|
7
|
-
export declare class CorruptSaveError extends ParserError {
|
|
8
|
-
constructor(message?: string);
|
|
9
|
-
}
|
|
10
|
-
export declare class CompressionLibraryError extends ParserError {
|
|
11
|
-
constructor(message?: string);
|
|
12
|
-
}
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
export class ParserError extends Error {
|
|
2
|
-
constructor(name, message) {
|
|
3
|
-
super(message);
|
|
4
|
-
this.name = name;
|
|
5
|
-
}
|
|
6
|
-
}
|
|
7
|
-
export class UnsupportedVersionError extends ParserError {
|
|
8
|
-
constructor(message) {
|
|
9
|
-
super('UnsupportedVersionError', message ?? 'This save version is not supported.');
|
|
10
|
-
}
|
|
11
|
-
}
|
|
12
|
-
export class CorruptSaveError extends ParserError {
|
|
13
|
-
constructor(message) {
|
|
14
|
-
super('CorruptSaveError', message ?? 'This save data is most likely corrupt.');
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
export class CompressionLibraryError extends ParserError {
|
|
18
|
-
constructor(message) {
|
|
19
|
-
super('CompressionLibraryError', message ?? 'Failed to compress/decompress save data.');
|
|
20
|
-
}
|
|
21
|
-
}
|