@lexmata/micropdf 0.4.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/LICENSE +191 -0
- package/README.md +985 -0
- package/binding.gyp +73 -0
- package/dist/annot.d.ts +458 -0
- package/dist/annot.d.ts.map +1 -0
- package/dist/annot.js +697 -0
- package/dist/annot.js.map +1 -0
- package/dist/archive.d.ts +128 -0
- package/dist/archive.d.ts.map +1 -0
- package/dist/archive.js +268 -0
- package/dist/archive.js.map +1 -0
- package/dist/buffer.d.ts +572 -0
- package/dist/buffer.d.ts.map +1 -0
- package/dist/buffer.js +971 -0
- package/dist/buffer.js.map +1 -0
- package/dist/colorspace.d.ts +287 -0
- package/dist/colorspace.d.ts.map +1 -0
- package/dist/colorspace.js +542 -0
- package/dist/colorspace.js.map +1 -0
- package/dist/context.d.ts +184 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +320 -0
- package/dist/context.js.map +1 -0
- package/dist/cookie.d.ts +164 -0
- package/dist/cookie.d.ts.map +1 -0
- package/dist/cookie.js +306 -0
- package/dist/cookie.js.map +1 -0
- package/dist/device.d.ts +169 -0
- package/dist/device.d.ts.map +1 -0
- package/dist/device.js +350 -0
- package/dist/device.js.map +1 -0
- package/dist/display-list.d.ts +202 -0
- package/dist/display-list.d.ts.map +1 -0
- package/dist/display-list.js +410 -0
- package/dist/display-list.js.map +1 -0
- package/dist/document.d.ts +637 -0
- package/dist/document.d.ts.map +1 -0
- package/dist/document.js +902 -0
- package/dist/document.js.map +1 -0
- package/dist/easy.d.ts +423 -0
- package/dist/easy.d.ts.map +1 -0
- package/dist/easy.js +644 -0
- package/dist/easy.js.map +1 -0
- package/dist/enhanced.d.ts +226 -0
- package/dist/enhanced.d.ts.map +1 -0
- package/dist/enhanced.js +368 -0
- package/dist/enhanced.js.map +1 -0
- package/dist/filter.d.ts +51 -0
- package/dist/filter.d.ts.map +1 -0
- package/dist/filter.js +381 -0
- package/dist/filter.js.map +1 -0
- package/dist/font.d.ts +222 -0
- package/dist/font.d.ts.map +1 -0
- package/dist/font.js +381 -0
- package/dist/font.js.map +1 -0
- package/dist/form.d.ts +214 -0
- package/dist/form.d.ts.map +1 -0
- package/dist/form.js +497 -0
- package/dist/form.js.map +1 -0
- package/dist/geometry.d.ts +469 -0
- package/dist/geometry.d.ts.map +1 -0
- package/dist/geometry.js +780 -0
- package/dist/geometry.js.map +1 -0
- package/dist/image.d.ts +172 -0
- package/dist/image.d.ts.map +1 -0
- package/dist/image.js +348 -0
- package/dist/image.js.map +1 -0
- package/dist/index.d.ts +171 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +339 -0
- package/dist/index.js.map +1 -0
- package/dist/link.d.ts +168 -0
- package/dist/link.d.ts.map +1 -0
- package/dist/link.js +343 -0
- package/dist/link.js.map +1 -0
- package/dist/micropdf.d.ts +40 -0
- package/dist/micropdf.d.ts.map +1 -0
- package/dist/micropdf.js +45 -0
- package/dist/micropdf.js.map +1 -0
- package/dist/nanopdf.d.ts +40 -0
- package/dist/nanopdf.d.ts.map +1 -0
- package/dist/nanopdf.js +45 -0
- package/dist/nanopdf.js.map +1 -0
- package/dist/native.d.ts +242 -0
- package/dist/native.d.ts.map +1 -0
- package/dist/native.js +509 -0
- package/dist/native.js.map +1 -0
- package/dist/output.d.ts +166 -0
- package/dist/output.d.ts.map +1 -0
- package/dist/output.js +365 -0
- package/dist/output.js.map +1 -0
- package/dist/path.d.ts +420 -0
- package/dist/path.d.ts.map +1 -0
- package/dist/path.js +687 -0
- package/dist/path.js.map +1 -0
- package/dist/pdf/object.d.ts +489 -0
- package/dist/pdf/object.d.ts.map +1 -0
- package/dist/pdf/object.js +1045 -0
- package/dist/pdf/object.js.map +1 -0
- package/dist/pixmap.d.ts +315 -0
- package/dist/pixmap.d.ts.map +1 -0
- package/dist/pixmap.js +590 -0
- package/dist/pixmap.js.map +1 -0
- package/dist/profiler.d.ts +159 -0
- package/dist/profiler.d.ts.map +1 -0
- package/dist/profiler.js +380 -0
- package/dist/profiler.js.map +1 -0
- package/dist/render-options.d.ts +227 -0
- package/dist/render-options.d.ts.map +1 -0
- package/dist/render-options.js +130 -0
- package/dist/render-options.js.map +1 -0
- package/dist/resource-tracking.d.ts +332 -0
- package/dist/resource-tracking.d.ts.map +1 -0
- package/dist/resource-tracking.js +653 -0
- package/dist/resource-tracking.js.map +1 -0
- package/dist/simple.d.ts +276 -0
- package/dist/simple.d.ts.map +1 -0
- package/dist/simple.js +343 -0
- package/dist/simple.js.map +1 -0
- package/dist/stext.d.ts +290 -0
- package/dist/stext.d.ts.map +1 -0
- package/dist/stext.js +312 -0
- package/dist/stext.js.map +1 -0
- package/dist/stream.d.ts +174 -0
- package/dist/stream.d.ts.map +1 -0
- package/dist/stream.js +476 -0
- package/dist/stream.js.map +1 -0
- package/dist/text.d.ts +337 -0
- package/dist/text.d.ts.map +1 -0
- package/dist/text.js +454 -0
- package/dist/text.js.map +1 -0
- package/dist/typed-arrays.d.ts +127 -0
- package/dist/typed-arrays.d.ts.map +1 -0
- package/dist/typed-arrays.js +410 -0
- package/dist/typed-arrays.js.map +1 -0
- package/dist/types.d.ts +358 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +216 -0
- package/dist/types.js.map +1 -0
- package/native/annot.cc +557 -0
- package/native/buffer.cc +204 -0
- package/native/colorspace.cc +166 -0
- package/native/context.cc +84 -0
- package/native/cookie.cc +179 -0
- package/native/device.cc +179 -0
- package/native/display_list.cc +179 -0
- package/native/document.cc +268 -0
- package/native/enhanced.cc +70 -0
- package/native/font.cc +282 -0
- package/native/form.cc +523 -0
- package/native/geometry.cc +255 -0
- package/native/image.cc +216 -0
- package/native/include/micropdf/enhanced.h +38 -0
- package/native/include/micropdf/types.h +36 -0
- package/native/include/micropdf.h +106 -0
- package/native/include/mupdf-ffi.h +39 -0
- package/native/include/mupdf.h +11 -0
- package/native/include/mupdf_minimal.h +381 -0
- package/native/lib/linux-x64/libmicropdf.a +0 -0
- package/native/link.cc +234 -0
- package/native/micropdf.cc +71 -0
- package/native/output.cc +229 -0
- package/native/page.cc +572 -0
- package/native/path.cc +259 -0
- package/native/pixmap.cc +240 -0
- package/native/stext.cc +610 -0
- package/native/stream.cc +239 -0
- package/package.json +120 -0
- package/scripts/build-from-rust.js +97 -0
- package/scripts/install.js +184 -0
package/dist/buffer.js
ADDED
|
@@ -0,0 +1,971 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Buffer - Dynamic byte array wrapper for PDF data manipulation
|
|
3
|
+
*
|
|
4
|
+
* This module provides a flexible buffer implementation for working with binary PDF data.
|
|
5
|
+
* Buffers are used throughout the library for reading, writing, and manipulating
|
|
6
|
+
* PDF content, streams, and binary resources.
|
|
7
|
+
*
|
|
8
|
+
* This implementation mirrors the Rust `fitz::buffer::Buffer` for 100% API compatibility
|
|
9
|
+
* and wraps Node.js Buffer for efficient memory management.
|
|
10
|
+
*
|
|
11
|
+
* @module buffer
|
|
12
|
+
* @example
|
|
13
|
+
* ```typescript
|
|
14
|
+
* import { Buffer } from 'micropdf';
|
|
15
|
+
*
|
|
16
|
+
* // Create from string
|
|
17
|
+
* const buf = Buffer.fromString('Hello, PDF!');
|
|
18
|
+
*
|
|
19
|
+
* // Append data
|
|
20
|
+
* buf.append(Buffer.fromString(' More text.'));
|
|
21
|
+
*
|
|
22
|
+
* // Get as string
|
|
23
|
+
* console.log(buf.toString()); // "Hello, PDF! More text."
|
|
24
|
+
*
|
|
25
|
+
* // Get raw bytes
|
|
26
|
+
* const bytes = buf.toUint8Array();
|
|
27
|
+
*
|
|
28
|
+
* // Get size
|
|
29
|
+
* console.log(buf.length); // 24
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
import { MicroPDFError, isBufferLike } from './types.js';
|
|
33
|
+
import { createHash } from 'node:crypto';
|
|
34
|
+
// Shared TextDecoder for efficient UTF-8 decoding of large buffers
|
|
35
|
+
const textDecoder = new TextDecoder('utf-8');
|
|
36
|
+
// Threshold in bytes above which TextDecoder is more efficient than Node's toString()
|
|
37
|
+
const TEXT_DECODER_THRESHOLD = 1024;
|
|
38
|
+
// Re-export for convenience
|
|
39
|
+
export { isBufferLike };
|
|
40
|
+
/**
|
|
41
|
+
* A dynamic byte buffer for PDF data manipulation.
|
|
42
|
+
*
|
|
43
|
+
* Buffer provides efficient storage and manipulation of binary data. It's used
|
|
44
|
+
* throughout the library for PDF streams, content, images, and other binary resources.
|
|
45
|
+
*
|
|
46
|
+
* **Key Features:**
|
|
47
|
+
* - Dynamic resizing as data is appended
|
|
48
|
+
* - Zero-copy conversion to/from Node.js Buffer
|
|
49
|
+
* - String encoding/decoding support
|
|
50
|
+
* - Slice and copy operations
|
|
51
|
+
* - Compatible with standard Node.js Buffer operations
|
|
52
|
+
*
|
|
53
|
+
* Mirrors the Rust `Buffer` implementation with `bytes` crate semantics.
|
|
54
|
+
*
|
|
55
|
+
* @class Buffer
|
|
56
|
+
* @example
|
|
57
|
+
* ```typescript
|
|
58
|
+
* // Create empty buffer
|
|
59
|
+
* const buf1 = Buffer.create();
|
|
60
|
+
*
|
|
61
|
+
* // Create from string
|
|
62
|
+
* const buf2 = Buffer.fromString('Hello');
|
|
63
|
+
*
|
|
64
|
+
* // Create from bytes
|
|
65
|
+
* const bytes = new Uint8Array([72, 101, 108, 108, 111]);
|
|
66
|
+
* const buf3 = Buffer.fromUint8Array(bytes);
|
|
67
|
+
*
|
|
68
|
+
* // Append data
|
|
69
|
+
* buf1.append(buf2);
|
|
70
|
+
* buf1.append(Buffer.fromString(' World!'));
|
|
71
|
+
*
|
|
72
|
+
* // Extract data
|
|
73
|
+
* console.log(buf1.toString()); // "Hello World!"
|
|
74
|
+
* console.log(buf1.length); // 12
|
|
75
|
+
*
|
|
76
|
+
* // Slice
|
|
77
|
+
* const hello = buf1.slice(0, 5);
|
|
78
|
+
* console.log(hello.toString()); // "Hello"
|
|
79
|
+
*
|
|
80
|
+
* // Clear
|
|
81
|
+
* buf1.clear();
|
|
82
|
+
* console.log(buf1.length); // 0
|
|
83
|
+
* ```
|
|
84
|
+
*/
|
|
85
|
+
export class Buffer {
|
|
86
|
+
/**
|
|
87
|
+
* The underlying Node.js Buffer containing the data.
|
|
88
|
+
* @private
|
|
89
|
+
* @type {globalThis.Buffer}
|
|
90
|
+
*/
|
|
91
|
+
_data;
|
|
92
|
+
/**
|
|
93
|
+
* Creates a new Buffer instance.
|
|
94
|
+
*
|
|
95
|
+
* **Note**: Use static factory methods instead of calling this constructor directly.
|
|
96
|
+
*
|
|
97
|
+
* @private
|
|
98
|
+
* @param {globalThis.Buffer} data - The underlying Node.js Buffer
|
|
99
|
+
*/
|
|
100
|
+
constructor(data) {
|
|
101
|
+
this._data = data;
|
|
102
|
+
}
|
|
103
|
+
// ============================================================================
|
|
104
|
+
// Static Constructors
|
|
105
|
+
// ============================================================================
|
|
106
|
+
/**
|
|
107
|
+
* Creates a new empty buffer with optional initial capacity.
|
|
108
|
+
*
|
|
109
|
+
* The capacity parameter is a hint for initial memory allocation. The buffer
|
|
110
|
+
* will automatically grow as needed when data is appended.
|
|
111
|
+
*
|
|
112
|
+
* @static
|
|
113
|
+
* @param {number} [capacity=0] - Initial capacity in bytes (optional)
|
|
114
|
+
* @returns {Buffer} A new empty buffer
|
|
115
|
+
* @example
|
|
116
|
+
* ```typescript
|
|
117
|
+
* // Create empty buffer
|
|
118
|
+
* const buf1 = Buffer.create();
|
|
119
|
+
*
|
|
120
|
+
* // Create with initial capacity
|
|
121
|
+
* const buf2 = Buffer.create(1024); // Reserve 1KB
|
|
122
|
+
* ```
|
|
123
|
+
*/
|
|
124
|
+
static create(capacity = 0) {
|
|
125
|
+
return new Buffer(globalThis.Buffer.alloc(capacity));
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Creates a buffer from a Node.js Buffer (zero-copy).
|
|
129
|
+
*
|
|
130
|
+
* This operation wraps the existing Buffer without copying data, making it
|
|
131
|
+
* very efficient. Modifications to the original Buffer will be visible in
|
|
132
|
+
* the MicroPDF Buffer and vice versa.
|
|
133
|
+
*
|
|
134
|
+
* @static
|
|
135
|
+
* @param {globalThis.Buffer} data - The Node.js Buffer to wrap
|
|
136
|
+
* @returns {Buffer} A new Buffer wrapping the provided data
|
|
137
|
+
* @example
|
|
138
|
+
* ```typescript
|
|
139
|
+
* const nodeBuffer = Buffer.from('Hello');
|
|
140
|
+
* const pdfBuffer = Buffer.fromBuffer(nodeBuffer);
|
|
141
|
+
* console.log(pdfBuffer.toString()); // "Hello"
|
|
142
|
+
* ```
|
|
143
|
+
*/
|
|
144
|
+
static fromBuffer(data) {
|
|
145
|
+
return new Buffer(data);
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Creates a buffer from a Uint8Array.
|
|
149
|
+
*
|
|
150
|
+
* The data is copied into a new Node.js Buffer.
|
|
151
|
+
*
|
|
152
|
+
* @static
|
|
153
|
+
* @param {Uint8Array} data - The byte array to copy
|
|
154
|
+
* @returns {Buffer} A new Buffer containing the data
|
|
155
|
+
* @example
|
|
156
|
+
* ```typescript
|
|
157
|
+
* const bytes = new Uint8Array([72, 101, 108, 108, 111]);
|
|
158
|
+
* const buf = Buffer.fromUint8Array(bytes);
|
|
159
|
+
* console.log(buf.toString()); // "Hello"
|
|
160
|
+
* ```
|
|
161
|
+
*/
|
|
162
|
+
static fromUint8Array(data) {
|
|
163
|
+
return new Buffer(globalThis.Buffer.from(data));
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Creates a buffer from an ArrayBuffer.
|
|
167
|
+
*
|
|
168
|
+
* Useful for working with binary data from various Web APIs and file operations.
|
|
169
|
+
*
|
|
170
|
+
* @static
|
|
171
|
+
* @param {ArrayBuffer} data - The ArrayBuffer to convert
|
|
172
|
+
* @returns {Buffer} A new Buffer containing the data
|
|
173
|
+
* @example
|
|
174
|
+
* ```typescript
|
|
175
|
+
* const arrayBuffer = new ArrayBuffer(5);
|
|
176
|
+
* const view = new Uint8Array(arrayBuffer);
|
|
177
|
+
* view.set([72, 101, 108, 108, 111]);
|
|
178
|
+
* const buf = Buffer.fromArrayBuffer(arrayBuffer);
|
|
179
|
+
* console.log(buf.toString()); // "Hello"
|
|
180
|
+
* ```
|
|
181
|
+
*/
|
|
182
|
+
static fromArrayBuffer(data) {
|
|
183
|
+
return new Buffer(globalThis.Buffer.from(data));
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Creates a buffer from a string with specified encoding.
|
|
187
|
+
*
|
|
188
|
+
* Supports all standard Node.js buffer encodings including UTF-8, ASCII,
|
|
189
|
+
* Base64, Hex, and more.
|
|
190
|
+
*
|
|
191
|
+
* @static
|
|
192
|
+
* @param {string} str - The string to encode
|
|
193
|
+
* @param {BufferEncoding} [encoding='utf-8'] - The character encoding to use
|
|
194
|
+
* @returns {Buffer} A new Buffer containing the encoded string
|
|
195
|
+
* @example
|
|
196
|
+
* ```typescript
|
|
197
|
+
* // UTF-8 (default)
|
|
198
|
+
* const buf1 = Buffer.fromString('Hello');
|
|
199
|
+
*
|
|
200
|
+
* // ASCII
|
|
201
|
+
* const buf2 = Buffer.fromString('Hello', 'ascii');
|
|
202
|
+
*
|
|
203
|
+
* // Base64
|
|
204
|
+
* const buf3 = Buffer.fromString('SGVsbG8=', 'base64');
|
|
205
|
+
* console.log(buf3.toString()); // "Hello"
|
|
206
|
+
*
|
|
207
|
+
* // Hex
|
|
208
|
+
* const buf4 = Buffer.fromString('48656c6c6f', 'hex');
|
|
209
|
+
* console.log(buf4.toString()); // "Hello"
|
|
210
|
+
* ```
|
|
211
|
+
*/
|
|
212
|
+
static fromString(str, encoding = 'utf-8') {
|
|
213
|
+
return new Buffer(globalThis.Buffer.from(str, encoding));
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Create a buffer from base64-encoded data
|
|
217
|
+
*/
|
|
218
|
+
static fromBase64(data) {
|
|
219
|
+
return new Buffer(globalThis.Buffer.from(data, 'base64'));
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Create a buffer from hex-encoded data
|
|
223
|
+
*/
|
|
224
|
+
static fromHex(data) {
|
|
225
|
+
return new Buffer(globalThis.Buffer.from(data, 'hex'));
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* Create a buffer from various input types
|
|
229
|
+
*/
|
|
230
|
+
static from(data) {
|
|
231
|
+
if (data instanceof Buffer) {
|
|
232
|
+
return Buffer.fromBuffer(data._data);
|
|
233
|
+
}
|
|
234
|
+
if (globalThis.Buffer.isBuffer(data)) {
|
|
235
|
+
return Buffer.fromBuffer(data);
|
|
236
|
+
}
|
|
237
|
+
if (data instanceof Uint8Array) {
|
|
238
|
+
return Buffer.fromUint8Array(data);
|
|
239
|
+
}
|
|
240
|
+
if (data instanceof ArrayBuffer) {
|
|
241
|
+
return Buffer.fromArrayBuffer(data);
|
|
242
|
+
}
|
|
243
|
+
if (typeof data === 'string') {
|
|
244
|
+
return Buffer.fromString(data);
|
|
245
|
+
}
|
|
246
|
+
if (Array.isArray(data)) {
|
|
247
|
+
return new Buffer(globalThis.Buffer.from(data));
|
|
248
|
+
}
|
|
249
|
+
throw MicroPDFError.argument('Expected Buffer, Uint8Array, ArrayBuffer, string, or number[]');
|
|
250
|
+
}
|
|
251
|
+
// ============================================================================
|
|
252
|
+
// Properties
|
|
253
|
+
// ============================================================================
|
|
254
|
+
/**
|
|
255
|
+
* Get the length of the buffer in bytes
|
|
256
|
+
*/
|
|
257
|
+
get length() {
|
|
258
|
+
return this._data.length;
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* Check if the buffer is empty
|
|
262
|
+
*/
|
|
263
|
+
get isEmpty() {
|
|
264
|
+
return this._data.length === 0;
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* Get the buffer capacity
|
|
268
|
+
*/
|
|
269
|
+
get capacity() {
|
|
270
|
+
return this._data.length;
|
|
271
|
+
}
|
|
272
|
+
// ============================================================================
|
|
273
|
+
// Conversion Methods
|
|
274
|
+
// ============================================================================
|
|
275
|
+
/**
|
|
276
|
+
* Get the buffer data as a Node.js Buffer
|
|
277
|
+
*/
|
|
278
|
+
toNodeBuffer() {
|
|
279
|
+
return this._data;
|
|
280
|
+
}
|
|
281
|
+
/**
|
|
282
|
+
* Get the buffer data as a Uint8Array (copy)
|
|
283
|
+
*
|
|
284
|
+
* Creates a new Uint8Array with a copy of the buffer data.
|
|
285
|
+
* Use `toUint8ArrayView()` for a zero-copy view if you don't need to modify it.
|
|
286
|
+
*/
|
|
287
|
+
toUint8Array() {
|
|
288
|
+
return new Uint8Array(this._data);
|
|
289
|
+
}
|
|
290
|
+
/**
|
|
291
|
+
* Get a zero-copy Uint8Array view of the buffer data
|
|
292
|
+
*
|
|
293
|
+
* WARNING: This returns a view, not a copy. Modifying the view will
|
|
294
|
+
* modify the original buffer. The view becomes invalid if the buffer
|
|
295
|
+
* is modified (append, resize, etc.) or freed.
|
|
296
|
+
*
|
|
297
|
+
* Use this for read-only operations where performance matters.
|
|
298
|
+
*/
|
|
299
|
+
toUint8ArrayView() {
|
|
300
|
+
// Node.js Buffer is a subclass of Uint8Array, so we can return directly
|
|
301
|
+
return this._data;
|
|
302
|
+
}
|
|
303
|
+
/**
|
|
304
|
+
* Get the buffer data as an ArrayBuffer
|
|
305
|
+
*/
|
|
306
|
+
toArrayBuffer() {
|
|
307
|
+
const buf = this._data.buffer.slice(this._data.byteOffset, this._data.byteOffset + this._data.byteLength);
|
|
308
|
+
// Handle SharedArrayBuffer case
|
|
309
|
+
if (buf instanceof SharedArrayBuffer) {
|
|
310
|
+
const ab = new ArrayBuffer(buf.byteLength);
|
|
311
|
+
new Uint8Array(ab).set(new Uint8Array(buf));
|
|
312
|
+
return ab;
|
|
313
|
+
}
|
|
314
|
+
return buf;
|
|
315
|
+
}
|
|
316
|
+
/**
|
|
317
|
+
* Get the buffer data as a string
|
|
318
|
+
*
|
|
319
|
+
* For UTF-8 encoding with buffers larger than 1KB, uses TextDecoder
|
|
320
|
+
* which is more efficient than Node's toString() for large strings.
|
|
321
|
+
*/
|
|
322
|
+
toString(encoding = 'utf-8') {
|
|
323
|
+
// Use TextDecoder for large UTF-8 buffers (more efficient)
|
|
324
|
+
if ((encoding === 'utf-8' || encoding === 'utf8') &&
|
|
325
|
+
this._data.length > TEXT_DECODER_THRESHOLD) {
|
|
326
|
+
return textDecoder.decode(this._data);
|
|
327
|
+
}
|
|
328
|
+
return this._data.toString(encoding);
|
|
329
|
+
}
|
|
330
|
+
/**
|
|
331
|
+
* Get the buffer data as base64-encoded string
|
|
332
|
+
*/
|
|
333
|
+
toBase64() {
|
|
334
|
+
return this._data.toString('base64');
|
|
335
|
+
}
|
|
336
|
+
/**
|
|
337
|
+
* Get the buffer data as hex-encoded string
|
|
338
|
+
*/
|
|
339
|
+
toHex() {
|
|
340
|
+
return this._data.toString('hex');
|
|
341
|
+
}
|
|
342
|
+
/**
|
|
343
|
+
* Get the buffer data as a number array
|
|
344
|
+
*/
|
|
345
|
+
toArray() {
|
|
346
|
+
return [...this._data];
|
|
347
|
+
}
|
|
348
|
+
// ============================================================================
|
|
349
|
+
// Modification Methods
|
|
350
|
+
// ============================================================================
|
|
351
|
+
/**
|
|
352
|
+
* Resize the buffer to the specified size
|
|
353
|
+
*/
|
|
354
|
+
resize(newLength) {
|
|
355
|
+
if (newLength === this._data.length) {
|
|
356
|
+
return this;
|
|
357
|
+
}
|
|
358
|
+
const newData = globalThis.Buffer.alloc(newLength);
|
|
359
|
+
this._data.copy(newData, 0, 0, Math.min(this._data.length, newLength));
|
|
360
|
+
this._data = newData;
|
|
361
|
+
return this;
|
|
362
|
+
}
|
|
363
|
+
/**
|
|
364
|
+
* Clear all data from the buffer
|
|
365
|
+
*/
|
|
366
|
+
clear() {
|
|
367
|
+
this._data = globalThis.Buffer.alloc(0);
|
|
368
|
+
return this;
|
|
369
|
+
}
|
|
370
|
+
/**
|
|
371
|
+
* Append data to the buffer
|
|
372
|
+
*/
|
|
373
|
+
append(data) {
|
|
374
|
+
const other = Buffer.from(data);
|
|
375
|
+
this._data = globalThis.Buffer.concat([this._data, other._data]);
|
|
376
|
+
return this;
|
|
377
|
+
}
|
|
378
|
+
/**
|
|
379
|
+
* Append a single byte to the buffer
|
|
380
|
+
*/
|
|
381
|
+
appendByte(byte) {
|
|
382
|
+
const newData = globalThis.Buffer.alloc(this._data.length + 1);
|
|
383
|
+
this._data.copy(newData);
|
|
384
|
+
newData[this._data.length] = byte & 0xff;
|
|
385
|
+
this._data = newData;
|
|
386
|
+
return this;
|
|
387
|
+
}
|
|
388
|
+
/**
|
|
389
|
+
* Append a string to the buffer (UTF-8 encoded)
|
|
390
|
+
*/
|
|
391
|
+
appendString(str, encoding = 'utf-8') {
|
|
392
|
+
return this.append(globalThis.Buffer.from(str, encoding));
|
|
393
|
+
}
|
|
394
|
+
/**
|
|
395
|
+
* Append a 16-bit integer in little-endian format
|
|
396
|
+
*/
|
|
397
|
+
appendInt16LE(value) {
|
|
398
|
+
const buf = globalThis.Buffer.alloc(2);
|
|
399
|
+
buf.writeInt16LE(value, 0);
|
|
400
|
+
return this.append(buf);
|
|
401
|
+
}
|
|
402
|
+
/**
|
|
403
|
+
* Append a 32-bit integer in little-endian format
|
|
404
|
+
*/
|
|
405
|
+
appendInt32LE(value) {
|
|
406
|
+
const buf = globalThis.Buffer.alloc(4);
|
|
407
|
+
buf.writeInt32LE(value, 0);
|
|
408
|
+
return this.append(buf);
|
|
409
|
+
}
|
|
410
|
+
/**
|
|
411
|
+
* Append a 16-bit integer in big-endian format
|
|
412
|
+
*/
|
|
413
|
+
appendInt16BE(value) {
|
|
414
|
+
const buf = globalThis.Buffer.alloc(2);
|
|
415
|
+
buf.writeInt16BE(value, 0);
|
|
416
|
+
return this.append(buf);
|
|
417
|
+
}
|
|
418
|
+
/**
|
|
419
|
+
* Append a 32-bit integer in big-endian format
|
|
420
|
+
*/
|
|
421
|
+
appendInt32BE(value) {
|
|
422
|
+
const buf = globalThis.Buffer.alloc(4);
|
|
423
|
+
buf.writeInt32BE(value, 0);
|
|
424
|
+
return this.append(buf);
|
|
425
|
+
}
|
|
426
|
+
/**
|
|
427
|
+
* Append a 16-bit unsigned integer in little-endian format
|
|
428
|
+
*/
|
|
429
|
+
appendUInt16LE(value) {
|
|
430
|
+
const buf = globalThis.Buffer.alloc(2);
|
|
431
|
+
buf.writeUInt16LE(value, 0);
|
|
432
|
+
return this.append(buf);
|
|
433
|
+
}
|
|
434
|
+
/**
|
|
435
|
+
* Append a 32-bit unsigned integer in little-endian format
|
|
436
|
+
*/
|
|
437
|
+
appendUInt32LE(value) {
|
|
438
|
+
const buf = globalThis.Buffer.alloc(4);
|
|
439
|
+
buf.writeUInt32LE(value, 0);
|
|
440
|
+
return this.append(buf);
|
|
441
|
+
}
|
|
442
|
+
/**
|
|
443
|
+
* Append a 16-bit unsigned integer in big-endian format
|
|
444
|
+
*/
|
|
445
|
+
appendUInt16BE(value) {
|
|
446
|
+
const buf = globalThis.Buffer.alloc(2);
|
|
447
|
+
buf.writeUInt16BE(value, 0);
|
|
448
|
+
return this.append(buf);
|
|
449
|
+
}
|
|
450
|
+
/**
|
|
451
|
+
* Append a 32-bit unsigned integer in big-endian format
|
|
452
|
+
*/
|
|
453
|
+
appendUInt32BE(value) {
|
|
454
|
+
const buf = globalThis.Buffer.alloc(4);
|
|
455
|
+
buf.writeUInt32BE(value, 0);
|
|
456
|
+
return this.append(buf);
|
|
457
|
+
}
|
|
458
|
+
/**
|
|
459
|
+
* Append a float in little-endian format
|
|
460
|
+
*/
|
|
461
|
+
appendFloatLE(value) {
|
|
462
|
+
const buf = globalThis.Buffer.alloc(4);
|
|
463
|
+
buf.writeFloatLE(value, 0);
|
|
464
|
+
return this.append(buf);
|
|
465
|
+
}
|
|
466
|
+
/**
|
|
467
|
+
* Append a float in big-endian format
|
|
468
|
+
*/
|
|
469
|
+
appendFloatBE(value) {
|
|
470
|
+
const buf = globalThis.Buffer.alloc(4);
|
|
471
|
+
buf.writeFloatBE(value, 0);
|
|
472
|
+
return this.append(buf);
|
|
473
|
+
}
|
|
474
|
+
/**
|
|
475
|
+
* Append a double in little-endian format
|
|
476
|
+
*/
|
|
477
|
+
appendDoubleLE(value) {
|
|
478
|
+
const buf = globalThis.Buffer.alloc(8);
|
|
479
|
+
buf.writeDoubleLE(value, 0);
|
|
480
|
+
return this.append(buf);
|
|
481
|
+
}
|
|
482
|
+
/**
|
|
483
|
+
* Append a double in big-endian format
|
|
484
|
+
*/
|
|
485
|
+
appendDoubleBE(value) {
|
|
486
|
+
const buf = globalThis.Buffer.alloc(8);
|
|
487
|
+
buf.writeDoubleBE(value, 0);
|
|
488
|
+
return this.append(buf);
|
|
489
|
+
}
|
|
490
|
+
// ============================================================================
|
|
491
|
+
// Access Methods
|
|
492
|
+
// ============================================================================
|
|
493
|
+
/**
|
|
494
|
+
* Get a slice of the buffer
|
|
495
|
+
*/
|
|
496
|
+
slice(start, end) {
|
|
497
|
+
return new Buffer(globalThis.Buffer.from(this._data.subarray(start, end)));
|
|
498
|
+
}
|
|
499
|
+
/**
|
|
500
|
+
* Split the buffer at the given index
|
|
501
|
+
*/
|
|
502
|
+
splitAt(mid) {
|
|
503
|
+
const first = this.slice(0, mid);
|
|
504
|
+
const second = this.slice(mid);
|
|
505
|
+
return [first, second];
|
|
506
|
+
}
|
|
507
|
+
/**
|
|
508
|
+
* Get a byte at the specified index
|
|
509
|
+
*/
|
|
510
|
+
at(index) {
|
|
511
|
+
if (index < 0) {
|
|
512
|
+
index = this._data.length + index;
|
|
513
|
+
}
|
|
514
|
+
if (index < 0 || index >= this._data.length) {
|
|
515
|
+
return undefined;
|
|
516
|
+
}
|
|
517
|
+
return this._data[index];
|
|
518
|
+
}
|
|
519
|
+
/**
|
|
520
|
+
* Set a byte at the specified index
|
|
521
|
+
*/
|
|
522
|
+
set(index, value) {
|
|
523
|
+
if (index < 0) {
|
|
524
|
+
index = this._data.length + index;
|
|
525
|
+
}
|
|
526
|
+
if (index >= 0 && index < this._data.length) {
|
|
527
|
+
this._data[index] = value & 0xff;
|
|
528
|
+
}
|
|
529
|
+
return this;
|
|
530
|
+
}
|
|
531
|
+
/**
|
|
532
|
+
* Read a 16-bit unsigned integer at offset (big-endian)
|
|
533
|
+
*/
|
|
534
|
+
readUInt16BE(offset) {
|
|
535
|
+
return this._data.readUInt16BE(offset);
|
|
536
|
+
}
|
|
537
|
+
/**
|
|
538
|
+
* Read a 32-bit unsigned integer at offset (big-endian)
|
|
539
|
+
*/
|
|
540
|
+
readUInt32BE(offset) {
|
|
541
|
+
return this._data.readUInt32BE(offset);
|
|
542
|
+
}
|
|
543
|
+
/**
|
|
544
|
+
* Read a 16-bit unsigned integer at offset (little-endian)
|
|
545
|
+
*/
|
|
546
|
+
readUInt16LE(offset) {
|
|
547
|
+
return this._data.readUInt16LE(offset);
|
|
548
|
+
}
|
|
549
|
+
/**
|
|
550
|
+
* Read a 32-bit unsigned integer at offset (little-endian)
|
|
551
|
+
*/
|
|
552
|
+
readUInt32LE(offset) {
|
|
553
|
+
return this._data.readUInt32LE(offset);
|
|
554
|
+
}
|
|
555
|
+
/**
|
|
556
|
+
* Read a 16-bit signed integer at offset (big-endian)
|
|
557
|
+
*/
|
|
558
|
+
readInt16BE(offset) {
|
|
559
|
+
return this._data.readInt16BE(offset);
|
|
560
|
+
}
|
|
561
|
+
/**
|
|
562
|
+
* Read a 32-bit signed integer at offset (big-endian)
|
|
563
|
+
*/
|
|
564
|
+
readInt32BE(offset) {
|
|
565
|
+
return this._data.readInt32BE(offset);
|
|
566
|
+
}
|
|
567
|
+
/**
|
|
568
|
+
* Read a 16-bit signed integer at offset (little-endian)
|
|
569
|
+
*/
|
|
570
|
+
readInt16LE(offset) {
|
|
571
|
+
return this._data.readInt16LE(offset);
|
|
572
|
+
}
|
|
573
|
+
/**
|
|
574
|
+
* Read a 32-bit signed integer at offset (little-endian)
|
|
575
|
+
*/
|
|
576
|
+
readInt32LE(offset) {
|
|
577
|
+
return this._data.readInt32LE(offset);
|
|
578
|
+
}
|
|
579
|
+
/**
|
|
580
|
+
* Read a float at offset (big-endian)
|
|
581
|
+
*/
|
|
582
|
+
readFloatBE(offset) {
|
|
583
|
+
return this._data.readFloatBE(offset);
|
|
584
|
+
}
|
|
585
|
+
/**
|
|
586
|
+
* Read a float at offset (little-endian)
|
|
587
|
+
*/
|
|
588
|
+
readFloatLE(offset) {
|
|
589
|
+
return this._data.readFloatLE(offset);
|
|
590
|
+
}
|
|
591
|
+
/**
|
|
592
|
+
* Read a double at offset (big-endian)
|
|
593
|
+
*/
|
|
594
|
+
readDoubleBE(offset) {
|
|
595
|
+
return this._data.readDoubleBE(offset);
|
|
596
|
+
}
|
|
597
|
+
/**
|
|
598
|
+
* Read a double at offset (little-endian)
|
|
599
|
+
*/
|
|
600
|
+
readDoubleLE(offset) {
|
|
601
|
+
return this._data.readDoubleLE(offset);
|
|
602
|
+
}
|
|
603
|
+
// ============================================================================
|
|
604
|
+
// Hashing Methods
|
|
605
|
+
// ============================================================================
|
|
606
|
+
/**
|
|
607
|
+
* Compute MD5 digest of buffer contents
|
|
608
|
+
*/
|
|
609
|
+
md5Digest() {
|
|
610
|
+
const hash = createHash('md5');
|
|
611
|
+
hash.update(this._data);
|
|
612
|
+
return new Uint8Array(hash.digest());
|
|
613
|
+
}
|
|
614
|
+
/**
|
|
615
|
+
* Compute SHA-256 digest of buffer contents
|
|
616
|
+
*/
|
|
617
|
+
sha256Digest() {
|
|
618
|
+
const hash = createHash('sha256');
|
|
619
|
+
hash.update(this._data);
|
|
620
|
+
return new Uint8Array(hash.digest());
|
|
621
|
+
}
|
|
622
|
+
// ============================================================================
|
|
623
|
+
// Comparison Methods
|
|
624
|
+
// ============================================================================
|
|
625
|
+
/**
|
|
626
|
+
* Check equality with another buffer
|
|
627
|
+
*/
|
|
628
|
+
equals(other) {
|
|
629
|
+
const otherBuf = other instanceof Buffer ? other : Buffer.from(other);
|
|
630
|
+
return this._data.equals(otherBuf._data);
|
|
631
|
+
}
|
|
632
|
+
/**
|
|
633
|
+
* Compare with another buffer
|
|
634
|
+
* Returns -1, 0, or 1
|
|
635
|
+
*/
|
|
636
|
+
compare(other) {
|
|
637
|
+
const otherBuf = other instanceof Buffer ? other : Buffer.from(other);
|
|
638
|
+
return this._data.compare(otherBuf._data);
|
|
639
|
+
}
|
|
640
|
+
/**
|
|
641
|
+
* Find index of a byte or pattern
|
|
642
|
+
*/
|
|
643
|
+
indexOf(value, start = 0) {
|
|
644
|
+
if (typeof value === 'number') {
|
|
645
|
+
return this._data.indexOf(value, start);
|
|
646
|
+
}
|
|
647
|
+
const pattern = Buffer.from(value);
|
|
648
|
+
return this._data.indexOf(pattern._data, start);
|
|
649
|
+
}
|
|
650
|
+
/**
|
|
651
|
+
* Check if buffer includes a byte or pattern
|
|
652
|
+
*/
|
|
653
|
+
includes(value, start = 0) {
|
|
654
|
+
return this.includes(value, start);
|
|
655
|
+
}
|
|
656
|
+
// ============================================================================
|
|
657
|
+
// Iterator Support
|
|
658
|
+
// ============================================================================
|
|
659
|
+
/**
|
|
660
|
+
* Iterate over bytes
|
|
661
|
+
*/
|
|
662
|
+
*[Symbol.iterator]() {
|
|
663
|
+
for (const byte of this._data) {
|
|
664
|
+
yield byte;
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
/**
|
|
668
|
+
* Get entries iterator
|
|
669
|
+
*/
|
|
670
|
+
*entries() {
|
|
671
|
+
for (let i = 0; i < this._data.length; i++) {
|
|
672
|
+
yield [i, this._data[i]];
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
/**
|
|
676
|
+
* Get keys iterator
|
|
677
|
+
*/
|
|
678
|
+
*keys() {
|
|
679
|
+
for (let i = 0; i < this._data.length; i++) {
|
|
680
|
+
yield i;
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
/**
|
|
684
|
+
* Get values iterator
|
|
685
|
+
*/
|
|
686
|
+
*values() {
|
|
687
|
+
for (const byte of this._data) {
|
|
688
|
+
yield byte;
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
// ============================================================================
|
|
692
|
+
// Clone
|
|
693
|
+
// ============================================================================
|
|
694
|
+
/**
|
|
695
|
+
* Create a copy of the buffer
|
|
696
|
+
*/
|
|
697
|
+
clone() {
|
|
698
|
+
return new Buffer(globalThis.Buffer.from(this._data));
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
/**
|
|
702
|
+
* A reader for consuming buffer contents
|
|
703
|
+
*/
|
|
704
|
+
export class BufferReader {
|
|
705
|
+
data;
|
|
706
|
+
position;
|
|
707
|
+
constructor(buffer) {
|
|
708
|
+
this.data =
|
|
709
|
+
buffer instanceof Buffer ? buffer.toNodeBuffer() : Buffer.from(buffer).toNodeBuffer();
|
|
710
|
+
this.position = 0;
|
|
711
|
+
}
|
|
712
|
+
/**
|
|
713
|
+
* Get the current read position
|
|
714
|
+
*/
|
|
715
|
+
get pos() {
|
|
716
|
+
return this.position;
|
|
717
|
+
}
|
|
718
|
+
/**
|
|
719
|
+
* Get the number of bytes remaining
|
|
720
|
+
*/
|
|
721
|
+
get remaining() {
|
|
722
|
+
return this.data.length - this.position;
|
|
723
|
+
}
|
|
724
|
+
/**
|
|
725
|
+
* Check if we've reached the end
|
|
726
|
+
*/
|
|
727
|
+
get isEof() {
|
|
728
|
+
return this.position >= this.data.length;
|
|
729
|
+
}
|
|
730
|
+
/**
|
|
731
|
+
* Peek at the next byte without consuming it
|
|
732
|
+
*/
|
|
733
|
+
peek() {
|
|
734
|
+
if (this.position >= this.data.length) {
|
|
735
|
+
return null;
|
|
736
|
+
}
|
|
737
|
+
return this.data[this.position] ?? null;
|
|
738
|
+
}
|
|
739
|
+
/**
|
|
740
|
+
* Read a single byte
|
|
741
|
+
*/
|
|
742
|
+
readByte() {
|
|
743
|
+
if (this.position >= this.data.length) {
|
|
744
|
+
return null;
|
|
745
|
+
}
|
|
746
|
+
return this.data[this.position++] ?? null;
|
|
747
|
+
}
|
|
748
|
+
/**
|
|
749
|
+
* Read bytes into a buffer
|
|
750
|
+
*/
|
|
751
|
+
read(length) {
|
|
752
|
+
const end = Math.min(this.position + length, this.data.length);
|
|
753
|
+
const result = new Uint8Array(this.data.subarray(this.position, end));
|
|
754
|
+
this.position = end;
|
|
755
|
+
return result;
|
|
756
|
+
}
|
|
757
|
+
/**
|
|
758
|
+
* Read exactly n bytes, or throw if not enough data
|
|
759
|
+
*/
|
|
760
|
+
readExact(length) {
|
|
761
|
+
if (this.remaining < length) {
|
|
762
|
+
throw MicroPDFError.eof();
|
|
763
|
+
}
|
|
764
|
+
return this.read(length);
|
|
765
|
+
}
|
|
766
|
+
/**
|
|
767
|
+
* Read a 16-bit unsigned integer (big-endian)
|
|
768
|
+
*/
|
|
769
|
+
readUInt16BE() {
|
|
770
|
+
if (this.remaining < 2)
|
|
771
|
+
throw MicroPDFError.eof();
|
|
772
|
+
const value = this.data.readUInt16BE(this.position);
|
|
773
|
+
this.position += 2;
|
|
774
|
+
return value;
|
|
775
|
+
}
|
|
776
|
+
/**
|
|
777
|
+
* Read a 32-bit unsigned integer (big-endian)
|
|
778
|
+
*/
|
|
779
|
+
readUInt32BE() {
|
|
780
|
+
if (this.remaining < 4)
|
|
781
|
+
throw MicroPDFError.eof();
|
|
782
|
+
const value = this.data.readUInt32BE(this.position);
|
|
783
|
+
this.position += 4;
|
|
784
|
+
return value;
|
|
785
|
+
}
|
|
786
|
+
/**
|
|
787
|
+
* Read a 16-bit unsigned integer (little-endian)
|
|
788
|
+
*/
|
|
789
|
+
readUInt16LE() {
|
|
790
|
+
if (this.remaining < 2)
|
|
791
|
+
throw MicroPDFError.eof();
|
|
792
|
+
const value = this.data.readUInt16LE(this.position);
|
|
793
|
+
this.position += 2;
|
|
794
|
+
return value;
|
|
795
|
+
}
|
|
796
|
+
/**
|
|
797
|
+
* Read a 32-bit unsigned integer (little-endian)
|
|
798
|
+
*/
|
|
799
|
+
readUInt32LE() {
|
|
800
|
+
if (this.remaining < 4)
|
|
801
|
+
throw MicroPDFError.eof();
|
|
802
|
+
const value = this.data.readUInt32LE(this.position);
|
|
803
|
+
this.position += 4;
|
|
804
|
+
return value;
|
|
805
|
+
}
|
|
806
|
+
/**
|
|
807
|
+
* Read a 24-bit unsigned integer (big-endian)
|
|
808
|
+
*/
|
|
809
|
+
readUInt24BE() {
|
|
810
|
+
if (this.remaining < 3)
|
|
811
|
+
throw MicroPDFError.eof();
|
|
812
|
+
const b0 = this.data[this.position++];
|
|
813
|
+
const b1 = this.data[this.position++];
|
|
814
|
+
const b2 = this.data[this.position++];
|
|
815
|
+
return (b0 << 16) | (b1 << 8) | b2;
|
|
816
|
+
}
|
|
817
|
+
/**
|
|
818
|
+
* Seek to a position
|
|
819
|
+
*/
|
|
820
|
+
seek(pos) {
|
|
821
|
+
this.position = Math.max(0, Math.min(pos, this.data.length));
|
|
822
|
+
return this;
|
|
823
|
+
}
|
|
824
|
+
/**
|
|
825
|
+
* Skip n bytes
|
|
826
|
+
*/
|
|
827
|
+
skip(n) {
|
|
828
|
+
this.position = Math.min(this.position + n, this.data.length);
|
|
829
|
+
return this;
|
|
830
|
+
}
|
|
831
|
+
/**
|
|
832
|
+
* Read a line (up to and including newline)
|
|
833
|
+
*/
|
|
834
|
+
readLine() {
|
|
835
|
+
if (this.isEof) {
|
|
836
|
+
return null;
|
|
837
|
+
}
|
|
838
|
+
const start = this.position;
|
|
839
|
+
while (this.position < this.data.length) {
|
|
840
|
+
if (this.data[this.position++] === 0x0a) {
|
|
841
|
+
break;
|
|
842
|
+
}
|
|
843
|
+
}
|
|
844
|
+
return new Uint8Array(this.data.subarray(start, this.position));
|
|
845
|
+
}
|
|
846
|
+
/**
|
|
847
|
+
* Read a line as string
|
|
848
|
+
*/
|
|
849
|
+
readLineString(encoding = 'utf-8') {
|
|
850
|
+
const line = this.readLine();
|
|
851
|
+
if (line === null) {
|
|
852
|
+
return null;
|
|
853
|
+
}
|
|
854
|
+
return globalThis.Buffer.from(line).toString(encoding);
|
|
855
|
+
}
|
|
856
|
+
}
|
|
857
|
+
/**
|
|
858
|
+
* A writer that accumulates data into a buffer
|
|
859
|
+
*/
|
|
860
|
+
export class BufferWriter {
|
|
861
|
+
data;
|
|
862
|
+
position;
|
|
863
|
+
constructor(capacity = 256) {
|
|
864
|
+
this.data = globalThis.Buffer.alloc(capacity);
|
|
865
|
+
this.position = 0;
|
|
866
|
+
}
|
|
867
|
+
/**
|
|
868
|
+
* Get the current length
|
|
869
|
+
*/
|
|
870
|
+
get length() {
|
|
871
|
+
return this.position;
|
|
872
|
+
}
|
|
873
|
+
/**
|
|
874
|
+
* Check if empty
|
|
875
|
+
*/
|
|
876
|
+
get isEmpty() {
|
|
877
|
+
return this.position === 0;
|
|
878
|
+
}
|
|
879
|
+
/**
|
|
880
|
+
* Ensure capacity
|
|
881
|
+
*/
|
|
882
|
+
ensureCapacity(additional) {
|
|
883
|
+
const required = this.position + additional;
|
|
884
|
+
if (required > this.data.length) {
|
|
885
|
+
const newCapacity = Math.max(this.data.length * 2, required);
|
|
886
|
+
const newData = globalThis.Buffer.alloc(newCapacity);
|
|
887
|
+
this.data.copy(newData, 0, 0, this.position);
|
|
888
|
+
this.data = newData;
|
|
889
|
+
}
|
|
890
|
+
}
|
|
891
|
+
/**
|
|
892
|
+
* Write bytes
|
|
893
|
+
*/
|
|
894
|
+
write(data) {
|
|
895
|
+
const buf = Buffer.from(data).toNodeBuffer();
|
|
896
|
+
this.ensureCapacity(buf.length);
|
|
897
|
+
buf.copy(this.data, this.position);
|
|
898
|
+
this.position += buf.length;
|
|
899
|
+
return this;
|
|
900
|
+
}
|
|
901
|
+
/**
|
|
902
|
+
* Write a single byte
|
|
903
|
+
*/
|
|
904
|
+
writeByte(value) {
|
|
905
|
+
this.ensureCapacity(1);
|
|
906
|
+
this.data[this.position++] = value & 0xff;
|
|
907
|
+
return this;
|
|
908
|
+
}
|
|
909
|
+
/**
|
|
910
|
+
* Write a 16-bit unsigned integer (big-endian)
|
|
911
|
+
*/
|
|
912
|
+
writeUInt16BE(value) {
|
|
913
|
+
this.ensureCapacity(2);
|
|
914
|
+
this.data.writeUInt16BE(value, this.position);
|
|
915
|
+
this.position += 2;
|
|
916
|
+
return this;
|
|
917
|
+
}
|
|
918
|
+
/**
|
|
919
|
+
* Write a 32-bit unsigned integer (big-endian)
|
|
920
|
+
*/
|
|
921
|
+
writeUInt32BE(value) {
|
|
922
|
+
this.ensureCapacity(4);
|
|
923
|
+
this.data.writeUInt32BE(value, this.position);
|
|
924
|
+
this.position += 4;
|
|
925
|
+
return this;
|
|
926
|
+
}
|
|
927
|
+
/**
|
|
928
|
+
* Write a 16-bit unsigned integer (little-endian)
|
|
929
|
+
*/
|
|
930
|
+
writeUInt16LE(value) {
|
|
931
|
+
this.ensureCapacity(2);
|
|
932
|
+
this.data.writeUInt16LE(value, this.position);
|
|
933
|
+
this.position += 2;
|
|
934
|
+
return this;
|
|
935
|
+
}
|
|
936
|
+
/**
|
|
937
|
+
* Write a 32-bit unsigned integer (little-endian)
|
|
938
|
+
*/
|
|
939
|
+
writeUInt32LE(value) {
|
|
940
|
+
this.ensureCapacity(4);
|
|
941
|
+
this.data.writeUInt32LE(value, this.position);
|
|
942
|
+
this.position += 4;
|
|
943
|
+
return this;
|
|
944
|
+
}
|
|
945
|
+
/**
|
|
946
|
+
* Write a string
|
|
947
|
+
*/
|
|
948
|
+
writeString(str, encoding = 'utf-8') {
|
|
949
|
+
return this.write(globalThis.Buffer.from(str, encoding));
|
|
950
|
+
}
|
|
951
|
+
/**
|
|
952
|
+
* Get the accumulated data as a slice
|
|
953
|
+
*/
|
|
954
|
+
toSlice() {
|
|
955
|
+
return new Uint8Array(this.data.subarray(0, this.position));
|
|
956
|
+
}
|
|
957
|
+
/**
|
|
958
|
+
* Convert to Buffer
|
|
959
|
+
*/
|
|
960
|
+
toBuffer() {
|
|
961
|
+
return Buffer.fromUint8Array(this.toSlice());
|
|
962
|
+
}
|
|
963
|
+
/**
|
|
964
|
+
* Clear the writer
|
|
965
|
+
*/
|
|
966
|
+
clear() {
|
|
967
|
+
this.position = 0;
|
|
968
|
+
return this;
|
|
969
|
+
}
|
|
970
|
+
}
|
|
971
|
+
//# sourceMappingURL=buffer.js.map
|