object-input-stream 0.1.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.
@@ -0,0 +1,1022 @@
1
+ "use strict";
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 __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __propKey = (this && this.__propKey) || function (x) {
36
+ return typeof x === "symbol" ? x : "".concat(x);
37
+ };
38
+ var __setFunctionName = (this && this.__setFunctionName) || function (f, name, prefix) {
39
+ if (typeof name === "symbol") name = name.description ? "[".concat(name.description, "]") : "";
40
+ return Object.defineProperty(f, "name", { configurable: true, value: prefix ? "".concat(prefix, " ", name) : name });
41
+ };
42
+ Object.defineProperty(exports, "__esModule", { value: true });
43
+ exports.BaseFallbackEnum = exports.BaseFallbackExternalizable = exports.BaseFallbackSerializable = exports.BaseFallbackClass = exports.BaseProxy = exports.ObjectStreamClass = exports.HandleTable = exports.ByteArray = exports.ObjectInputStream = void 0;
44
+ const exc = __importStar(require("./exceptions"));
45
+ const classes_1 = require("./classes");
46
+ class ObjectInputStream {
47
+ constructor(data, options) {
48
+ // ========== CONSTANTS ==========
49
+ this.baseWireHandle = 0x7E0000;
50
+ this.PROTOCOL_VERSION_1 = 1;
51
+ this.PROTOCOL_VERSION_2 = 2;
52
+ this.STREAM_MAGIC = 0xACED;
53
+ this.STREAM_VERSION = 0x0005;
54
+ this.SC_WRITE_METHOD = 0x01;
55
+ this.SC_BLOCK_DATA = 0x08;
56
+ this.SC_SERIALIZABLE = 0x02;
57
+ this.SC_EXTERNALIZABLE = 0x04;
58
+ this.SC_ENUM = 0x10;
59
+ this.TC_BASE = 0x70;
60
+ this.TC_MAX = 0x7E;
61
+ this.TC_NULL = 0x70;
62
+ this.TC_REFERENCE = 0x71;
63
+ this.TC_CLASSDESC = 0x72;
64
+ this.TC_OBJECT = 0x73;
65
+ this.TC_STRING = 0x74;
66
+ this.TC_ARRAY = 0x75;
67
+ this.TC_CLASS = 0x76;
68
+ this.TC_BLOCKDATA = 0x77;
69
+ this.TC_ENDBLOCKDATA = 0x78;
70
+ this.TC_RESET = 0x79;
71
+ this.TC_BLOCKDATALONG = 0x7A;
72
+ this.TC_EXCEPTION = 0x7B;
73
+ this.TC_LONGSTRING = 0x7C;
74
+ this.TC_PROXYCLASSDESC = 0x7D;
75
+ this.TC_ENUM = 0x7E;
76
+ this.data = data;
77
+ this.offset = 0;
78
+ this.blockDataMode = false;
79
+ this.remainingInBlock = -1;
80
+ this.handleTable = new HandleTable();
81
+ this.registeredClasses = new Map();
82
+ this.proxyClasses = new Map();
83
+ this.curContext = null;
84
+ if (this.readUnsignedShort() !== this.STREAM_MAGIC)
85
+ throw new exc.StreamCorruptedException("Missing STREAM_MAGIC");
86
+ if (this.readUnsignedShort() !== this.STREAM_VERSION)
87
+ throw new exc.StreamCorruptedException("Missing STREAM_VERSION");
88
+ this.setBlockDataMode(true);
89
+ const initialSerializables = options?.initialClasses?.serializable ?? classes_1.builtinSerializables;
90
+ const initialExternalizables = options?.initialClasses?.externalizable ?? classes_1.builtinExternalizables;
91
+ const initialEnums = options?.initialClasses?.enum ?? classes_1.builtinEnums;
92
+ const initialClasses = options?.initialClasses?.general ?? classes_1.builtinClasses;
93
+ for (const [name, ctor] of initialSerializables)
94
+ this.registerSerializable(name, ctor);
95
+ for (const [name, ctor] of initialExternalizables)
96
+ this.registerExternalizable(name, ctor);
97
+ for (const [name, enum_] of initialEnums)
98
+ this.registerEnum(name, enum_);
99
+ for (const [name, ctor] of initialClasses)
100
+ this.registerClass(name, ctor);
101
+ }
102
+ // ========== PROTECTED BYTE READ METHODS ==========
103
+ setBlockDataMode(newMode) {
104
+ if (this.blockDataMode === newMode) {
105
+ return this.blockDataMode;
106
+ }
107
+ this.remainingInBlock = newMode ? 0 : -1;
108
+ if (!newMode && this.remainingInBlock > 0) {
109
+ throw new exc.IllegalStateException("unread block data");
110
+ }
111
+ this.blockDataMode = newMode;
112
+ return !this.blockDataMode;
113
+ }
114
+ peek1() {
115
+ if (!this.blockDataMode)
116
+ return (this.offset < this.data.length) ? this.data[this.offset] : -1;
117
+ if (this.remainingInBlock === 0)
118
+ this.refillBlockData();
119
+ if (this.remainingInBlock > 0) {
120
+ this.remainingInBlock;
121
+ return this.data[this.offset];
122
+ }
123
+ else {
124
+ return -1;
125
+ }
126
+ }
127
+ peekByte() {
128
+ const result = this.peek1();
129
+ if (result < 0)
130
+ throw new exc.EOFException();
131
+ return result >= 128 ? 256 - result : result;
132
+ }
133
+ readBlockHeader() {
134
+ if (!this.blockDataMode)
135
+ throw new exc.IllegalStateException("readBlockHeader in normal mode");
136
+ if (this.curContext?.defaultEndData)
137
+ // Fix for 4360508
138
+ return -1;
139
+ const oldMode = this.setBlockDataMode(false);
140
+ let len = null;
141
+ try {
142
+ while (len === null) {
143
+ const tc = this.peek1();
144
+ switch (tc) {
145
+ case this.TC_BLOCKDATA:
146
+ this.readByte();
147
+ len = this.readUnsignedByte();
148
+ break;
149
+ case this.TC_BLOCKDATALONG:
150
+ this.readByte();
151
+ len = this.readInt();
152
+ if (len < 0)
153
+ throw new exc.StreamCorruptedException("illegal block data header length: " + len);
154
+ break;
155
+ case this.TC_RESET:
156
+ this.readReset();
157
+ break;
158
+ default:
159
+ if (tc >= 0 && (tc < this.TC_BASE || tc > this.TC_MAX))
160
+ throw new exc.StreamCorruptedException("invalid block type code: " + tcHex(tc));
161
+ len = -1;
162
+ break;
163
+ }
164
+ }
165
+ }
166
+ finally {
167
+ this.setBlockDataMode(oldMode);
168
+ }
169
+ return len;
170
+ }
171
+ refillBlockData() {
172
+ if (!this.blockDataMode)
173
+ throw new exc.IllegalStateException("refill in normal mode");
174
+ if (this.remainingInBlock > 0)
175
+ return;
176
+ while (true) {
177
+ const len = this.readBlockHeader();
178
+ if (len < 0)
179
+ return;
180
+ if (len > 0) {
181
+ this.remainingInBlock = len;
182
+ return;
183
+ }
184
+ }
185
+ }
186
+ // ========== BYTE READ METHODS ==========
187
+ read1() {
188
+ if (!this.blockDataMode)
189
+ return (this.offset < this.data.length) ? this.data[this.offset++] : -1;
190
+ if (this.remainingInBlock === 0)
191
+ this.refillBlockData();
192
+ if (this.remainingInBlock > 0) {
193
+ this.remainingInBlock--;
194
+ return this.data[this.offset++];
195
+ }
196
+ else {
197
+ return -1;
198
+ }
199
+ }
200
+ read(len) {
201
+ len = Math.max(len, 0);
202
+ len = Math.min(len, this.data.length - this.offset);
203
+ if (!this.blockDataMode) {
204
+ const result = new Uint8Array(this.data.slice(this.offset, this.offset + len));
205
+ this.offset += len;
206
+ return result;
207
+ }
208
+ const blocks = [];
209
+ let left = len;
210
+ while (left > 0 && this.peek1() >= 0) {
211
+ const toRead = Math.min(left, this.remainingInBlock);
212
+ const block = this.data.subarray(this.offset, this.offset + toRead);
213
+ this.offset += toRead;
214
+ this.remainingInBlock -= toRead;
215
+ left -= toRead;
216
+ blocks.push(block);
217
+ }
218
+ const result = new Uint8Array(blocks.reduce((sum, cur) => sum + cur.length, 0));
219
+ let offset = 0;
220
+ for (const block of blocks) {
221
+ result.set(block, offset);
222
+ offset += block.length;
223
+ }
224
+ if (offset !== result.length)
225
+ throw new exc.InternalError();
226
+ return result;
227
+ }
228
+ readFully(len) {
229
+ const result = this.read(len);
230
+ if (result.length < len)
231
+ throw new exc.EOFException();
232
+ return result;
233
+ }
234
+ // ========== PROTECTED PRIMITIVE READ METHODS ==========
235
+ readLongUTF() {
236
+ const length = this.readLong();
237
+ if (length > Number.MAX_SAFE_INTEGER) {
238
+ throw new exc.NotImplementedError("string longer than Number.MAX_SAFE_INTEGER bytes");
239
+ }
240
+ return this.readUTFBody(Number(length));
241
+ }
242
+ // https://docs.oracle.com/javase/8/docs/api/java/io/DataInput.html#readUTF--
243
+ readUTFBody(byteLength) {
244
+ const bytes = this.readFully(byteLength);
245
+ const resultChars = new Uint16Array(bytes.length);
246
+ let resultCharsOffset = 0;
247
+ for (let i = 0; i < bytes.length; resultCharsOffset++) {
248
+ const a = bytes[i++];
249
+ // Single-byte group
250
+ if ((a & 128) === 0) {
251
+ resultChars[resultCharsOffset] = a;
252
+ }
253
+ // Two-byte group
254
+ else if ((a & 224) === 192) {
255
+ if (i + 1 > bytes.length)
256
+ throw new exc.UTFDataFormatException();
257
+ const b = bytes[i++];
258
+ if ((b & 192) !== 128)
259
+ throw new exc.UTFDataFormatException();
260
+ resultChars[resultCharsOffset] = (((a & 0x1F) << 6) | (b & 0x3F));
261
+ }
262
+ // Three-byte group
263
+ else if ((a & 240) === 224) {
264
+ if (i + 2 > bytes.length)
265
+ throw new exc.UTFDataFormatException();
266
+ const b = bytes[i++];
267
+ const c = bytes[i++];
268
+ if ((b & 192) !== 128)
269
+ throw new exc.UTFDataFormatException();
270
+ if ((c & 192) !== 128)
271
+ throw new exc.UTFDataFormatException();
272
+ resultChars[resultCharsOffset] = (((a & 0x0F) << 12) | ((b & 0x3F) << 6) | (c & 0x3F));
273
+ }
274
+ // Encoding error
275
+ else {
276
+ throw new exc.UTFDataFormatException();
277
+ }
278
+ }
279
+ return Array.from(resultChars.subarray(0, resultCharsOffset), c => String.fromCharCode(c)).join("");
280
+ }
281
+ readTC() { return this.readByte(); }
282
+ // ========== PRIMITIVE READ METHODS ==========
283
+ readBoolean() {
284
+ return ByteArray.getBoolean(this.readFully(1));
285
+ }
286
+ readByte() {
287
+ return ByteArray.getByte(this.readFully(1));
288
+ }
289
+ readUnsignedByte() {
290
+ return ByteArray.getUnsignedByte(this.readFully(1));
291
+ }
292
+ readChar() {
293
+ return ByteArray.getChar(this.readFully(2));
294
+ }
295
+ readShort() {
296
+ return ByteArray.getShort(this.readFully(2));
297
+ }
298
+ readUnsignedShort() {
299
+ return ByteArray.getUnsignedShort(this.readFully(2));
300
+ }
301
+ readInt() {
302
+ return ByteArray.getInt(this.readFully(4));
303
+ }
304
+ readLong() {
305
+ return ByteArray.getLong(this.readFully(8));
306
+ }
307
+ readFloat() {
308
+ return ByteArray.getFloat(this.readFully(4));
309
+ }
310
+ readDouble() {
311
+ return ByteArray.getDouble(this.readFully(8));
312
+ }
313
+ readUTF() {
314
+ return this.readUTFBody(this.readUnsignedShort());
315
+ }
316
+ // ========== PROTECTED OBJECT READ METHODS ==========
317
+ readReset() {
318
+ if (this.readTC() !== this.TC_RESET)
319
+ throw new exc.InternalError();
320
+ // TODO when depth > 0
321
+ this.handleTable.reset();
322
+ }
323
+ readNull() {
324
+ if (this.readTC() !== this.TC_NULL)
325
+ throw new exc.InternalError();
326
+ return null;
327
+ }
328
+ readHandle() {
329
+ if (this.readTC() !== this.TC_REFERENCE)
330
+ throw new exc.InternalError();
331
+ const handle = this.readInt();
332
+ return this.handleTable.getObject(handle);
333
+ }
334
+ readClass() {
335
+ if (this.readTC() !== this.TC_CLASS)
336
+ throw new exc.InternalError();
337
+ const classDesc = this.readClassDesc();
338
+ if (classDesc === null)
339
+ throw new exc.NullPointerException();
340
+ const result = classDesc.cl;
341
+ const handle = this.handleTable.newHandle(result);
342
+ return result;
343
+ }
344
+ readClassDesc() {
345
+ const tc = this.peekByte();
346
+ switch (tc) {
347
+ case this.TC_NULL:
348
+ return this.readNull();
349
+ case this.TC_PROXYCLASSDESC:
350
+ return this.readProxyDesc();
351
+ case this.TC_CLASSDESC:
352
+ return this.readNonProxyDesc();
353
+ case this.TC_REFERENCE:
354
+ const d = this.readHandle();
355
+ if (!(d instanceof ObjectStreamClass))
356
+ throw new exc.ClassCastException(d);
357
+ d.checkInitialized();
358
+ return d;
359
+ default:
360
+ throw new exc.StreamCorruptedException("invalid classDesc type code: " + tcHex(tc));
361
+ }
362
+ }
363
+ readProxyDesc() {
364
+ if (this.readTC() !== this.TC_PROXYCLASSDESC)
365
+ throw new exc.InternalError();
366
+ const desc = new ObjectStreamClass(null, null, true);
367
+ const handle = this.handleTable.newHandle(desc);
368
+ const proxyInterfaces = [];
369
+ const numIfaces = this.readInt();
370
+ for (let i = 0; i < numIfaces; i++) {
371
+ proxyInterfaces.push(this.readUTF());
372
+ }
373
+ const cl = this.resolveProxyClass(proxyInterfaces);
374
+ const annotation = this.readAnnotation();
375
+ const superDesc = this.readClassDesc();
376
+ desc.initProxy(cl, proxyInterfaces, annotation, superDesc);
377
+ return desc;
378
+ }
379
+ resolveProxyClass(proxyInterfaces) {
380
+ var _a, _b;
381
+ const ifacesStr = proxyInterfaces.join(",");
382
+ if (!this.proxyClasses.has(ifacesStr)) {
383
+ const classId = this.proxyClasses.size.toString();
384
+ const className = "JavaProxy" + classId;
385
+ const newClass = { [_a = __propKey(className)]: (_b = class extends BaseProxy {
386
+ },
387
+ __setFunctionName(_b, _a),
388
+ _b.proxyInterfaces = proxyInterfaces,
389
+ _b) }[className];
390
+ this.proxyClasses.set(ifacesStr, newClass);
391
+ }
392
+ return this.proxyClasses.get(ifacesStr);
393
+ }
394
+ readNonProxyDesc() {
395
+ if (this.readTC() !== this.TC_CLASSDESC)
396
+ throw new exc.InternalError();
397
+ const name = this.readUTF();
398
+ const suid = this.readLong();
399
+ const desc = new ObjectStreamClass(name, suid, false);
400
+ const handle = this.handleTable.newHandle(desc);
401
+ const flags = this.readUnsignedByte();
402
+ const numFields = this.readShort();
403
+ const fields = [];
404
+ for (let i = 0; i < numFields; i++) {
405
+ const typecode = String.fromCodePoint(this.readUnsignedByte());
406
+ const fieldName = this.readUTF();
407
+ switch (typecode) {
408
+ case 'L':
409
+ case '[':
410
+ const className = this.readString();
411
+ fields.push({ typecode, name: fieldName, className });
412
+ break;
413
+ case 'B':
414
+ case 'C':
415
+ case 'D':
416
+ case 'F':
417
+ case 'I':
418
+ case 'J':
419
+ case 'S':
420
+ case 'Z':
421
+ fields.push({ typecode, name: fieldName });
422
+ break;
423
+ default:
424
+ throw new exc.InvalidClassException(name, "invalid typecode for field " + fieldName + ": " + typecode);
425
+ }
426
+ }
427
+ const annotation = this.readAnnotation();
428
+ const superDesc = this.readClassDesc();
429
+ const cl = this.resolveClass(name, this.getClassType(flags), desc, superDesc);
430
+ desc.initNonProxy(cl, flags, fields, annotation, superDesc);
431
+ return desc;
432
+ }
433
+ getClassType(flags) {
434
+ if (flags & this.SC_ENUM)
435
+ return "enum";
436
+ else if (flags & this.SC_SERIALIZABLE)
437
+ return "serializable";
438
+ else if (flags & this.SC_EXTERNALIZABLE)
439
+ return "externalizable";
440
+ else
441
+ return "general";
442
+ }
443
+ resolveClass(name, type, desc, superDesc) {
444
+ var _a, _b;
445
+ if (this.registeredClasses.has(name))
446
+ return this.registeredClasses.get(name)[1];
447
+ const fallbackSuperClass = {
448
+ "general": BaseFallbackClass,
449
+ "serializable": BaseFallbackSerializable,
450
+ "externalizable": BaseFallbackExternalizable,
451
+ "enum": BaseFallbackEnum,
452
+ }[type];
453
+ const superClass = superDesc !== null ? superDesc.cl : fallbackSuperClass;
454
+ const cl = { [_a = __propKey(name)]: (_b = class extends superClass {
455
+ },
456
+ __setFunctionName(_b, _a),
457
+ _b.$desc = desc,
458
+ _b) }[name];
459
+ // @ts-expect-error
460
+ cl.displayName = name;
461
+ return cl;
462
+ }
463
+ readString() {
464
+ const tc = this.readTC();
465
+ let str;
466
+ switch (tc) {
467
+ case this.TC_STRING:
468
+ str = this.readUTF();
469
+ break;
470
+ case this.TC_LONGSTRING:
471
+ str = this.readLongUTF();
472
+ break;
473
+ case this.TC_REFERENCE:
474
+ str = this.readHandle();
475
+ if (typeof str !== "string")
476
+ throw new exc.ClassCastException("string reference is not a string: " + str);
477
+ return str;
478
+ default:
479
+ throw new exc.StreamCorruptedException("invalid string type code: " + tcHex(tc));
480
+ }
481
+ this.handleTable.newHandle(str);
482
+ return str;
483
+ }
484
+ readArray() {
485
+ if (this.readTC() !== this.TC_ARRAY)
486
+ throw new exc.InternalError();
487
+ const desc = this.readClassDesc();
488
+ const len = this.readInt();
489
+ if (len < 0)
490
+ throw new exc.StreamCorruptedException("Array length is negative");
491
+ const result = [];
492
+ const handle = this.handleTable.newHandle(result);
493
+ if (!desc?.name?.startsWith("[") || desc.name.length < 2)
494
+ throw new exc.StreamCorruptedException("Invalid array desc name: " + desc?.name);
495
+ const typecode = desc.name.charAt(1);
496
+ for (let i = 0; i < len; i++) {
497
+ result.push(this.readValue(typecode));
498
+ }
499
+ return result;
500
+ }
501
+ readValue(typecode) {
502
+ switch (typecode) {
503
+ case '[':
504
+ case 'L':
505
+ // TODO: type checking
506
+ return this.readObject();
507
+ case 'B': return this.readByte();
508
+ case 'C': return this.readChar();
509
+ case 'D': return this.readDouble();
510
+ case 'F': return this.readFloat();
511
+ case 'I': return this.readInt();
512
+ case 'J': return this.readLong();
513
+ case 'S': return this.readShort();
514
+ case 'Z': return this.readBoolean();
515
+ default:
516
+ throw new exc.StreamCorruptedException("Unkown field value typecode: " + typecode);
517
+ }
518
+ }
519
+ readEnum() {
520
+ if (this.readTC() !== this.TC_ENUM)
521
+ throw new exc.InternalError();
522
+ const desc = this.readClassDesc();
523
+ if (!desc?.isEnum)
524
+ throw new exc.InvalidClassException(desc?.name ?? null, "non-enum class");
525
+ const handle = this.handleTable.newHandle(null);
526
+ const constantName = this.readString();
527
+ if (!(constantName in desc.cl))
528
+ throw new exc.InvalidClassException(desc.name, "enum constant name doesn't exist: " + constantName);
529
+ // @ts-expect-error
530
+ const result = desc.cl[constantName];
531
+ this.handleTable.replaceObject(handle, null, result);
532
+ return result;
533
+ }
534
+ readOrdinaryObject() {
535
+ if (this.readTC() !== this.TC_OBJECT)
536
+ throw new exc.InternalError();
537
+ const desc = this.readClassDesc();
538
+ if (desc === null)
539
+ throw new exc.NullPointerException();
540
+ const result = new desc.cl();
541
+ const handle = this.handleTable.newHandle(result);
542
+ if (desc.externalizable) {
543
+ this.readExternalData(result, desc);
544
+ }
545
+ else if (desc.serializable) {
546
+ this.readSerialData(result, desc);
547
+ }
548
+ else {
549
+ throw new exc.InvalidClassException(desc.name, "not serializable and not externalizable");
550
+ }
551
+ if (typeof result.readResolve === "function") {
552
+ const replaced = result.readResolve();
553
+ this.handleTable.replaceObject(handle, result, replaced);
554
+ return replaced;
555
+ }
556
+ else {
557
+ return result;
558
+ }
559
+ }
560
+ readExternalData(obj, desc) {
561
+ const registered = this.registeredClasses.get(desc.name)?.[1];
562
+ if (!desc.hasBlockExternalData && desc.cl !== registered)
563
+ throw new exc.ClassNotFoundException("Cannot deserialize instance of Externalizable class " + desc.name + " written using PROTOCOL_VERSION_1, without a matching JS-side class");
564
+ const oldContext = this.curContext;
565
+ this.curContext = null;
566
+ try {
567
+ if (desc.hasBlockExternalData)
568
+ this.setBlockDataMode(true);
569
+ try {
570
+ obj.readExternal(this);
571
+ }
572
+ finally {
573
+ if (desc.hasBlockExternalData)
574
+ this.readAnnotation();
575
+ }
576
+ }
577
+ finally {
578
+ this.curContext = oldContext;
579
+ }
580
+ }
581
+ readSerialData(obj, objDesc) {
582
+ const descs = this.getClassDescHierarchy(objDesc);
583
+ for (const curDesc of descs) {
584
+ const curClass = curDesc.cl;
585
+ let readMethod = null;
586
+ if (obj instanceof curClass) {
587
+ if (curClass.serialVersionUID !== undefined && curClass.serialVersionUID !== curDesc.suid)
588
+ throw new exc.InvalidClassException(curDesc.name, "stream suid " + curDesc.suid + " doesn't match available suid " + curClass.serialVersionUID);
589
+ if (typeof curClass.prototype.readObject === "function") {
590
+ readMethod = curClass.prototype.readObject;
591
+ }
592
+ else {
593
+ readMethod = defaultReadMethod;
594
+ }
595
+ }
596
+ else {
597
+ if (curClass.prototype instanceof BaseFallbackClass) {
598
+ readMethod = defaultReadMethod;
599
+ }
600
+ else {
601
+ throw new exc.ClassNotFoundException(curDesc.name + " parent of " + objDesc.name + " in java but not in javascript");
602
+ }
603
+ }
604
+ const oldContext = this.curContext;
605
+ this.curContext = {
606
+ desc: curDesc,
607
+ obj,
608
+ alreadyReadFields: false,
609
+ defaultEndData: false,
610
+ };
611
+ this.setBlockDataMode(true);
612
+ readMethod.apply(obj, [this]);
613
+ if (curDesc.hasWriteObjectData)
614
+ this.readAnnotation();
615
+ this.curContext = oldContext;
616
+ }
617
+ }
618
+ getClassDescHierarchy(classDesc) {
619
+ const hierarchy = [];
620
+ let currClass = classDesc;
621
+ while (currClass !== null) {
622
+ hierarchy.push(currClass);
623
+ currClass = currClass.superDesc;
624
+ }
625
+ return hierarchy.reverse();
626
+ }
627
+ readFatalException() {
628
+ if (this.readTC() !== this.TC_EXCEPTION)
629
+ throw new exc.InternalError();
630
+ this.handleTable.reset();
631
+ const oldMode = this.setBlockDataMode(false);
632
+ const tc = this.peekByte();
633
+ this.setBlockDataMode(oldMode);
634
+ if (tc !== this.TC_OBJECT && tc !== this.TC_REFERENCE)
635
+ throw new exc.StreamCorruptedException("invalid exception type code: " + tcHex(tc));
636
+ const result = this.readObject();
637
+ // This line is required by the spec and implemented in OpenJDK's ObjectOutputStream,
638
+ // but not in OpenJDK's ObjectInputStream. This is a bug in OpenJDK.
639
+ this.handleTable.reset();
640
+ return result;
641
+ }
642
+ readAnnotation() {
643
+ const result = [];
644
+ while (true) {
645
+ if (this.blockDataMode) {
646
+ const block = this.read(Infinity);
647
+ if (block.length > 0)
648
+ result.push(block);
649
+ this.setBlockDataMode(false);
650
+ }
651
+ switch (this.peekByte()) {
652
+ case this.TC_BLOCKDATA:
653
+ case this.TC_BLOCKDATALONG:
654
+ this.setBlockDataMode(true);
655
+ break;
656
+ case this.TC_ENDBLOCKDATA:
657
+ this.readByte();
658
+ return result;
659
+ default:
660
+ result.push(this.readObject());
661
+ break;
662
+ }
663
+ }
664
+ }
665
+ // ========== OBJECT READ METHODS ==========
666
+ readObject() {
667
+ const oldMode = this.blockDataMode;
668
+ if (this.blockDataMode) {
669
+ this.peek1();
670
+ if (this.remainingInBlock > 0) {
671
+ throw new exc.OptionalDataException(this.remainingInBlock);
672
+ }
673
+ else if (this.curContext?.defaultEndData) {
674
+ // Fix for 4360508
675
+ throw new exc.OptionalDataException(true);
676
+ }
677
+ this.setBlockDataMode(false);
678
+ }
679
+ let tc;
680
+ // Skip resets
681
+ while ((tc = this.peekByte()) === this.TC_RESET)
682
+ this.readReset();
683
+ try {
684
+ switch (tc) {
685
+ case this.TC_NULL:
686
+ return this.readNull();
687
+ case this.TC_REFERENCE:
688
+ return this.readHandle();
689
+ case this.TC_CLASS:
690
+ return this.readClass();
691
+ case this.TC_CLASSDESC:
692
+ case this.TC_PROXYCLASSDESC:
693
+ return this.readClassDesc();
694
+ case this.TC_STRING:
695
+ case this.TC_LONGSTRING:
696
+ return this.readString();
697
+ case this.TC_ARRAY:
698
+ return this.readArray();
699
+ case this.TC_ENUM:
700
+ return this.readEnum();
701
+ case this.TC_OBJECT:
702
+ return this.readOrdinaryObject();
703
+ case this.TC_EXCEPTION:
704
+ const ex = this.readFatalException();
705
+ throw new exc.WriteAbortedException("writing aborted", ex);
706
+ case this.TC_ENDBLOCKDATA:
707
+ if (oldMode) {
708
+ throw new exc.OptionalDataException(true);
709
+ }
710
+ else {
711
+ throw new exc.StreamCorruptedException("unexpected end of block data");
712
+ }
713
+ default:
714
+ throw new exc.StreamCorruptedException("invalid object type code: " + tcHex(tc));
715
+ }
716
+ }
717
+ finally {
718
+ this.setBlockDataMode(oldMode);
719
+ }
720
+ }
721
+ readFields() {
722
+ if (this.curContext === null)
723
+ throw new exc.NotActiveException("Not inside a readObject method");
724
+ if (this.curContext.alreadyReadFields)
725
+ throw new exc.NotActiveException("Fields already read");
726
+ const fields = this.curContext.desc.fields;
727
+ if (fields === null)
728
+ throw new exc.InternalError();
729
+ this.setBlockDataMode(false);
730
+ const result = new Map();
731
+ for (const field of fields) {
732
+ result.set(field.name, this.readValue(field.typecode));
733
+ }
734
+ this.setBlockDataMode(true);
735
+ this.curContext.alreadyReadFields = true;
736
+ if (!this.curContext.desc.hasWriteObjectData)
737
+ this.curContext.defaultEndData = true;
738
+ return result;
739
+ }
740
+ defaultReadObject() {
741
+ const fields = this.readFields();
742
+ const obj = this.curContext?.obj;
743
+ for (const [k, v] of fields.entries()) {
744
+ // @ts-expect-error
745
+ obj[k] = v;
746
+ }
747
+ }
748
+ readEverything() {
749
+ const result = [];
750
+ try {
751
+ while (true) {
752
+ const block = this.read(Infinity);
753
+ if (block.length > 0)
754
+ result.push(block);
755
+ result.push(this.readObject());
756
+ }
757
+ }
758
+ catch (e) {
759
+ if (!(e instanceof exc.OptionalDataException || e instanceof exc.EOFException))
760
+ throw e;
761
+ }
762
+ return result;
763
+ }
764
+ // ========== PROTECTED CLASS REGISTRATION METHODS ==========
765
+ registerClass0(name, clazz, type) {
766
+ this.registeredClasses.set(name, [type, clazz]);
767
+ }
768
+ // ========== CLASS REGISTRATION METHODS ==========
769
+ registerSerializable(name, ctor) {
770
+ return this.registerClass0(name, ctor, "serializable");
771
+ }
772
+ registerExternalizable(name, ctor) {
773
+ return this.registerClass0(name, ctor, "externalizable");
774
+ }
775
+ registerEnum(name, enum_) {
776
+ return this.registerClass0(name, enum_, "enum");
777
+ }
778
+ registerClass(name, clazz) {
779
+ return this.registerClass0(name, clazz, "general");
780
+ }
781
+ }
782
+ exports.ObjectInputStream = ObjectInputStream;
783
+ ObjectInputStream.baseWireHandle = 0x7E0000;
784
+ ObjectInputStream.PROTOCOL_VERSION_1 = 1;
785
+ ObjectInputStream.PROTOCOL_VERSION_2 = 2;
786
+ ObjectInputStream.STREAM_MAGIC = 0xACED;
787
+ ObjectInputStream.STREAM_VERSION = 0x0005;
788
+ ObjectInputStream.SC_WRITE_METHOD = 0x01;
789
+ ObjectInputStream.SC_BLOCK_DATA = 0x08;
790
+ ObjectInputStream.SC_SERIALIZABLE = 0x02;
791
+ ObjectInputStream.SC_EXTERNALIZABLE = 0x04;
792
+ ObjectInputStream.SC_ENUM = 0x10;
793
+ ObjectInputStream.TC_BASE = 0x70;
794
+ ObjectInputStream.TC_MAX = 0x7E;
795
+ ObjectInputStream.TC_NULL = 0x70;
796
+ ObjectInputStream.TC_REFERENCE = 0x71;
797
+ ObjectInputStream.TC_CLASSDESC = 0x72;
798
+ ObjectInputStream.TC_OBJECT = 0x73;
799
+ ObjectInputStream.TC_STRING = 0x74;
800
+ ObjectInputStream.TC_ARRAY = 0x75;
801
+ ObjectInputStream.TC_CLASS = 0x76;
802
+ ObjectInputStream.TC_BLOCKDATA = 0x77;
803
+ ObjectInputStream.TC_ENDBLOCKDATA = 0x78;
804
+ ObjectInputStream.TC_RESET = 0x79;
805
+ ObjectInputStream.TC_BLOCKDATALONG = 0x7A;
806
+ ObjectInputStream.TC_EXCEPTION = 0x7B;
807
+ ObjectInputStream.TC_LONGSTRING = 0x7C;
808
+ ObjectInputStream.TC_PROXYCLASSDESC = 0x7D;
809
+ ObjectInputStream.TC_ENUM = 0x7E;
810
+ exports.default = ObjectInputStream;
811
+ class ByteArray {
812
+ static getIntegral(arr, numBytes, signed) {
813
+ if (arr.length < numBytes) {
814
+ throw new exc.IndexOutOfBoundsException();
815
+ }
816
+ if (numBytes <= 0) {
817
+ return 0n;
818
+ }
819
+ const bytes = arr.subarray(0, numBytes);
820
+ let result = 0n;
821
+ for (const byte of bytes) {
822
+ result <<= 8n;
823
+ result += BigInt(byte);
824
+ }
825
+ if (signed) {
826
+ const topBit = 1n << BigInt(numBytes * 8 - 1);
827
+ if ((result & topBit) !== 0n) {
828
+ result -= 1n << BigInt(numBytes * 8);
829
+ }
830
+ }
831
+ return result;
832
+ }
833
+ static getBoolean(arr) {
834
+ if (arr.length < 1)
835
+ throw new exc.IndexOutOfBoundsException();
836
+ return arr[0] !== 0;
837
+ }
838
+ static getByte(arr) {
839
+ return Number(this.getIntegral(arr, 1, true));
840
+ }
841
+ static getUnsignedByte(arr) {
842
+ return Number(this.getIntegral(arr, 1, false));
843
+ }
844
+ static getChar(arr) {
845
+ return String.fromCharCode(Number(this.getIntegral(arr, 2, false)));
846
+ }
847
+ static getShort(arr) {
848
+ return Number(this.getIntegral(arr, 2, true));
849
+ }
850
+ static getUnsignedShort(arr) {
851
+ return Number(this.getIntegral(arr, 2, false));
852
+ }
853
+ static getInt(arr) {
854
+ return Number(this.getIntegral(arr, 4, true));
855
+ }
856
+ static getLong(arr) {
857
+ return this.getIntegral(arr, 8, true);
858
+ }
859
+ static getFloat(arr) {
860
+ if (arr.length < 4)
861
+ throw new exc.IndexOutOfBoundsException();
862
+ return new DataView(arr.subarray(0, 4).buffer).getFloat32(0, false);
863
+ }
864
+ static getDouble(arr) {
865
+ if (arr.length < 8)
866
+ throw new exc.IndexOutOfBoundsException();
867
+ return new DataView(arr.subarray(0, 8).buffer).getFloat64(0, false);
868
+ }
869
+ }
870
+ exports.ByteArray = ByteArray;
871
+ class HandleTable {
872
+ constructor() {
873
+ this.table = new Map();
874
+ this.currHandle = ObjectInputStream.baseWireHandle;
875
+ }
876
+ reset() {
877
+ this.table.clear();
878
+ this.currHandle = ObjectInputStream.baseWireHandle;
879
+ }
880
+ newHandle(obj) {
881
+ const handle = this.currHandle++;
882
+ this.table.set(handle, obj);
883
+ return handle;
884
+ }
885
+ getObject(handle) {
886
+ if (!this.table.has(handle))
887
+ throw new exc.StreamCorruptedException("Object handle doesn't exist: " + handle);
888
+ return this.table.get(handle);
889
+ }
890
+ replaceObject(handle, oldObj, newObj) {
891
+ if (this.table.get(handle) !== oldObj)
892
+ throw new exc.IllegalStateException(`Replaced handle ${handle} doesn't refer to object ${oldObj}`);
893
+ this.table.set(handle, newObj);
894
+ }
895
+ }
896
+ exports.HandleTable = HandleTable;
897
+ function tcHex(tc) {
898
+ return tc.toString(16).padStart(2, '0');
899
+ }
900
+ class ObjectStreamClass {
901
+ constructor(name, suid, isProxy) {
902
+ this.initialized = false;
903
+ this.name = name;
904
+ this.suid = suid;
905
+ this.isProxy = isProxy;
906
+ // Set default values
907
+ this.cl = Object;
908
+ this.fields = (isProxy ? null : []);
909
+ this.proxyInterfaces = (isProxy ? [] : null);
910
+ this.isEnum = false;
911
+ this.serializable = false;
912
+ this.externalizable = false;
913
+ this.hasWriteObjectData = false;
914
+ this.hasBlockExternalData = false;
915
+ this.annotation = [];
916
+ this.superDesc = null;
917
+ }
918
+ initNonProxy(cl, flags, fields, annotation, superDesc) {
919
+ if (this.isProxy)
920
+ throw new exc.IllegalStateException("initialize non-proxy on a proxy class");
921
+ if (this.initialized)
922
+ throw new exc.IllegalStateException("already initialized non-proxy");
923
+ this.cl = cl;
924
+ this.isEnum = (flags & ObjectInputStream.SC_ENUM) !== 0;
925
+ this.serializable = (flags & ObjectInputStream.SC_SERIALIZABLE) !== 0;
926
+ this.externalizable = (flags & ObjectInputStream.SC_EXTERNALIZABLE) !== 0;
927
+ this.hasWriteObjectData = (flags & ObjectInputStream.SC_WRITE_METHOD) !== 0;
928
+ this.hasBlockExternalData = (flags & ObjectInputStream.SC_BLOCK_DATA) !== 0;
929
+ this.fields = fields;
930
+ this.annotation = annotation;
931
+ this.superDesc = superDesc;
932
+ if (this.serializable && this.externalizable)
933
+ throw new exc.InvalidClassException(this.name, "serializable and externalizable flags conflict");
934
+ if (this.isEnum && this.suid !== 0n)
935
+ throw new exc.InvalidClassException(this.name, "enum descriptor has non-zero serialVersionUID: " + this.suid);
936
+ if (this.isEnum && this.fields.length > 0)
937
+ throw new exc.InvalidClassException(this.name, "enum descriptor has non-zero field count: " + this.fields.length);
938
+ this.initialized = true;
939
+ }
940
+ initProxy(cl, proxyInterfaces, annotation, superDesc) {
941
+ if (!this.isProxy)
942
+ throw new exc.IllegalStateException("initialize proxy on a non-proxy class");
943
+ if (this.initialized)
944
+ throw new exc.IllegalStateException("already initialized proxy");
945
+ this.cl = cl;
946
+ this.proxyInterfaces = proxyInterfaces;
947
+ this.annotation = annotation;
948
+ this.superDesc = superDesc;
949
+ this.initialized = true;
950
+ }
951
+ checkInitialized() {
952
+ if (!this.initialized)
953
+ throw new exc.InvalidClassException(this.name, "Class descriptor should be initialized");
954
+ }
955
+ }
956
+ exports.ObjectStreamClass = ObjectStreamClass;
957
+ class BaseProxy {
958
+ constructor(h) {
959
+ this.h = h;
960
+ return new Proxy(this, { get: (target, prop, receiver) => {
961
+ if (typeof prop !== "string")
962
+ return Reflect.get(target, prop, receiver);
963
+ if (this.h === undefined || typeof this.h.invoke !== "function")
964
+ throw new TypeError("invocation handler doesn't have invoke method");
965
+ const h = this.h;
966
+ return (...args) => {
967
+ return h.invoke(target, prop, args);
968
+ };
969
+ } });
970
+ }
971
+ static getInterfaces() {
972
+ return this.proxyInterfaces;
973
+ }
974
+ }
975
+ exports.BaseProxy = BaseProxy;
976
+ BaseProxy.proxyInterfaces = [];
977
+ class BaseFallbackClass {
978
+ }
979
+ exports.BaseFallbackClass = BaseFallbackClass;
980
+ class BaseFallbackSerializable extends BaseFallbackClass {
981
+ constructor() {
982
+ super(...arguments);
983
+ this.$annotation = [];
984
+ }
985
+ readObject(ois) {
986
+ ois.defaultReadObject();
987
+ this.$annotation.push(ois.readEverything());
988
+ }
989
+ }
990
+ exports.BaseFallbackSerializable = BaseFallbackSerializable;
991
+ class BaseFallbackExternalizable extends BaseFallbackClass {
992
+ constructor() {
993
+ super(...arguments);
994
+ this.$annotation = [];
995
+ }
996
+ readExternal(ois) {
997
+ this.$annotation = ois.readEverything();
998
+ }
999
+ }
1000
+ exports.BaseFallbackExternalizable = BaseFallbackExternalizable;
1001
+ class BaseFallbackEnum extends BaseFallbackClass {
1002
+ constructor() {
1003
+ super();
1004
+ return new Proxy(this, {
1005
+ get: (target, prop, receiver) => {
1006
+ if (typeof prop !== "string")
1007
+ return Reflect.get(target, prop, receiver);
1008
+ return prop;
1009
+ },
1010
+ has(target, prop) {
1011
+ if (typeof prop === "string")
1012
+ return true;
1013
+ return prop in target;
1014
+ },
1015
+ });
1016
+ }
1017
+ }
1018
+ exports.BaseFallbackEnum = BaseFallbackEnum;
1019
+ function defaultReadMethod(ois) {
1020
+ ois.defaultReadObject();
1021
+ }
1022
+ //# sourceMappingURL=object-input-stream.js.map