object-input-stream 0.1.0 → 0.2.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 +18 -16
- package/package.json +2 -1
- package/src/ast.ts +46 -43
- package/src/index.ts +2 -0
- package/src/internal.ts +2 -0
- package/src/object-input-stream.ts +179 -119
- package/src/ois-ast.ts +885 -91
- package/dist/ast.d.ts +0 -278
- package/dist/ast.d.ts.map +0 -1
- package/dist/ast.js +0 -3
- package/dist/ast.js.map +0 -1
- package/dist/classes.d.ts +0 -86
- package/dist/classes.d.ts.map +0 -1
- package/dist/classes.js +0 -193
- package/dist/classes.js.map +0 -1
- package/dist/example.d.ts +0 -2
- package/dist/example.d.ts.map +0 -1
- package/dist/example.js +0 -36
- package/dist/example.js.map +0 -1
- package/dist/exceptions.d.ts +0 -66
- package/dist/exceptions.d.ts.map +0 -1
- package/dist/exceptions.js +0 -154
- package/dist/exceptions.js.map +0 -1
- package/dist/index.d.ts +0 -8
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -49
- package/dist/index.js.map +0 -1
- package/dist/internal.d.ts +0 -2
- package/dist/internal.d.ts.map +0 -1
- package/dist/internal.js +0 -12
- package/dist/internal.js.map +0 -1
- package/dist/object-input-stream.d.ts +0 -226
- package/dist/object-input-stream.d.ts.map +0 -1
- package/dist/object-input-stream.js +0 -1022
- package/dist/object-input-stream.js.map +0 -1
- package/dist/ois-ast.d.ts +0 -21
- package/dist/ois-ast.d.ts.map +0 -1
- package/dist/ois-ast.js +0 -229
- package/dist/ois-ast.js.map +0 -1
package/README.md
CHANGED
|
@@ -98,9 +98,9 @@ class CustomSerializable implements Serializable {
|
|
|
98
98
|
ois.registerSerializable("com.mypackage.CustomSerializable", CustomSerializable);
|
|
99
99
|
```
|
|
100
100
|
|
|
101
|
-
>
|
|
101
|
+
> Warning: Java serializable classes that don't write their fields before writing anything else to stream MUST have a custom handler class that replicates that behavior. Not doing that could lead to undefined behavior.
|
|
102
102
|
|
|
103
|
-
>
|
|
103
|
+
> Note: if you recreate and register an entire inheritence chain of serializable classes, their `readObject` methods will be called in order, same as in Java. For every class in the chain that doesn't have a JavaScript handler / where the handler class doesn't have a `readObject` method, `ois.defaultReadObject` is called, again, same as in Java.
|
|
104
104
|
|
|
105
105
|
##### Externalizable Classes
|
|
106
106
|
|
|
@@ -122,7 +122,7 @@ class CustomExternalizable implements Externalizable {
|
|
|
122
122
|
ois.registerExternalizable("com.mypackage.CustomExternalizable", CustomExternalizable);
|
|
123
123
|
```
|
|
124
124
|
|
|
125
|
-
> Warning: Java externalizable objects written using `PROTOCOL_VERSION_1` MUST have a custom handler class that reads all written data to stream. Not doing that
|
|
125
|
+
> Warning: Java externalizable objects written using `PROTOCOL_VERSION_1` MUST have a custom handler class that reads all written data to stream. Not doing that could lead to undefined behavior.
|
|
126
126
|
|
|
127
127
|
##### Enum Objects
|
|
128
128
|
|
|
@@ -223,7 +223,7 @@ Dynamically generated general class handlers are of the following structure:
|
|
|
223
223
|
```ts
|
|
224
224
|
class ExampleProxy {
|
|
225
225
|
// A list of the proxy interface names associated with the class
|
|
226
|
-
static readonly proxyInterfaces: string[] = []
|
|
226
|
+
static readonly $proxyInterfaces: string[] = []
|
|
227
227
|
// The proxy handler class / lambda from Java
|
|
228
228
|
h?: InvocationHandler
|
|
229
229
|
// Creates a proxy object that calls this.h on property access
|
|
@@ -235,6 +235,8 @@ interface InvocationHandler {
|
|
|
235
235
|
}
|
|
236
236
|
```
|
|
237
237
|
|
|
238
|
+
To use a proxy object in JavaScript, you will need to register a class to correspond to its handler's class.
|
|
239
|
+
|
|
238
240
|
#### Built-in Class Handlers
|
|
239
241
|
|
|
240
242
|
Primitive wrapper types have built-in handler classes that implement `readResolve` to replace instances with their primitive values. E.g. if the next object on stream is an `Integer` of value 5 and you call `readObject`, it will return the primitive value `5`.
|
|
@@ -283,21 +285,21 @@ type OisOptions = {
|
|
|
283
285
|
## AST
|
|
284
286
|
|
|
285
287
|
```js
|
|
286
|
-
|
|
288
|
+
import { ObjectInputStreamAST } from 'object-input-stream';
|
|
289
|
+
|
|
290
|
+
const data = new Uint8Array( /* Java object serialization stream data */ );
|
|
291
|
+
const ois = new ObjectInputStream(data);
|
|
292
|
+
|
|
293
|
+
// Read everything
|
|
294
|
+
|
|
295
|
+
const ast = ois.getAST();
|
|
287
296
|
```
|
|
288
297
|
|
|
298
|
+
> WARNING: The AST structure and API are unstable, and may change at any time.
|
|
299
|
+
|
|
300
|
+
> Note: an AST can be reliably produced only for a stream that has been parsed fully and without errors.
|
|
301
|
+
|
|
289
302
|
## Limitations
|
|
290
303
|
|
|
291
304
|
- Requires a runtime that supports `bigint` (all modern runtimes)
|
|
292
305
|
- Doesn't support strings over 9 petabytes in size (`Number.MAX_SAFE_INTEGER` bytes)
|
|
293
|
-
|
|
294
|
-
## TODO
|
|
295
|
-
|
|
296
|
-
- [ ] ObjectInputStreamAST class: emit AST after parsing
|
|
297
|
-
- [ ] Complete existing tests
|
|
298
|
-
- [ ] Expand tests
|
|
299
|
-
- [ ] Classes
|
|
300
|
-
- [ ] Class descriptors
|
|
301
|
-
- [ ] Proxy classes
|
|
302
|
-
- [ ] Enums
|
|
303
|
-
- [ ] Sudden death: a brazillian randomly generated primitives and objects with a complex reference graph and readObject/readExternal
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "object-input-stream",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "ObjectInputStream for JavaScript. Read Java serialized objects in Node and the browser.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.js",
|
|
@@ -34,6 +34,7 @@
|
|
|
34
34
|
"cross-env": "^10.1.0",
|
|
35
35
|
"jest": "^30.2.0",
|
|
36
36
|
"ts-jest": "^29.4.6",
|
|
37
|
+
"ts-node": "^10.9.2",
|
|
37
38
|
"typescript": "^5.9.3"
|
|
38
39
|
}
|
|
39
40
|
}
|
package/src/ast.ts
CHANGED
|
@@ -22,8 +22,10 @@ export default Ast
|
|
|
22
22
|
export type Node =
|
|
23
23
|
RootNode | MagicNode | VersionNode | ContentsNode
|
|
24
24
|
| BlockDataSequenceNode | BlockDataNode
|
|
25
|
-
| PrimitiveNode | UtfNode | LongUtfNode | UtfBodyNode
|
|
25
|
+
| PrimitiveNode | UtfNode | LongUtfNode | UtfBodyNode
|
|
26
26
|
| ObjectNode | TCNode | ClassDescInfoNode | ProxyClassDescInfoNode
|
|
27
|
+
| SerialDataNode | ExternalDataNode | SerialClassDataNode | FieldsNode | ValuesNode | FieldDescNode
|
|
28
|
+
| AnnotationNode
|
|
27
29
|
|
|
28
30
|
export interface RootNode extends BaseNode<[MagicNode, VersionNode, ContentsNode]> {
|
|
29
31
|
type: "root"
|
|
@@ -36,7 +38,7 @@ export interface ContentsNode extends BaseNode<(BlockDataSequenceNode | ObjectNo
|
|
|
36
38
|
type: "contents"
|
|
37
39
|
}
|
|
38
40
|
|
|
39
|
-
interface BaseNode<C extends
|
|
41
|
+
interface BaseNode<C extends Node[] | null> {
|
|
40
42
|
type: string
|
|
41
43
|
span: {start: number, end: number}
|
|
42
44
|
children: C
|
|
@@ -46,12 +48,12 @@ interface BaseNode<C extends BaseNode<any>[] | null> {
|
|
|
46
48
|
|
|
47
49
|
// ========== Primitives ==========
|
|
48
50
|
|
|
49
|
-
export type PrimitiveNode = ByteNode | UnsignedByteNode | ShortNode | UnsignedShortNode | IntNode | FloatNode | DoubleNode | CharNode | BooleanNode | LongNode
|
|
51
|
+
export type PrimitiveNode = ByteNode | UnsignedByteNode | ShortNode | UnsignedShortNode | IntNode | FloatNode | DoubleNode | CharNode | BooleanNode | LongNode | BytesNode
|
|
50
52
|
|
|
51
53
|
interface BasePrimitiveNode extends BaseNode<null> {
|
|
52
54
|
type: "primitive"
|
|
53
55
|
dataType: string
|
|
54
|
-
value: number | string | boolean | bigint
|
|
56
|
+
value: number | string | boolean | bigint | null
|
|
55
57
|
}
|
|
56
58
|
interface NumberNode extends BasePrimitiveNode {
|
|
57
59
|
dataType: string
|
|
@@ -77,33 +79,30 @@ export interface LongNode extends BasePrimitiveNode {
|
|
|
77
79
|
dataType: "long"
|
|
78
80
|
value: bigint
|
|
79
81
|
}
|
|
82
|
+
export interface BytesNode extends BasePrimitiveNode {
|
|
83
|
+
dataType: "bytes"
|
|
84
|
+
value: null
|
|
85
|
+
}
|
|
80
86
|
|
|
81
87
|
export interface UtfNode extends BaseNode<[UnsignedShortNode, UtfBodyNode]> {
|
|
82
88
|
type: "utf"
|
|
89
|
+
value: string
|
|
83
90
|
}
|
|
84
91
|
export interface LongUtfNode extends BaseNode<[LongNode, UtfBodyNode]> {
|
|
85
92
|
type: "long-utf"
|
|
93
|
+
value: string
|
|
86
94
|
}
|
|
87
95
|
export interface UtfBodyNode extends BaseNode<null> {
|
|
88
96
|
type: "utf-body"
|
|
89
97
|
value: string
|
|
90
98
|
}
|
|
91
99
|
|
|
92
|
-
export interface BytesNode extends BaseNode<null> {
|
|
93
|
-
type: "bytes"
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
export interface SkippedNode extends BaseNode<null> {
|
|
97
|
-
type: "skipped"
|
|
98
|
-
reason: string
|
|
99
|
-
}
|
|
100
|
-
|
|
101
100
|
|
|
102
101
|
// ========== Block Data ==========
|
|
103
102
|
|
|
104
|
-
export interface BlockDataSequenceNode extends BaseNode<BlockDataNode[]> {
|
|
103
|
+
export interface BlockDataSequenceNode extends BaseNode<(BlockDataNode | ResetNode)[]> {
|
|
105
104
|
type: "blockdata-sequence"
|
|
106
|
-
values: (PrimitiveNode | UtfNode
|
|
105
|
+
values: (PrimitiveNode | UtfNode)[]
|
|
107
106
|
}
|
|
108
107
|
|
|
109
108
|
export interface BlockDataNode extends BaseNode<
|
|
@@ -119,13 +118,13 @@ export interface BlockDataNode extends BaseNode<
|
|
|
119
118
|
export type ObjectNode = NewObjectNode | NewClassNode | NewArrayNode | NewStringNode | NewEnumNode | NewClassDescNode | PrevObjectNode | NullNode | ExceptionNode | ResetNode
|
|
120
119
|
export type ClassDescNode = NewClassDescNode | NullNode | PrevObjectNode
|
|
121
120
|
|
|
122
|
-
interface BaseObjectNode<C extends [TCNode, ...
|
|
121
|
+
interface BaseObjectNode<C extends [TCNode, ...Node[]]> extends BaseNode<C> {
|
|
123
122
|
type: "object"
|
|
124
123
|
objectType: string
|
|
125
124
|
}
|
|
126
125
|
|
|
127
126
|
export interface NewObjectNode extends BaseObjectNode<
|
|
128
|
-
[TC_OBJECT_Node, ClassDescNode,
|
|
127
|
+
[TC_OBJECT_Node, ClassDescNode, (ExternalDataNode | SerialDataNode)]
|
|
129
128
|
> {
|
|
130
129
|
objectType: "new-object"
|
|
131
130
|
handle: Handle
|
|
@@ -143,9 +142,10 @@ export interface NewStringNode extends BaseObjectNode<
|
|
|
143
142
|
[TC_LONGSTRING_Node, LongUtfNode]
|
|
144
143
|
> {
|
|
145
144
|
objectType: "new-string"
|
|
145
|
+
value: string
|
|
146
146
|
handle: Handle
|
|
147
147
|
}
|
|
148
|
-
export interface NewEnumNode extends BaseObjectNode<[TC_ENUM_Node, ClassDescNode,
|
|
148
|
+
export interface NewEnumNode extends BaseObjectNode<[TC_ENUM_Node, ClassDescNode, StringNode]> {
|
|
149
149
|
objectType: "new-enum"
|
|
150
150
|
handle: Handle
|
|
151
151
|
}
|
|
@@ -163,7 +163,7 @@ export interface PrevObjectNode extends BaseObjectNode<[TC_REFERENCE_Node, IntNo
|
|
|
163
163
|
export interface NullNode extends BaseObjectNode<[TC_NULL_Node]> {
|
|
164
164
|
objectType: "null"
|
|
165
165
|
}
|
|
166
|
-
export interface ExceptionNode extends BaseObjectNode<[TC_EXCEPTION_Node,
|
|
166
|
+
export interface ExceptionNode extends BaseObjectNode<[TC_EXCEPTION_Node, (NewObjectNode | PrevObjectNode)]> {
|
|
167
167
|
objectType: "exception"
|
|
168
168
|
exceptionEpoch: number
|
|
169
169
|
newEpoch: number
|
|
@@ -173,44 +173,47 @@ export interface ResetNode extends BaseObjectNode<[TC_RESET_Node]> {
|
|
|
173
173
|
newEpoch: number
|
|
174
174
|
}
|
|
175
175
|
|
|
176
|
-
export interface ClassDescInfoNode extends BaseNode<[
|
|
176
|
+
export interface ClassDescInfoNode extends BaseNode<[UnsignedByteNode, FieldsNode, AnnotationNode, ClassDescNode]> {
|
|
177
177
|
type: "class-desc-info"
|
|
178
178
|
}
|
|
179
|
-
export interface ProxyClassDescInfoNode extends BaseNode<[IntNode, ...UtfNode[],
|
|
179
|
+
export interface ProxyClassDescInfoNode extends BaseNode<[IntNode, ...UtfNode[], AnnotationNode, ClassDescNode]> {
|
|
180
180
|
type: "proxy-class-desc-info"
|
|
181
181
|
}
|
|
182
|
+
export interface AnnotationNode extends BaseNode<[ContentsNode, TC_ENDBLOCKDATA_Node]> {
|
|
183
|
+
type: "annotation"
|
|
184
|
+
}
|
|
182
185
|
|
|
186
|
+
export type StringNode = NewStringNode | PrevObjectNode;
|
|
183
187
|
|
|
184
188
|
// ========== Fields & Values ==========
|
|
185
189
|
|
|
186
|
-
export
|
|
187
|
-
|
|
188
|
-
interface BaseClassDataNode<C extends BaseNode<any>[] | null> extends BaseNode<C> {
|
|
189
|
-
type: "class-data"
|
|
190
|
-
classType: string
|
|
190
|
+
export interface SerialDataNode extends BaseNode<SerialClassDataNode[]> {
|
|
191
|
+
type: "serial-data"
|
|
191
192
|
}
|
|
192
|
-
export
|
|
193
|
-
|
|
193
|
+
export type SerialClassDataNode = NoWrClassNode | WrClassNode;
|
|
194
|
+
export interface NoWrClassNode extends BaseNode<
|
|
195
|
+
// Compliant signature is [ValuesNode],
|
|
196
|
+
// but read methods can ignore this constraint
|
|
197
|
+
[ContentsNode, ...([ValuesNode]|[])]
|
|
198
|
+
> {
|
|
199
|
+
type: "class-data"
|
|
194
200
|
writeMethod: false
|
|
195
201
|
}
|
|
196
|
-
export interface WrClassNode extends
|
|
197
|
-
[ValuesNode,
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
// Why? Because fuck you that's why.
|
|
201
|
-
[ContentsNode, ValuesNode, ContentsNode] |
|
|
202
|
-
[ContentsNode, ValuesNode] |
|
|
203
|
-
[ContentsNode]
|
|
202
|
+
export interface WrClassNode extends BaseNode<
|
|
203
|
+
// Compliant signature is [ValuesNode, AnnotationNode],
|
|
204
|
+
// but read methods can ignore this constraint
|
|
205
|
+
[...([ContentsNode, ValuesNode]|[]), AnnotationNode]
|
|
204
206
|
> {
|
|
205
|
-
|
|
207
|
+
type: "class-data"
|
|
206
208
|
writeMethod: true
|
|
207
209
|
}
|
|
208
|
-
export
|
|
209
|
-
|
|
210
|
+
export type ExternalDataNode = ExternalClassDataNode | OldExternalClassDataNode;
|
|
211
|
+
export interface ExternalClassDataNode extends BaseNode<[AnnotationNode]> {
|
|
212
|
+
type: "external-data"
|
|
210
213
|
protocolVersion: 2
|
|
211
214
|
}
|
|
212
|
-
export interface
|
|
213
|
-
|
|
215
|
+
export interface OldExternalClassDataNode extends BaseNode<(ObjectNode | PrimitiveNode | UtfNode)[]> {
|
|
216
|
+
type: "external-data"
|
|
214
217
|
protocolVersion: 1
|
|
215
218
|
}
|
|
216
219
|
|
|
@@ -226,7 +229,7 @@ export interface PrimitiveDescNode extends BaseNode<[UnsignedByteNode, UtfNode]>
|
|
|
226
229
|
type: "field-desc"
|
|
227
230
|
fieldType: "primitive"
|
|
228
231
|
}
|
|
229
|
-
export interface ObjectDescNode extends BaseNode<[UnsignedByteNode, UtfNode,
|
|
232
|
+
export interface ObjectDescNode extends BaseNode<[UnsignedByteNode, UtfNode, StringNode]> {
|
|
230
233
|
type: "field-desc"
|
|
231
234
|
fieldType: "object"
|
|
232
235
|
}
|
|
@@ -239,7 +242,7 @@ interface BaseTCNode extends BaseNode<null> {
|
|
|
239
242
|
value: number
|
|
240
243
|
}
|
|
241
244
|
|
|
242
|
-
type TCNode = TC_NULL_Node | TC_REFERENCE_Node | TC_CLASSDESC_Node | TC_OBJECT_Node | TC_STRING_Node | TC_ARRAY_Node | TC_CLASS_Node | TC_BLOCKDATA_Node | TC_ENDBLOCKDATA_Node | TC_RESET_Node | TC_BLOCKDATALONG_Node | TC_EXCEPTION_Node | TC_LONGSTRING_Node | TC_PROXYCLASSDESC_Node | TC_ENUM_Node
|
|
245
|
+
export type TCNode = TC_NULL_Node | TC_REFERENCE_Node | TC_CLASSDESC_Node | TC_OBJECT_Node | TC_STRING_Node | TC_ARRAY_Node | TC_CLASS_Node | TC_BLOCKDATA_Node | TC_ENDBLOCKDATA_Node | TC_RESET_Node | TC_BLOCKDATALONG_Node | TC_EXCEPTION_Node | TC_LONGSTRING_Node | TC_PROXYCLASSDESC_Node | TC_ENUM_Node
|
|
243
246
|
|
|
244
247
|
export type TC_NULL_Node = BaseTCNode & {value: typeof ObjectInputStream.TC_NULL}
|
|
245
248
|
export type TC_REFERENCE_Node = BaseTCNode & {value: typeof ObjectInputStream.TC_REFERENCE}
|
package/src/index.ts
CHANGED