pw-buffer 2.0.1 → 3.0.0
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/README.md +260 -15
- package/dist/MppcCompressorTransform.d.ts +8 -0
- package/dist/MppcCompressorTransform.js +15 -0
- package/dist/MppcDecompressorTransform.d.ts +8 -0
- package/dist/MppcDecompressorTransform.js +15 -0
- package/dist/PwBuffer.d.ts +9 -10
- package/dist/PwBuffer.js +41 -58
- package/dist/PwBufferOptions.d.ts +2 -0
- package/dist/PwBufferOptions.js +2 -0
- package/dist/index.d.ts +6 -1
- package/dist/index.js +25 -4
- package/dist/mppc.d.ts +23 -0
- package/dist/mppc.js +445 -0
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.js +5 -0
- package/dist/utils/write-cuint-to-pw-buffer.d.ts +2 -0
- package/dist/utils/write-cuint-to-pw-buffer.js +35 -0
- package/package.json +37 -9
package/README.md
CHANGED
|
@@ -1,18 +1,263 @@
|
|
|
1
|
-
#
|
|
2
|
-
PW Buffer
|
|
1
|
+
# Perfect World binary utils
|
|
3
2
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
3
|
+
A small TypeScript/Node.js library built on top of [extended-buffer](https://github.com/mvcbox/node-extended-buffer) that adds helpers commonly found in some Perfect World / PW-style binary protocols:
|
|
4
|
+
|
|
5
|
+
- **CUInt** (compressed unsigned integer) encoding/decoding
|
|
6
|
+
- **PW strings**: `CUInt` byte-length prefix + `utf16le` payload
|
|
7
|
+
- **PW octets**: `CUInt` byte-length prefix + raw bytes
|
|
8
|
+
- **MPPC** compressor/decompressor (stream-friendly) plus optional Node.js `Transform` wrappers
|
|
9
|
+
|
|
10
|
+
## Install
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
npm i pw-buffer
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Quick start
|
|
17
|
+
|
|
18
|
+
```ts
|
|
19
|
+
import { PwBuffer } from 'pw-buffer';
|
|
20
|
+
|
|
21
|
+
const b = new PwBuffer();
|
|
22
|
+
|
|
23
|
+
b.writeCUInt(123);
|
|
24
|
+
b.writePwString('Hello');
|
|
25
|
+
b.writePwOctets(Buffer.from([1, 2, 3]));
|
|
26
|
+
|
|
27
|
+
// Read back
|
|
28
|
+
console.log(b.readCUInt()); // 123
|
|
29
|
+
console.log(b.readPwString()); // "Hello"
|
|
30
|
+
console.log(b.readPwOctets().nativeBufferView); // <Buffer 01 02 03>
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## What is `PwBuffer`?
|
|
34
|
+
|
|
35
|
+
`PwBuffer` extends `ExtendedBuffer` from the `extended-buffer` package. That means you get all of `ExtendedBuffer` features (growable buffer, internal read pointer, append/prepend writes, etc.), plus PW-specific helpers.
|
|
36
|
+
|
|
37
|
+
### Append vs prepend (`unshift`)
|
|
38
|
+
|
|
39
|
+
Most write methods support an optional `unshift?: boolean` flag:
|
|
40
|
+
|
|
41
|
+
- `unshift = false` (default): append to the end
|
|
42
|
+
- `unshift = true`: prepend to the start
|
|
43
|
+
|
|
44
|
+
This is useful when you want to write a payload first and then prepend headers (length, opcode, etc.).
|
|
45
|
+
|
|
46
|
+
Example: build a length-prefixed packet
|
|
47
|
+
|
|
48
|
+
```ts
|
|
49
|
+
import { PwBuffer } from 'pw-buffer';
|
|
50
|
+
|
|
51
|
+
const pkt = new PwBuffer();
|
|
52
|
+
|
|
53
|
+
pkt.writePwString('Alice'); // body
|
|
54
|
+
pkt.writePwString('Bob'); //
|
|
55
|
+
|
|
56
|
+
// Prepend total byte length (example protocol convention)
|
|
57
|
+
pkt.writeCUInt(pkt.length, true); // length
|
|
58
|
+
pkt.writeCUInt(0x1234, true); // opcode
|
|
59
|
+
|
|
60
|
+
console.log(pkt.nativeBufferView);
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## API
|
|
64
|
+
|
|
65
|
+
The package exports:
|
|
66
|
+
|
|
67
|
+
```ts
|
|
68
|
+
export * from './utils';
|
|
69
|
+
export { PwBuffer } from './PwBuffer';
|
|
70
|
+
export type { PwBufferOptions } from './PwBufferOptions';
|
|
71
|
+
export { MppcCompressor, MppcDecompressor } from './mppc';
|
|
72
|
+
export { MppcCompressorTransform } from './MppcCompressorTransform';
|
|
73
|
+
export { MppcDecompressorTransform } from './MppcDecompressorTransform';
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### `PwBuffer(options?: PwBufferOptions)`
|
|
77
|
+
|
|
78
|
+
`PwBufferOptions` is currently the same as `ExtendedBufferOptions`:
|
|
79
|
+
|
|
80
|
+
- `capacity?: number` – initial capacity (bytes)
|
|
81
|
+
- `capacityStep?: number` – resize step (bytes)
|
|
82
|
+
|
|
83
|
+
Example:
|
|
84
|
+
|
|
85
|
+
```ts
|
|
86
|
+
import { PwBuffer } from 'pw-buffer';
|
|
87
|
+
|
|
88
|
+
const b = new PwBuffer({ capacity: 64 * 1024, capacityStep: 16 * 1024 });
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### `isReadableCUInt(): boolean`
|
|
92
|
+
|
|
93
|
+
Checks whether a full `CUInt` value can be read at the current read pointer without running out of data.
|
|
94
|
+
|
|
95
|
+
This is handy when you parse a stream and may receive partial frames.
|
|
96
|
+
|
|
97
|
+
```ts
|
|
98
|
+
if (b.isReadableCUInt()) {
|
|
99
|
+
const len = b.readCUInt();
|
|
100
|
+
// ...
|
|
17
101
|
}
|
|
18
102
|
```
|
|
103
|
+
|
|
104
|
+
### `readCUInt(): number`
|
|
105
|
+
|
|
106
|
+
Reads a **compressed unsigned integer** at the current read pointer.
|
|
107
|
+
|
|
108
|
+
- Returns a JavaScript `number` in the range **0…0xFFFFFFFF**.
|
|
109
|
+
- Advances the read pointer.
|
|
110
|
+
|
|
111
|
+
If there are not enough readable bytes, underlying `extended-buffer` reads may throw.
|
|
112
|
+
|
|
113
|
+
### `writeCUInt(value: number, unshift?: boolean): this`
|
|
114
|
+
|
|
115
|
+
Writes a **compressed unsigned integer**.
|
|
116
|
+
|
|
117
|
+
- `value` must be an **integer** in **0…0xFFFFFFFF**.
|
|
118
|
+
- If the value is outside the allowed range, it throws an `ExtendedBufferRangeError('CUINT_VALUE_OUT_OF_RANGE')`.
|
|
119
|
+
|
|
120
|
+
```ts
|
|
121
|
+
b.writeCUInt(1);
|
|
122
|
+
b.writeCUInt(127);
|
|
123
|
+
b.writeCUInt(128);
|
|
124
|
+
b.writeCUInt(0xFFFFFFFF);
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### CUInt encoding format
|
|
128
|
+
|
|
129
|
+
CUInt uses a leading-bit pattern to choose the byte width:
|
|
130
|
+
|
|
131
|
+
| Range | Encoded bytes | Notes |
|
|
132
|
+
|------:|:-------------:|---------------------------------|
|
|
133
|
+
| `0x00000000 … 0x0000007F` | 1 | `0xxxxxxx` |
|
|
134
|
+
| `0x00000080 … 0x00003FFF` | 2 | stored as `value \| 0x8000` |
|
|
135
|
+
| `0x00004000 … 0x1FFFFFFF` | 4 | stored as `value \| 0xC0000000` |
|
|
136
|
+
| `0x20000000 … 0xFFFFFFFF` | 5 | marker `0xE0` + 4-byte BE value |
|
|
137
|
+
|
|
138
|
+
> Implementation note: in the 5-byte case, the first byte is the marker `0xE0`, followed by the 32-bit big-endian value.
|
|
139
|
+
|
|
140
|
+
### `readPwString(): string`
|
|
141
|
+
|
|
142
|
+
Reads a PW string:
|
|
143
|
+
|
|
144
|
+
1. Reads a `CUInt` **byte length** `N`
|
|
145
|
+
2. Reads `N` bytes and decodes them as `utf16le`
|
|
146
|
+
|
|
147
|
+
```ts
|
|
148
|
+
const s = b.readPwString();
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### `writePwString(value: string, unshift?: boolean): this`
|
|
152
|
+
|
|
153
|
+
Writes a PW string:
|
|
154
|
+
|
|
155
|
+
1. Encodes the string to bytes using `utf16le`
|
|
156
|
+
2. Writes `CUInt(byteLength)`
|
|
157
|
+
3. Writes the bytes
|
|
158
|
+
|
|
159
|
+
```ts
|
|
160
|
+
b.writePwString('Hello');
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
### `readPwOctets(): PwBuffer`
|
|
164
|
+
|
|
165
|
+
Reads PW octets:
|
|
166
|
+
|
|
167
|
+
1. Reads a `CUInt` **byte length** `N`
|
|
168
|
+
2. Reads `N` raw bytes
|
|
169
|
+
3. Returns a **new** `PwBuffer` containing only those bytes
|
|
170
|
+
|
|
171
|
+
```ts
|
|
172
|
+
const oct = b.readPwOctets();
|
|
173
|
+
console.log(oct.length);
|
|
174
|
+
console.log(oct.nativeBufferView);
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
### `writePwOctets(octets: ExtendedBuffer | Buffer, unshift?: boolean): this`
|
|
178
|
+
|
|
179
|
+
Writes PW octets:
|
|
180
|
+
|
|
181
|
+
1. Writes `CUInt(octets.length)`
|
|
182
|
+
2. Writes raw `octets` bytes
|
|
183
|
+
|
|
184
|
+
```ts
|
|
185
|
+
b.writePwOctets(Buffer.from([0xde, 0xad, 0xbe, 0xef]));
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
## MPPC compression
|
|
189
|
+
|
|
190
|
+
The library includes a streaming MPPC compressor and decompressor:
|
|
191
|
+
|
|
192
|
+
- `MppcCompressor.update(chunk: Buffer): Buffer`
|
|
193
|
+
- `MppcDecompressor.update(chunk: Buffer): Buffer`
|
|
194
|
+
|
|
195
|
+
Both are **stateful**. Create a new instance per independent stream/connection.
|
|
196
|
+
|
|
197
|
+
### Basic usage
|
|
198
|
+
|
|
199
|
+
```ts
|
|
200
|
+
import { MppcCompressor, MppcDecompressor } from 'pw-buffer';
|
|
201
|
+
|
|
202
|
+
const input = Buffer.from('hello hello hello', 'utf8');
|
|
203
|
+
|
|
204
|
+
const c = new MppcCompressor();
|
|
205
|
+
const compressed = c.update(input);
|
|
206
|
+
|
|
207
|
+
const d = new MppcDecompressor();
|
|
208
|
+
const decompressed = d.update(compressed);
|
|
209
|
+
|
|
210
|
+
console.log(decompressed.toString('utf8')); // "hello hello hello"
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
### Streaming usage (chunked)
|
|
214
|
+
|
|
215
|
+
```ts
|
|
216
|
+
import { MppcCompressor, MppcDecompressor } from 'pw-buffer';
|
|
217
|
+
|
|
218
|
+
const c = new MppcCompressor();
|
|
219
|
+
const d = new MppcDecompressor();
|
|
220
|
+
|
|
221
|
+
const part1 = Buffer.from('hello ', 'utf8');
|
|
222
|
+
const part2 = Buffer.from('world', 'utf8');
|
|
223
|
+
|
|
224
|
+
const c1 = c.update(part1);
|
|
225
|
+
const c2 = c.update(part2);
|
|
226
|
+
|
|
227
|
+
const out1 = d.update(c1);
|
|
228
|
+
const out2 = d.update(c2);
|
|
229
|
+
|
|
230
|
+
console.log(Buffer.concat([out1, out2]).toString('utf8')); // "hello world"
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
## MPPC `Transform` streams
|
|
234
|
+
|
|
235
|
+
If you prefer Node.js stream piping, you can use the provided transforms:
|
|
236
|
+
|
|
237
|
+
- `MppcCompressorTransform`
|
|
238
|
+
- `MppcDecompressorTransform`
|
|
239
|
+
|
|
240
|
+
```ts
|
|
241
|
+
import fs from 'node:fs';
|
|
242
|
+
import { MppcCompressorTransform, MppcDecompressorTransform } from 'pw-buffer';
|
|
243
|
+
|
|
244
|
+
// Compress a file
|
|
245
|
+
fs.createReadStream('input.bin')
|
|
246
|
+
.pipe(new MppcCompressorTransform())
|
|
247
|
+
.pipe(fs.createWriteStream('input.bin.mppc'));
|
|
248
|
+
|
|
249
|
+
// Decompress a file
|
|
250
|
+
fs.createReadStream('input.bin.mppc')
|
|
251
|
+
.pipe(new MppcDecompressorTransform())
|
|
252
|
+
.pipe(fs.createWriteStream('input.bin'));
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
## Error handling tips
|
|
256
|
+
|
|
257
|
+
- Before reading from a buffer fed by a socket/stream, prefer guard checks such as `isReadable(size)` (from `ExtendedBuffer`) and `isReadableCUInt()`.
|
|
258
|
+
- `writeCUInt()` validates the value is an integer and within `0…0xFFFFFFFF`.
|
|
259
|
+
- If you need the full set of buffer operations (pointer control, reading/writing primitives, etc.), refer to the upstream [extended-buffer](https://github.com/mvcbox/node-extended-buffer) documentation.
|
|
260
|
+
|
|
261
|
+
## License
|
|
262
|
+
|
|
263
|
+
MIT (see the package metadata).
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
import { MppcCompressor } from './mppc';
|
|
3
|
+
import { Transform, TransformOptions } from 'stream';
|
|
4
|
+
export declare class MppcCompressorTransform extends Transform {
|
|
5
|
+
protected readonly _mppcCompressor: MppcCompressor;
|
|
6
|
+
constructor(transformOptions?: TransformOptions);
|
|
7
|
+
_transform(chunk: Buffer | null, encoding: string, callback: Function): void;
|
|
8
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MppcCompressorTransform = void 0;
|
|
4
|
+
const mppc_1 = require("./mppc");
|
|
5
|
+
const stream_1 = require("stream");
|
|
6
|
+
class MppcCompressorTransform extends stream_1.Transform {
|
|
7
|
+
constructor(transformOptions) {
|
|
8
|
+
super(transformOptions);
|
|
9
|
+
this._mppcCompressor = new mppc_1.MppcCompressor();
|
|
10
|
+
}
|
|
11
|
+
_transform(chunk, encoding, callback) {
|
|
12
|
+
callback(null, chunk ? this._mppcCompressor.update(chunk) : null);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
exports.MppcCompressorTransform = MppcCompressorTransform;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
import { MppcDecompressor } from './mppc';
|
|
3
|
+
import { Transform, TransformOptions } from 'stream';
|
|
4
|
+
export declare class MppcDecompressorTransform extends Transform {
|
|
5
|
+
protected readonly _mppcDecompressor: MppcDecompressor;
|
|
6
|
+
constructor(transformOptions?: TransformOptions);
|
|
7
|
+
_transform(chunk: Buffer | null, encoding: string, callback: Function): void;
|
|
8
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MppcDecompressorTransform = void 0;
|
|
4
|
+
const mppc_1 = require("./mppc");
|
|
5
|
+
const stream_1 = require("stream");
|
|
6
|
+
class MppcDecompressorTransform extends stream_1.Transform {
|
|
7
|
+
constructor(transformOptions) {
|
|
8
|
+
super(transformOptions);
|
|
9
|
+
this._mppcDecompressor = new mppc_1.MppcDecompressor();
|
|
10
|
+
}
|
|
11
|
+
_transform(chunk, encoding, callback) {
|
|
12
|
+
callback(null, chunk ? this._mppcDecompressor.update(chunk) : null);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
exports.MppcDecompressorTransform = MppcDecompressorTransform;
|
package/dist/PwBuffer.d.ts
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
|
-
import { ExtendedBuffer
|
|
3
|
-
|
|
4
|
-
}
|
|
2
|
+
import { ExtendedBuffer } from 'extended-buffer';
|
|
3
|
+
import type { PwBufferOptions } from './PwBufferOptions';
|
|
5
4
|
export declare class PwBuffer extends ExtendedBuffer {
|
|
5
|
+
protected createInstance(options?: PwBufferOptions): this;
|
|
6
6
|
isReadableCUInt(): boolean;
|
|
7
|
-
readCUInt(
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
writePwOctets(octets: ExtendedBuffer | Buffer, unshift?: boolean, noAssert?: boolean): this;
|
|
7
|
+
readCUInt(): number;
|
|
8
|
+
writeCUInt(value: number, unshift?: boolean): this;
|
|
9
|
+
readPwString(): string;
|
|
10
|
+
writePwString(string: string, unshift?: boolean): this;
|
|
11
|
+
readPwOctets(): this;
|
|
12
|
+
writePwOctets(octets: ExtendedBuffer | Buffer, unshift?: boolean): this;
|
|
14
13
|
}
|
package/dist/PwBuffer.js
CHANGED
|
@@ -1,14 +1,20 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
|
|
3
|
+
exports.PwBuffer = void 0;
|
|
4
4
|
const buffer_1 = require("buffer");
|
|
5
|
+
const utils = require("./utils");
|
|
6
|
+
const extended_buffer_1 = require("extended-buffer");
|
|
5
7
|
class PwBuffer extends extended_buffer_1.ExtendedBuffer {
|
|
8
|
+
createInstance(options) {
|
|
9
|
+
const ThisClass = this.constructor;
|
|
10
|
+
return new ThisClass(options);
|
|
11
|
+
}
|
|
6
12
|
isReadableCUInt() {
|
|
7
13
|
if (!this.isReadable(1)) {
|
|
8
14
|
return false;
|
|
9
15
|
}
|
|
10
16
|
let value = this.readUIntBE(1);
|
|
11
|
-
|
|
17
|
+
this._pointer--;
|
|
12
18
|
switch (value & 0xE0) {
|
|
13
19
|
case 0xE0:
|
|
14
20
|
return this.isReadable(5);
|
|
@@ -20,78 +26,55 @@ class PwBuffer extends extended_buffer_1.ExtendedBuffer {
|
|
|
20
26
|
}
|
|
21
27
|
return true;
|
|
22
28
|
}
|
|
23
|
-
readCUInt(
|
|
24
|
-
let value = this.readUIntBE(1
|
|
29
|
+
readCUInt() {
|
|
30
|
+
let value = this.readUIntBE(1);
|
|
25
31
|
switch (value & 0xE0) {
|
|
26
|
-
case 0xE0:
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
--this._pointer;
|
|
34
|
-
return this.readUIntBE(2, noAssert) & 0x3FFF;
|
|
35
|
-
}
|
|
36
|
-
return value;
|
|
37
|
-
}
|
|
38
|
-
_writeCUIntToBuffer(buffer, value, noAssert) {
|
|
39
|
-
let tmp;
|
|
40
|
-
if (value < 0x80) {
|
|
41
|
-
buffer.writeUIntBE(value, 1, false, noAssert);
|
|
42
|
-
}
|
|
43
|
-
else if (value < 0x4000) {
|
|
44
|
-
if ((tmp = value | 0x8000) < 0) {
|
|
45
|
-
buffer.writeIntBE(tmp, 2, false, noAssert);
|
|
46
|
-
}
|
|
47
|
-
else {
|
|
48
|
-
buffer.writeUIntBE(tmp, 2, false, noAssert);
|
|
32
|
+
case 0xE0: {
|
|
33
|
+
try {
|
|
34
|
+
return this.readUIntBE(4);
|
|
35
|
+
}
|
|
36
|
+
catch (e) {
|
|
37
|
+
this._pointer--;
|
|
38
|
+
}
|
|
49
39
|
}
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
buffer.writeIntBE(tmp, 4, false, noAssert);
|
|
40
|
+
case 0xC0: {
|
|
41
|
+
this._pointer--;
|
|
42
|
+
return this.readUIntBE(4) & 0x1FFFFFFF;
|
|
54
43
|
}
|
|
55
|
-
|
|
56
|
-
|
|
44
|
+
case 0x80:
|
|
45
|
+
case 0xA0: {
|
|
46
|
+
this._pointer--;
|
|
47
|
+
return this.readUIntBE(2) & 0x3FFF;
|
|
57
48
|
}
|
|
58
49
|
}
|
|
59
|
-
|
|
60
|
-
buffer.writeUIntBE(0xE0, 1, false, noAssert).writeUIntBE(value, 4, false, noAssert);
|
|
61
|
-
}
|
|
62
|
-
return this;
|
|
50
|
+
return value;
|
|
63
51
|
}
|
|
64
|
-
writeCUInt(value, unshift
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
let buffer = new ThisClass({
|
|
68
|
-
maxBufferLength: 5
|
|
69
|
-
});
|
|
70
|
-
buffer.allocEnd(buffer.getFreeSpace());
|
|
71
|
-
return this._writeCUIntToBuffer(buffer, value, noAssert)._writeNativeBuffer(buffer.buffer, true);
|
|
72
|
-
}
|
|
73
|
-
return this._writeCUIntToBuffer(this, value, noAssert);
|
|
52
|
+
writeCUInt(value, unshift) {
|
|
53
|
+
utils.writeCUIntToPwBuffer(this, value, unshift);
|
|
54
|
+
return this;
|
|
74
55
|
}
|
|
75
|
-
readPwString(
|
|
76
|
-
return this.readString(this.readCUInt(
|
|
56
|
+
readPwString() {
|
|
57
|
+
return this.readString(this.readCUInt(), 'utf16le');
|
|
77
58
|
}
|
|
78
|
-
writePwString(string, unshift
|
|
59
|
+
writePwString(string, unshift) {
|
|
60
|
+
const bytes = buffer_1.Buffer.from(string, 'utf16le');
|
|
79
61
|
if (unshift) {
|
|
80
|
-
return this.
|
|
62
|
+
return this.writeNativeBuffer(bytes, true).writeCUInt(bytes.length, true);
|
|
81
63
|
}
|
|
82
|
-
return this.writeCUInt(
|
|
64
|
+
return this.writeCUInt(bytes.length).writeNativeBuffer(bytes);
|
|
83
65
|
}
|
|
84
|
-
readPwOctets(
|
|
85
|
-
let byteLength = this.readCUInt(
|
|
66
|
+
readPwOctets() {
|
|
67
|
+
let byteLength = this.readCUInt();
|
|
86
68
|
return this.readBuffer(byteLength, false, {
|
|
87
|
-
|
|
69
|
+
capacity: byteLength,
|
|
70
|
+
capacityStep: 0
|
|
88
71
|
});
|
|
89
72
|
}
|
|
90
|
-
writePwOctets(octets, unshift
|
|
73
|
+
writePwOctets(octets, unshift) {
|
|
91
74
|
if (unshift) {
|
|
92
|
-
return this.writeBuffer(octets, true).writeCUInt(octets.length, true
|
|
75
|
+
return this.writeBuffer(octets, true).writeCUInt(octets.length, true);
|
|
93
76
|
}
|
|
94
|
-
return this.writeCUInt(octets.length
|
|
77
|
+
return this.writeCUInt(octets.length).writeBuffer(octets);
|
|
95
78
|
}
|
|
96
79
|
}
|
|
97
80
|
exports.PwBuffer = PwBuffer;
|
package/dist/index.d.ts
CHANGED
|
@@ -1 +1,6 @@
|
|
|
1
|
-
export * from './
|
|
1
|
+
export * from './utils';
|
|
2
|
+
export { PwBuffer } from './PwBuffer';
|
|
3
|
+
export type { PwBufferOptions } from './PwBufferOptions';
|
|
4
|
+
export { MppcCompressor, MppcDecompressor } from './mppc';
|
|
5
|
+
export { MppcCompressorTransform } from './MppcCompressorTransform';
|
|
6
|
+
export { MppcDecompressorTransform } from './MppcDecompressorTransform';
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,27 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
function
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
5
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
|
|
17
|
+
exports.MppcDecompressorTransform = exports.MppcCompressorTransform = exports.MppcDecompressor = exports.MppcCompressor = exports.PwBuffer = void 0;
|
|
18
|
+
__exportStar(require("./utils"), exports);
|
|
19
|
+
var PwBuffer_1 = require("./PwBuffer");
|
|
20
|
+
Object.defineProperty(exports, "PwBuffer", { enumerable: true, get: function () { return PwBuffer_1.PwBuffer; } });
|
|
21
|
+
var mppc_1 = require("./mppc");
|
|
22
|
+
Object.defineProperty(exports, "MppcCompressor", { enumerable: true, get: function () { return mppc_1.MppcCompressor; } });
|
|
23
|
+
Object.defineProperty(exports, "MppcDecompressor", { enumerable: true, get: function () { return mppc_1.MppcDecompressor; } });
|
|
24
|
+
var MppcCompressorTransform_1 = require("./MppcCompressorTransform");
|
|
25
|
+
Object.defineProperty(exports, "MppcCompressorTransform", { enumerable: true, get: function () { return MppcCompressorTransform_1.MppcCompressorTransform; } });
|
|
26
|
+
var MppcDecompressorTransform_1 = require("./MppcDecompressorTransform");
|
|
27
|
+
Object.defineProperty(exports, "MppcDecompressorTransform", { enumerable: true, get: function () { return MppcDecompressorTransform_1.MppcDecompressorTransform; } });
|
package/dist/mppc.d.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
export declare class MppcDecompressor {
|
|
3
|
+
private history;
|
|
4
|
+
private histPtr;
|
|
5
|
+
private bitOffset;
|
|
6
|
+
private legacy;
|
|
7
|
+
update(chunk: Buffer): Buffer;
|
|
8
|
+
}
|
|
9
|
+
export declare class MppcCompressor {
|
|
10
|
+
private history;
|
|
11
|
+
private histPtr;
|
|
12
|
+
private readonly bw;
|
|
13
|
+
private readonly dict;
|
|
14
|
+
private key3;
|
|
15
|
+
private addPosToDict;
|
|
16
|
+
private pushHistoryByte;
|
|
17
|
+
private writeLiteral;
|
|
18
|
+
private writeOffset;
|
|
19
|
+
private writeLength;
|
|
20
|
+
private writeFlushMarker;
|
|
21
|
+
private resetSegment;
|
|
22
|
+
update(chunk: Buffer): Buffer;
|
|
23
|
+
}
|
package/dist/mppc.js
ADDED
|
@@ -0,0 +1,445 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MppcCompressor = exports.MppcDecompressor = void 0;
|
|
4
|
+
const buffer_1 = require("buffer");
|
|
5
|
+
const extended_buffer_1 = require("extended-buffer");
|
|
6
|
+
const MPPC_HIST_LEN = 8192;
|
|
7
|
+
function readU32BEWithPadding(buffer, offset) {
|
|
8
|
+
const b0 = offset < buffer.length ? buffer[offset] : 0;
|
|
9
|
+
const b1 = offset + 1 < buffer.length ? buffer[offset + 1] : 0;
|
|
10
|
+
const b2 = offset + 2 < buffer.length ? buffer[offset + 2] : 0;
|
|
11
|
+
const b3 = offset + 3 < buffer.length ? buffer[offset + 3] : 0;
|
|
12
|
+
return (((b0 << 24) | (b1 << 16) | (b2 << 8) | b3) >>> 0);
|
|
13
|
+
}
|
|
14
|
+
class BitWriter {
|
|
15
|
+
constructor() {
|
|
16
|
+
this.out = [];
|
|
17
|
+
this.bitBuf = 0;
|
|
18
|
+
this.bitCount = 0;
|
|
19
|
+
}
|
|
20
|
+
writeBits(value, bits) {
|
|
21
|
+
if (bits <= 0) {
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
if (bits > 31) {
|
|
25
|
+
throw new Error(`BitWriter.writeBits: bits=${bits} too large`);
|
|
26
|
+
}
|
|
27
|
+
const mask = bits === 31 ? 0x7FFFFFFF : (1 << bits) - 1;
|
|
28
|
+
const v = (value & mask) >>> 0;
|
|
29
|
+
this.bitBuf = (this.bitBuf * (Math.pow(2, bits))) + v;
|
|
30
|
+
this.bitCount += bits;
|
|
31
|
+
while (this.bitCount >= 8) {
|
|
32
|
+
const shift = this.bitCount - 8;
|
|
33
|
+
const byte = Math.floor(this.bitBuf / (Math.pow(2, shift))) & 0xFF;
|
|
34
|
+
this.out.push(byte);
|
|
35
|
+
this.bitCount -= 8;
|
|
36
|
+
if (this.bitCount === 0) {
|
|
37
|
+
this.bitBuf = 0;
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
this.bitBuf = this.bitBuf % (Math.pow(2, this.bitCount));
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
alignToByteWithZeroPadding() {
|
|
45
|
+
const mod = this.bitCount & 7;
|
|
46
|
+
if (mod) {
|
|
47
|
+
this.writeBits(0, 8 - mod);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
flushBytes() {
|
|
51
|
+
if (!this.out.length) {
|
|
52
|
+
return buffer_1.Buffer.alloc(0);
|
|
53
|
+
}
|
|
54
|
+
const buffer = buffer_1.Buffer.from(this.out);
|
|
55
|
+
this.out = [];
|
|
56
|
+
return buffer;
|
|
57
|
+
}
|
|
58
|
+
getPendingBitCount() {
|
|
59
|
+
return this.bitCount;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
class MppcDecompressor {
|
|
63
|
+
constructor() {
|
|
64
|
+
this.history = new Uint8Array(MPPC_HIST_LEN);
|
|
65
|
+
this.histPtr = 0;
|
|
66
|
+
this.bitOffset = 0;
|
|
67
|
+
this.legacy = buffer_1.Buffer.alloc(0);
|
|
68
|
+
}
|
|
69
|
+
update(chunk) {
|
|
70
|
+
if (chunk.length) {
|
|
71
|
+
this.legacy = buffer_1.Buffer.concat([this.legacy, chunk]);
|
|
72
|
+
}
|
|
73
|
+
let rptr = 0;
|
|
74
|
+
let bitShift = this.bitOffset;
|
|
75
|
+
let consumedBits = 7;
|
|
76
|
+
const totalBits = this.legacy.length * 8 - bitShift;
|
|
77
|
+
let savedBitShift = 0;
|
|
78
|
+
let savedRptr = 0;
|
|
79
|
+
const outParts = [];
|
|
80
|
+
let histHead = this.histPtr;
|
|
81
|
+
const passBits = (n) => {
|
|
82
|
+
bitShift += n;
|
|
83
|
+
consumedBits += n;
|
|
84
|
+
if (consumedBits < totalBits) {
|
|
85
|
+
return true;
|
|
86
|
+
}
|
|
87
|
+
bitShift = savedBitShift;
|
|
88
|
+
rptr = savedRptr;
|
|
89
|
+
return false;
|
|
90
|
+
};
|
|
91
|
+
const fetch = () => {
|
|
92
|
+
rptr += bitShift >>> 3;
|
|
93
|
+
bitShift &= 7;
|
|
94
|
+
return ((readU32BEWithPadding(this.legacy, rptr) << bitShift) >>> 0);
|
|
95
|
+
};
|
|
96
|
+
while (totalBits > consumedBits) {
|
|
97
|
+
savedBitShift = bitShift;
|
|
98
|
+
savedRptr = rptr;
|
|
99
|
+
let val = fetch();
|
|
100
|
+
if (val < 0x80000000) {
|
|
101
|
+
if (!passBits(8)) {
|
|
102
|
+
break;
|
|
103
|
+
}
|
|
104
|
+
this.history[this.histPtr++] = (val >>> 24) & 0xFF;
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
if (val < 0xC0000000) {
|
|
108
|
+
if (!passBits(9)) {
|
|
109
|
+
break;
|
|
110
|
+
}
|
|
111
|
+
this.history[this.histPtr++] = (((val >>> 23) | 0x80) & 0xFF) >>> 0;
|
|
112
|
+
continue;
|
|
113
|
+
}
|
|
114
|
+
let off = 0;
|
|
115
|
+
if (val >= 0xF0000000) {
|
|
116
|
+
if (!passBits(10)) {
|
|
117
|
+
break;
|
|
118
|
+
}
|
|
119
|
+
off = (val >>> 22) & 0x3F;
|
|
120
|
+
if (off === 0) {
|
|
121
|
+
const advance = 8 - (bitShift & 7);
|
|
122
|
+
if (advance < 8) {
|
|
123
|
+
if (!passBits(advance)) {
|
|
124
|
+
break;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
if (this.histPtr > histHead) {
|
|
128
|
+
outParts.push(buffer_1.Buffer.from(this.history.subarray(histHead, this.histPtr)));
|
|
129
|
+
}
|
|
130
|
+
if (this.histPtr === MPPC_HIST_LEN) {
|
|
131
|
+
this.histPtr = 0;
|
|
132
|
+
}
|
|
133
|
+
histHead = this.histPtr;
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
else if (val >= 0xE0000000) {
|
|
138
|
+
if (!passBits(12)) {
|
|
139
|
+
break;
|
|
140
|
+
}
|
|
141
|
+
off = ((val >>> 20) & 0xFF) + 64;
|
|
142
|
+
}
|
|
143
|
+
else if (val >= 0xC0000000) {
|
|
144
|
+
if (!passBits(16)) {
|
|
145
|
+
break;
|
|
146
|
+
}
|
|
147
|
+
off = ((val >>> 16) & 0x1FFF) + 320;
|
|
148
|
+
}
|
|
149
|
+
val = fetch();
|
|
150
|
+
let len = 0;
|
|
151
|
+
if (val < 0x80000000) {
|
|
152
|
+
if (!passBits(1)) {
|
|
153
|
+
break;
|
|
154
|
+
}
|
|
155
|
+
len = 3;
|
|
156
|
+
}
|
|
157
|
+
else if (val < 0xC0000000) {
|
|
158
|
+
if (!passBits(4)) {
|
|
159
|
+
break;
|
|
160
|
+
}
|
|
161
|
+
len = 4 | ((val >>> 28) & 3);
|
|
162
|
+
}
|
|
163
|
+
else if (val < 0xE0000000) {
|
|
164
|
+
if (!passBits(6)) {
|
|
165
|
+
break;
|
|
166
|
+
}
|
|
167
|
+
len = 8 | ((val >>> 26) & 7);
|
|
168
|
+
}
|
|
169
|
+
else if (val < 0xF0000000) {
|
|
170
|
+
if (!passBits(8)) {
|
|
171
|
+
break;
|
|
172
|
+
}
|
|
173
|
+
len = 16 | ((val >>> 24) & 15);
|
|
174
|
+
}
|
|
175
|
+
else if (val < 0xF8000000) {
|
|
176
|
+
if (!passBits(10)) {
|
|
177
|
+
break;
|
|
178
|
+
}
|
|
179
|
+
len = 32 | ((val >>> 22) & 0x1F);
|
|
180
|
+
}
|
|
181
|
+
else if (val < 0xFC000000) {
|
|
182
|
+
if (!passBits(12)) {
|
|
183
|
+
break;
|
|
184
|
+
}
|
|
185
|
+
len = 64 | ((val >>> 20) & 0x3F);
|
|
186
|
+
}
|
|
187
|
+
else if (val < 0xFE000000) {
|
|
188
|
+
if (!passBits(14)) {
|
|
189
|
+
break;
|
|
190
|
+
}
|
|
191
|
+
len = 128 | ((val >>> 18) & 0x7F);
|
|
192
|
+
}
|
|
193
|
+
else if (val < 0xFF000000) {
|
|
194
|
+
if (!passBits(16)) {
|
|
195
|
+
break;
|
|
196
|
+
}
|
|
197
|
+
len = 256 | ((val >>> 16) & 0xFF);
|
|
198
|
+
}
|
|
199
|
+
else if (val < 0xFF800000) {
|
|
200
|
+
if (!passBits(18)) {
|
|
201
|
+
break;
|
|
202
|
+
}
|
|
203
|
+
len = 0x200 | ((val >>> 14) & 0x1FF);
|
|
204
|
+
}
|
|
205
|
+
else if (val < 0xFFC00000) {
|
|
206
|
+
if (!passBits(20)) {
|
|
207
|
+
break;
|
|
208
|
+
}
|
|
209
|
+
len = 0x400 | ((val >>> 12) & 0x3FF);
|
|
210
|
+
}
|
|
211
|
+
else if (val < 0xFFE00000) {
|
|
212
|
+
if (!passBits(22)) {
|
|
213
|
+
break;
|
|
214
|
+
}
|
|
215
|
+
len = 0x800 | ((val >>> 10) & 0x7FF);
|
|
216
|
+
}
|
|
217
|
+
else if (val < 0xFFF00000) {
|
|
218
|
+
if (!passBits(24)) {
|
|
219
|
+
break;
|
|
220
|
+
}
|
|
221
|
+
len = 0x1000 | ((val >>> 8) & 0xFFF);
|
|
222
|
+
}
|
|
223
|
+
else {
|
|
224
|
+
bitShift = savedBitShift;
|
|
225
|
+
rptr = savedRptr;
|
|
226
|
+
break;
|
|
227
|
+
}
|
|
228
|
+
const src = this.histPtr - off;
|
|
229
|
+
const dstEnd = this.histPtr + len;
|
|
230
|
+
if (src < 0 || dstEnd > MPPC_HIST_LEN) {
|
|
231
|
+
break;
|
|
232
|
+
}
|
|
233
|
+
for (let i = 0; i < len; i++) {
|
|
234
|
+
this.history[this.histPtr + i] = this.history[src + i];
|
|
235
|
+
}
|
|
236
|
+
this.histPtr = dstEnd;
|
|
237
|
+
}
|
|
238
|
+
if (this.histPtr > histHead) {
|
|
239
|
+
outParts.push(buffer_1.Buffer.from(this.history.subarray(histHead, this.histPtr)));
|
|
240
|
+
}
|
|
241
|
+
this.legacy = (0, extended_buffer_1.nativeBufferSubarray)(this.legacy, rptr);
|
|
242
|
+
this.bitOffset = bitShift;
|
|
243
|
+
return outParts.length ? buffer_1.Buffer.concat(outParts) : buffer_1.Buffer.alloc(0);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
exports.MppcDecompressor = MppcDecompressor;
|
|
247
|
+
class MppcCompressor {
|
|
248
|
+
constructor() {
|
|
249
|
+
this.history = new Uint8Array(MPPC_HIST_LEN);
|
|
250
|
+
this.histPtr = 0;
|
|
251
|
+
this.bw = new BitWriter();
|
|
252
|
+
this.dict = new Map();
|
|
253
|
+
}
|
|
254
|
+
key3(b0, b1, b2) {
|
|
255
|
+
return ((b0 & 0xFF) << 16) | ((b1 & 0xFF) << 8) | (b2 & 0xFF);
|
|
256
|
+
}
|
|
257
|
+
addPosToDict(pos) {
|
|
258
|
+
if (pos < 0 || pos + 2 >= this.histPtr) {
|
|
259
|
+
return;
|
|
260
|
+
}
|
|
261
|
+
const key = this.key3(this.history[pos], this.history[pos + 1], this.history[pos + 2]);
|
|
262
|
+
let arr = this.dict.get(key);
|
|
263
|
+
if (!arr) {
|
|
264
|
+
arr = [];
|
|
265
|
+
this.dict.set(key, arr);
|
|
266
|
+
}
|
|
267
|
+
arr.push(pos);
|
|
268
|
+
if (arr.length > 64) {
|
|
269
|
+
arr.splice(0, arr.length - 64);
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
pushHistoryByte(b) {
|
|
273
|
+
this.history[this.histPtr] = b & 0xFF;
|
|
274
|
+
this.histPtr++;
|
|
275
|
+
this.addPosToDict(this.histPtr - 3);
|
|
276
|
+
}
|
|
277
|
+
writeLiteral(b) {
|
|
278
|
+
if ((b & 0x80) === 0) {
|
|
279
|
+
this.bw.writeBits(b & 0xFF, 8);
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
this.bw.writeBits(0x100 | (b & 0x7F), 9);
|
|
283
|
+
}
|
|
284
|
+
writeOffset(off) {
|
|
285
|
+
if (off < 0) {
|
|
286
|
+
throw new Error(`MPPC offset underflow: ${off}`);
|
|
287
|
+
}
|
|
288
|
+
if (off < 64) {
|
|
289
|
+
this.bw.writeBits((0b1111 << 6) | (off & 0x3F), 10);
|
|
290
|
+
return;
|
|
291
|
+
}
|
|
292
|
+
if (off < 320) {
|
|
293
|
+
this.bw.writeBits((0b1110 << 8) | ((off - 64) & 0xFF), 12);
|
|
294
|
+
return;
|
|
295
|
+
}
|
|
296
|
+
this.bw.writeBits((0b110 << 13) | ((off - 320) & 0x1FFF), 16);
|
|
297
|
+
}
|
|
298
|
+
writeLength(len) {
|
|
299
|
+
if (len < 3) {
|
|
300
|
+
throw new Error(`MPPC length too small: ${len}`);
|
|
301
|
+
}
|
|
302
|
+
if (len === 3) {
|
|
303
|
+
this.bw.writeBits(0, 1);
|
|
304
|
+
return;
|
|
305
|
+
}
|
|
306
|
+
if (len <= 7) {
|
|
307
|
+
this.bw.writeBits((0b10 << 2) | (len - 4), 4);
|
|
308
|
+
return;
|
|
309
|
+
}
|
|
310
|
+
if (len <= 15) {
|
|
311
|
+
this.bw.writeBits((0b110 << 3) | (len - 8), 6);
|
|
312
|
+
return;
|
|
313
|
+
}
|
|
314
|
+
if (len <= 31) {
|
|
315
|
+
this.bw.writeBits((0b1110 << 4) | (len - 16), 8);
|
|
316
|
+
return;
|
|
317
|
+
}
|
|
318
|
+
if (len <= 63) {
|
|
319
|
+
this.bw.writeBits((0b11110 << 5) | (len - 32), 10);
|
|
320
|
+
return;
|
|
321
|
+
}
|
|
322
|
+
if (len <= 127) {
|
|
323
|
+
this.bw.writeBits((0b111110 << 6) | (len - 64), 12);
|
|
324
|
+
return;
|
|
325
|
+
}
|
|
326
|
+
if (len <= 255) {
|
|
327
|
+
this.bw.writeBits((0b1111110 << 7) | (len - 128), 14);
|
|
328
|
+
return;
|
|
329
|
+
}
|
|
330
|
+
if (len <= 511) {
|
|
331
|
+
this.bw.writeBits((0b11111110 << 8) | (len - 256), 16);
|
|
332
|
+
return;
|
|
333
|
+
}
|
|
334
|
+
if (len <= 1023) {
|
|
335
|
+
this.bw.writeBits((0b111111110 << 9) | (len - 512), 18);
|
|
336
|
+
return;
|
|
337
|
+
}
|
|
338
|
+
if (len <= 2047) {
|
|
339
|
+
this.bw.writeBits((0b1111111110 << 10) | (len - 1024), 20);
|
|
340
|
+
return;
|
|
341
|
+
}
|
|
342
|
+
if (len <= 4095) {
|
|
343
|
+
this.bw.writeBits((0b11111111110 << 11) | (len - 2048), 22);
|
|
344
|
+
return;
|
|
345
|
+
}
|
|
346
|
+
if (len <= 8191) {
|
|
347
|
+
this.bw.writeBits((0b111111111110 << 12) | (len - 4096), 24);
|
|
348
|
+
return;
|
|
349
|
+
}
|
|
350
|
+
throw new Error(`MPPC length too large: ${len}`);
|
|
351
|
+
}
|
|
352
|
+
writeFlushMarker() {
|
|
353
|
+
this.writeOffset(0);
|
|
354
|
+
this.bw.alignToByteWithZeroPadding();
|
|
355
|
+
}
|
|
356
|
+
resetSegment() {
|
|
357
|
+
this.histPtr = 0;
|
|
358
|
+
this.dict.clear();
|
|
359
|
+
}
|
|
360
|
+
update(chunk) {
|
|
361
|
+
const flushBoundary = true;
|
|
362
|
+
const parts = [];
|
|
363
|
+
let i = 0;
|
|
364
|
+
while (i < chunk.length) {
|
|
365
|
+
if (this.histPtr === MPPC_HIST_LEN) {
|
|
366
|
+
this.writeFlushMarker();
|
|
367
|
+
parts.push(this.bw.flushBytes());
|
|
368
|
+
this.resetSegment();
|
|
369
|
+
}
|
|
370
|
+
const remainingHist = MPPC_HIST_LEN - this.histPtr;
|
|
371
|
+
const remainingIn = chunk.length - i;
|
|
372
|
+
const limit = remainingIn < remainingHist ? remainingIn : remainingHist;
|
|
373
|
+
if (limit <= 0) {
|
|
374
|
+
break;
|
|
375
|
+
}
|
|
376
|
+
let bestLen = 0;
|
|
377
|
+
let bestOff = 0;
|
|
378
|
+
if (limit >= 3 && this.histPtr >= 3) {
|
|
379
|
+
const key = this.key3(chunk[i], chunk[i + 1], chunk[i + 2]);
|
|
380
|
+
const candidates = this.dict.get(key);
|
|
381
|
+
if (candidates === null || candidates === void 0 ? void 0 : candidates.length) {
|
|
382
|
+
let checked = 0;
|
|
383
|
+
for (let c = candidates.length - 1; c >= 0; c--) {
|
|
384
|
+
const pos = candidates[c];
|
|
385
|
+
const off = this.histPtr - pos;
|
|
386
|
+
if (off <= 0 || off > this.histPtr) {
|
|
387
|
+
continue;
|
|
388
|
+
}
|
|
389
|
+
if (off > 0x1FFF + 320) {
|
|
390
|
+
continue;
|
|
391
|
+
}
|
|
392
|
+
const maxLen = Math.min(limit, this.histPtr - pos, 8191);
|
|
393
|
+
let l = 3;
|
|
394
|
+
while (l < maxLen && this.history[pos + l] === chunk[i + l]) {
|
|
395
|
+
l++;
|
|
396
|
+
}
|
|
397
|
+
if (l > bestLen) {
|
|
398
|
+
bestLen = l;
|
|
399
|
+
bestOff = off;
|
|
400
|
+
if (bestLen === maxLen) {
|
|
401
|
+
break;
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
if (++checked >= 32) {
|
|
405
|
+
break;
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
if (bestLen >= 3 && bestOff > 0) {
|
|
411
|
+
this.writeOffset(bestOff);
|
|
412
|
+
this.writeLength(bestLen);
|
|
413
|
+
for (let k = 0; k < bestLen; k++) {
|
|
414
|
+
this.pushHistoryByte(chunk[i + k]);
|
|
415
|
+
}
|
|
416
|
+
i += bestLen;
|
|
417
|
+
}
|
|
418
|
+
else {
|
|
419
|
+
const b = chunk[i];
|
|
420
|
+
this.writeLiteral(b);
|
|
421
|
+
this.pushHistoryByte(b);
|
|
422
|
+
i++;
|
|
423
|
+
}
|
|
424
|
+
const flushed = this.bw.flushBytes();
|
|
425
|
+
if (flushed.length) {
|
|
426
|
+
parts.push(flushed);
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
if (flushBoundary) {
|
|
430
|
+
this.writeFlushMarker();
|
|
431
|
+
const flushed = this.bw.flushBytes();
|
|
432
|
+
if (flushed.length) {
|
|
433
|
+
parts.push(flushed);
|
|
434
|
+
}
|
|
435
|
+
if (this.histPtr === MPPC_HIST_LEN) {
|
|
436
|
+
this.resetSegment();
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
if (!parts.length) {
|
|
440
|
+
return buffer_1.Buffer.alloc(0);
|
|
441
|
+
}
|
|
442
|
+
return parts.length === 1 ? parts[0] : buffer_1.Buffer.concat(parts);
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
exports.MppcCompressor = MppcCompressor;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { writeCUIntToPwBuffer } from './write-cuint-to-pw-buffer';
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.writeCUIntToPwBuffer = void 0;
|
|
4
|
+
var write_cuint_to_pw_buffer_1 = require("./write-cuint-to-pw-buffer");
|
|
5
|
+
Object.defineProperty(exports, "writeCUIntToPwBuffer", { enumerable: true, get: function () { return write_cuint_to_pw_buffer_1.writeCUIntToPwBuffer; } });
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.writeCUIntToPwBuffer = void 0;
|
|
4
|
+
const extended_buffer_1 = require("extended-buffer");
|
|
5
|
+
function writeCUIntToPwBuffer(buffer, value, unshift) {
|
|
6
|
+
(0, extended_buffer_1.assertInteger)(value);
|
|
7
|
+
if (value < 0 || value > 0xFFFFFFFF) {
|
|
8
|
+
throw new extended_buffer_1.ExtendedBufferRangeError('CUINT_VALUE_OUT_OF_RANGE');
|
|
9
|
+
}
|
|
10
|
+
if (value < 0x80) {
|
|
11
|
+
buffer.writeUIntBE(value & 0xFF, 1, unshift);
|
|
12
|
+
}
|
|
13
|
+
else if (value < 0x4000) {
|
|
14
|
+
buffer.writeUIntBE((value | 0x8000) & 0xFFFF, 2, unshift);
|
|
15
|
+
}
|
|
16
|
+
else if (value < 0x20000000) {
|
|
17
|
+
buffer.writeUIntBE((value | 0xC0000000) >>> 0, 4, unshift);
|
|
18
|
+
}
|
|
19
|
+
else {
|
|
20
|
+
const savedPointer = buffer.getPointer();
|
|
21
|
+
try {
|
|
22
|
+
if (unshift) {
|
|
23
|
+
buffer.allocStart(5).writeUIntBE(value >>> 0, 4, true).writeUIntBE(0xE0, 1, true);
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
buffer.allocEnd(5).writeUIntBE(0xE0, 1).writeUIntBE(value >>> 0, 4);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
catch (e) {
|
|
30
|
+
buffer.setPointer(savedPointer);
|
|
31
|
+
throw e;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
exports.writeCUIntToPwBuffer = writeCUIntToPwBuffer;
|
package/package.json
CHANGED
|
@@ -1,12 +1,35 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pw-buffer",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "PW Buffer, Perfect World",
|
|
5
|
-
"main": "dist/index.js",
|
|
6
|
-
"types": "dist/index.d.ts",
|
|
3
|
+
"version": "3.0.0",
|
|
4
|
+
"description": "PW Buffer, Perfect World, Beijing Perfect World",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"types": "./dist/index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"require": "./dist/index.js",
|
|
11
|
+
"default": "./dist/index.js"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
7
14
|
"scripts": {
|
|
8
|
-
"
|
|
9
|
-
"
|
|
15
|
+
"build": "npm run clean && node ./node_modules/.bin/tsc",
|
|
16
|
+
"clean": "node -e \"['./dist'].forEach(item => require('fs').rmSync(item, {recursive:true,force:true}));\"",
|
|
17
|
+
"prepack": "npm run build"
|
|
18
|
+
},
|
|
19
|
+
"engines": {
|
|
20
|
+
"node": ">=6.0.0"
|
|
21
|
+
},
|
|
22
|
+
"devEngines": {
|
|
23
|
+
"runtime": {
|
|
24
|
+
"name": "node",
|
|
25
|
+
"version": ">=18.0.0",
|
|
26
|
+
"onFail": "error"
|
|
27
|
+
},
|
|
28
|
+
"packageManager": {
|
|
29
|
+
"name": "npm",
|
|
30
|
+
"version": ">=8.6.0",
|
|
31
|
+
"onFail": "error"
|
|
32
|
+
}
|
|
10
33
|
},
|
|
11
34
|
"repository": {
|
|
12
35
|
"type": "git",
|
|
@@ -18,11 +41,16 @@
|
|
|
18
41
|
"url": "https://github.com/mvcbox/node-pw-buffer/issues"
|
|
19
42
|
},
|
|
20
43
|
"homepage": "https://github.com/mvcbox/node-pw-buffer#readme",
|
|
44
|
+
"files": [
|
|
45
|
+
"dist",
|
|
46
|
+
"LICENSE",
|
|
47
|
+
"README.md"
|
|
48
|
+
],
|
|
21
49
|
"dependencies": {
|
|
22
|
-
"extended-buffer": "^
|
|
50
|
+
"extended-buffer": "^7.0.1"
|
|
23
51
|
},
|
|
24
52
|
"devDependencies": {
|
|
25
|
-
"@types/node": "^
|
|
26
|
-
"typescript": "^
|
|
53
|
+
"@types/node": "^6.14.13",
|
|
54
|
+
"typescript": "^4.7.2"
|
|
27
55
|
}
|
|
28
56
|
}
|