depyo 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +97 -0
- package/depyo.js +213 -0
- package/lib/BinaryReader.js +153 -0
- package/lib/OpCode.js +90 -0
- package/lib/OpCodes.js +940 -0
- package/lib/PycDecompiler.js +2031 -0
- package/lib/PycDisassembler.js +55 -0
- package/lib/PycReader.js +905 -0
- package/lib/PycResult.js +82 -0
- package/lib/PythonObject.js +242 -0
- package/lib/Unpickle.js +173 -0
- package/lib/ast/ast_node.js +3442 -0
- package/lib/bytecode/python_1_0.js +116 -0
- package/lib/bytecode/python_1_1.js +116 -0
- package/lib/bytecode/python_1_3.js +119 -0
- package/lib/bytecode/python_1_4.js +121 -0
- package/lib/bytecode/python_1_5.js +120 -0
- package/lib/bytecode/python_1_6.js +124 -0
- package/lib/bytecode/python_2_0.js +137 -0
- package/lib/bytecode/python_2_1.js +142 -0
- package/lib/bytecode/python_2_2.js +147 -0
- package/lib/bytecode/python_2_3.js +145 -0
- package/lib/bytecode/python_2_4.js +147 -0
- package/lib/bytecode/python_2_5.js +147 -0
- package/lib/bytecode/python_2_6.js +147 -0
- package/lib/bytecode/python_2_7.js +151 -0
- package/lib/bytecode/python_3_0.js +132 -0
- package/lib/bytecode/python_3_1.js +135 -0
- package/lib/bytecode/python_3_10.js +312 -0
- package/lib/bytecode/python_3_11.js +284 -0
- package/lib/bytecode/python_3_12.js +327 -0
- package/lib/bytecode/python_3_13.js +173 -0
- package/lib/bytecode/python_3_14.js +177 -0
- package/lib/bytecode/python_3_2.js +136 -0
- package/lib/bytecode/python_3_3.js +136 -0
- package/lib/bytecode/python_3_4.js +137 -0
- package/lib/bytecode/python_3_5.js +149 -0
- package/lib/bytecode/python_3_6.js +153 -0
- package/lib/bytecode/python_3_7.js +292 -0
- package/lib/bytecode/python_3_8.js +294 -0
- package/lib/bytecode/python_3_9.js +296 -0
- package/lib/code_reader.js +146 -0
- package/lib/handlers/binary_ops.js +174 -0
- package/lib/handlers/collections_update.js +239 -0
- package/lib/handlers/comparisons.js +95 -0
- package/lib/handlers/context_managers.js +250 -0
- package/lib/handlers/control_flow_jumps.js +954 -0
- package/lib/handlers/exceptions_blocks.js +952 -0
- package/lib/handlers/formatting.js +31 -0
- package/lib/handlers/function_calls.js +496 -0
- package/lib/handlers/function_class_build.js +330 -0
- package/lib/handlers/generators_async.js +172 -0
- package/lib/handlers/imports.js +53 -0
- package/lib/handlers/load_store_names.js +711 -0
- package/lib/handlers/loop_iterator.js +318 -0
- package/lib/handlers/misc_other.js +1201 -0
- package/lib/handlers/pattern_matching.js +226 -0
- package/lib/handlers/stack_ops.js +280 -0
- package/lib/handlers/subscript_slice.js +394 -0
- package/lib/handlers/unary_ops.js +91 -0
- package/lib/handlers/unpack.js +141 -0
- package/lib/stack_history.js +63 -0
- package/lib/zip_reader.js +217 -0
- package/package.json +35 -0
package/lib/PycReader.js
ADDED
|
@@ -0,0 +1,905 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const {BinaryReader} = require('./BinaryReader');
|
|
3
|
+
const {PythonObject, PythonCodeObject} = require('./PythonObject');
|
|
4
|
+
|
|
5
|
+
const PyLong_MARSHAL_SHIFT = 15;
|
|
6
|
+
const PyLong_MARSHAL_RATIO = 30 / PyLong_MARSHAL_SHIFT;
|
|
7
|
+
const PyLong_MARSHAL_BASE = 0x8000;
|
|
8
|
+
const PyLong_MARSHAL_MASK = 0x7FFF;
|
|
9
|
+
|
|
10
|
+
const TypeNull = '0';
|
|
11
|
+
const TypeNone = 'N';
|
|
12
|
+
const TypeFalse = 'F';
|
|
13
|
+
const TypeTrue = 'T';
|
|
14
|
+
const TypeStopiter = 'S';
|
|
15
|
+
const TypeEllipsis = '.';
|
|
16
|
+
const TypeInt = 'i';
|
|
17
|
+
const TypeInt64 = 'I';
|
|
18
|
+
const TypeFloat = 'f';
|
|
19
|
+
const TypeBinaryFloat = 'g';
|
|
20
|
+
const TypeComplex = 'x';
|
|
21
|
+
const TypeBinaryComplex = 'y';
|
|
22
|
+
const TypeLong = 'l';
|
|
23
|
+
const TypeString = 's';
|
|
24
|
+
const TypeInterned = 't';
|
|
25
|
+
const TypeStringRef = 'R';
|
|
26
|
+
const TypeTuple = '(';
|
|
27
|
+
const TypeList = '[';
|
|
28
|
+
const TypeDict = '{';
|
|
29
|
+
const TypeCode = 'c';
|
|
30
|
+
const TypeCode2 = 'C';
|
|
31
|
+
const TypeUnicode = 'u';
|
|
32
|
+
const TypeUnknown = '?';
|
|
33
|
+
const TypeSet = '<';
|
|
34
|
+
const TypeFrozenset = '>';
|
|
35
|
+
const TypeAscii = 'a';
|
|
36
|
+
const TypeAsciiInterned = 'A';
|
|
37
|
+
const TypeSmallTuple = ')';
|
|
38
|
+
const TypeShortAscii = 'z';
|
|
39
|
+
const TypeShortAsciiInterned = 'Z';
|
|
40
|
+
const TypeObjectReference = 'r';
|
|
41
|
+
const KnownTypes = new Set([
|
|
42
|
+
TypeNull, TypeNone, TypeFalse, TypeTrue, TypeStopiter, TypeEllipsis,
|
|
43
|
+
TypeInt, TypeInt64, TypeFloat, TypeBinaryFloat, TypeComplex, TypeBinaryComplex,
|
|
44
|
+
TypeLong, TypeString, TypeInterned, TypeStringRef, TypeTuple, TypeList,
|
|
45
|
+
TypeDict, TypeCode, TypeCode2, TypeUnicode, TypeUnknown, TypeSet, TypeFrozenset,
|
|
46
|
+
TypeAscii, TypeAsciiInterned, TypeSmallTuple, TypeShortAscii, TypeShortAsciiInterned,
|
|
47
|
+
TypeObjectReference
|
|
48
|
+
]);
|
|
49
|
+
|
|
50
|
+
const MagicToVersion = {
|
|
51
|
+
0x00999902: {major: 1, minor: 0, IsUnicode: false, opcode: require('./bytecode/python_1_0')},
|
|
52
|
+
0x00999903: {major: 1, minor: 1, IsUnicode: false, opcode: require('./bytecode/python_1_1')}, /* Also covers 1.2 */
|
|
53
|
+
0x0A0D2E89: {major: 1, minor: 3, IsUnicode: false, opcode: require('./bytecode/python_1_3')},
|
|
54
|
+
0x0A0D1704: {major: 1, minor: 4, IsUnicode: false, opcode: require('./bytecode/python_1_4')},
|
|
55
|
+
0x0A0D4E99: {major: 1, minor: 5, IsUnicode: false, opcode: require('./bytecode/python_1_5')},
|
|
56
|
+
|
|
57
|
+
0x0A0DC4FC: {major: 1, minor: 6, IsUnicode: false, opcode: require('./bytecode/python_1_6')},
|
|
58
|
+
0x0A0DC4FD: {major: 1, minor: 6, IsUnicode: true, opcode: require('./bytecode/python_1_6')},
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
0x0A0DC687: {major: 2, minor: 0, IsUnicode: false, opcode: require('./bytecode/python_2_0')},
|
|
62
|
+
0x0A0DC688: {major: 2, minor: 0, IsUnicode: true, opcode: require('./bytecode/python_2_0')},
|
|
63
|
+
|
|
64
|
+
0x0A0DEB2A: {major: 2, minor: 1, IsUnicode: false, opcode: require('./bytecode/python_2_1')},
|
|
65
|
+
0x0A0DEB2B: {major: 2, minor: 1, IsUnicode: true, opcode: require('./bytecode/python_2_1')},
|
|
66
|
+
|
|
67
|
+
0x0A0DED2D: {major: 2, minor: 2, IsUnicode: false, opcode: require('./bytecode/python_2_2')},
|
|
68
|
+
0x0A0DED2E: {major: 2, minor: 2, IsUnicode: true, opcode: require('./bytecode/python_2_2')},
|
|
69
|
+
|
|
70
|
+
0x0A0DF23B: {major: 2, minor: 3, IsUnicode: false, opcode: require('./bytecode/python_2_3')},
|
|
71
|
+
0x0A0DF23C: {major: 2, minor: 3, IsUnicode: true, opcode: require('./bytecode/python_2_3')},
|
|
72
|
+
|
|
73
|
+
0x0A0DF26D: {major: 2, minor: 4, IsUnicode: false, opcode: require('./bytecode/python_2_4')},
|
|
74
|
+
0x0A0DF26E: {major: 2, minor: 4, IsUnicode: true, opcode: require('./bytecode/python_2_4')},
|
|
75
|
+
|
|
76
|
+
0x0A0DF2B3: {major: 2, minor: 5, IsUnicode: false, opcode: require('./bytecode/python_2_5')},
|
|
77
|
+
0x0A0DF2B4: {major: 2, minor: 5, IsUnicode: true, opcode: require('./bytecode/python_2_5')},
|
|
78
|
+
|
|
79
|
+
0x0A0DF2D1: {major: 2, minor: 6, IsUnicode: false, opcode: require('./bytecode/python_2_6')},
|
|
80
|
+
0x0A0DF2D2: {major: 2, minor: 6, IsUnicode: true, opcode: require('./bytecode/python_2_6')},
|
|
81
|
+
|
|
82
|
+
0x0A0DF303: {major: 2, minor: 7, IsUnicode: false, opcode: require('./bytecode/python_2_7')},
|
|
83
|
+
0x0A0DF304: {major: 2, minor: 7, IsUnicode: true, opcode: require('./bytecode/python_2_7')},
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
0x0A0D0C3A: {major: 3, minor: 0, IsUnicode: true, opcode: require('./bytecode/python_3_0')},
|
|
87
|
+
0x0A0D0C4E: {major: 3, minor: 1, IsUnicode: true, opcode: require('./bytecode/python_3_1')},
|
|
88
|
+
0x0A0D0C6C: {major: 3, minor: 2, IsUnicode: true, opcode: require('./bytecode/python_3_2')},
|
|
89
|
+
0x0A0D0C9E: {major: 3, minor: 3, IsUnicode: true, opcode: require('./bytecode/python_3_3')},
|
|
90
|
+
0x0A0D0CEE: {major: 3, minor: 4, IsUnicode: true, opcode: require('./bytecode/python_3_4')},
|
|
91
|
+
0x0A0D0D16: {major: 3, minor: 5, IsUnicode: true, opcode: require('./bytecode/python_3_5')},
|
|
92
|
+
0x0A0D0D17: {major: 3, minor: 5, revision: 3, IsUnicode: true, opcode: require('./bytecode/python_3_5')},
|
|
93
|
+
0x0A0D0D33: {major: 3, minor: 6, IsUnicode: true, opcode: require('./bytecode/python_3_6')},
|
|
94
|
+
0x0A0D0D41: {major: 3, minor: 7, IsUnicode: true, opcode: require('./bytecode/python_3_7')},
|
|
95
|
+
0x0A0D0D42: {major: 3, minor: 7, IsUnicode: true, opcode: require('./bytecode/python_3_7')},
|
|
96
|
+
0x0A0D0D49: {major: 3, minor: 8, IsUnicode: true, opcode: require('./bytecode/python_3_8')},
|
|
97
|
+
0x0A0D0D55: {major: 3, minor: 8, IsUnicode: true, opcode: require('./bytecode/python_3_8')},
|
|
98
|
+
0x0A0D0D61: {major: 3, minor: 9, IsUnicode: true, opcode: require('./bytecode/python_3_9')},
|
|
99
|
+
0x0A0D0D6F: {major: 3, minor: 10, IsUnicode: true, opcode: require('./bytecode/python_3_10')},
|
|
100
|
+
0x0A0D0DA7: {major: 3, minor: 11, IsUnicode: true, opcode: require('./bytecode/python_3_11')},
|
|
101
|
+
0x0A0D0DCB: {major: 3, minor: 12, IsUnicode: true, opcode: require('./bytecode/python_3_12')},
|
|
102
|
+
0x0A0D0DF3: {major: 3, minor: 13, IsUnicode: true, opcode: require('./bytecode/python_3_13')},
|
|
103
|
+
0x0A0D0E2B: {major: 3, minor: 14, IsUnicode: true, opcode: require('./bytecode/python_3_14')}
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
class PycReader
|
|
108
|
+
{
|
|
109
|
+
static LoadError = class extends Error {
|
|
110
|
+
|
|
111
|
+
FileName = null;
|
|
112
|
+
position = -1;
|
|
113
|
+
constructor (msg, filename, pc) {
|
|
114
|
+
super(msg);
|
|
115
|
+
this.FileName = filename;
|
|
116
|
+
this.position = pc;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
Strings = [];
|
|
121
|
+
Objects = [];
|
|
122
|
+
m_rdr = null;
|
|
123
|
+
m_filename = null;
|
|
124
|
+
m_version = null;
|
|
125
|
+
|
|
126
|
+
constructor(data) {
|
|
127
|
+
if (!data) {
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
let buffer = data;
|
|
132
|
+
if (typeof(data) == 'string') {
|
|
133
|
+
buffer = fs.readFileSync(data);
|
|
134
|
+
} else if (!Buffer.isBuffer(buffer)) {
|
|
135
|
+
throw new Error('PycReader accepts only String as a file path or Buffer as content.');
|
|
136
|
+
}
|
|
137
|
+
this.m_rdr = new BinaryReader(buffer);
|
|
138
|
+
|
|
139
|
+
let marshalVersion = this.m_rdr.readUInt32();
|
|
140
|
+
this.m_version = MagicToVersion[marshalVersion] || MagicToVersion[marshalVersion & 0xFFFFFFFE] || {major: -1, minor: -1, IsUnicode: false};
|
|
141
|
+
|
|
142
|
+
// Fallback: pick nearest known magic if opcode table is missing (helps PyPy forks)
|
|
143
|
+
if (!this.m_version.opcode) {
|
|
144
|
+
let nearest = null, bestDiff = Number.MAX_SAFE_INTEGER;
|
|
145
|
+
for (const [magic, info] of Object.entries(MagicToVersion)) {
|
|
146
|
+
const diff = Math.abs(parseInt(magic) - marshalVersion);
|
|
147
|
+
if (diff < bestDiff) {
|
|
148
|
+
bestDiff = diff;
|
|
149
|
+
nearest = info;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
if (nearest && bestDiff <= 0x1000) {
|
|
153
|
+
this.m_version = nearest;
|
|
154
|
+
if (global.g_cliArgs?.debug) {
|
|
155
|
+
console.warn(`Using nearest magic match (diff=0x${bestDiff.toString(16)}) -> Python ${nearest.major}.${nearest.minor}`);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
let flags = 0;
|
|
161
|
+
let timeStamp = 0;
|
|
162
|
+
let size = 0;
|
|
163
|
+
|
|
164
|
+
if (this.versionCompare(3, 7) >= 0) {
|
|
165
|
+
flags = this.m_rdr.readUInt32();
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
if (flags & 1) {
|
|
169
|
+
this.m_rdr.readUInt32()
|
|
170
|
+
this.m_rdr.readUInt32()
|
|
171
|
+
} else {
|
|
172
|
+
timeStamp = this.m_rdr.readUInt32();
|
|
173
|
+
|
|
174
|
+
if (this.versionCompare(3, 3) >= 0) {
|
|
175
|
+
size = this.m_rdr.readUInt32();
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
if (global.g_cliArgs.debug) {
|
|
180
|
+
console.log(`Python version: ${this.m_version.major}.${this.m_version.minor}`);
|
|
181
|
+
console.log(`timestamp: ${new Date(timeStamp * 1000)}`);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
get Reader() {
|
|
186
|
+
return this.m_rdr.Reader;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
get OpCodes() {
|
|
190
|
+
return this.m_version.opcode;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
ReadObject() {
|
|
194
|
+
try {
|
|
195
|
+
let obj = new PythonObject(), value = null;
|
|
196
|
+
let charCode = this.m_rdr.readChar().charCodeAt(0);
|
|
197
|
+
let objectType = String.fromCharCode(charCode & 0x7f);
|
|
198
|
+
let isInterned = false;
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
if ((charCode & 0x80) == 0x80) {
|
|
202
|
+
this.Objects.push(obj);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
switch (objectType) {
|
|
206
|
+
case TypeObjectReference:
|
|
207
|
+
let objectIndex = this.m_rdr.readInt32();
|
|
208
|
+
if (objectIndex >= this.Objects.length) {
|
|
209
|
+
throw new LoadError("Referense is outside of the boundaries", this.m_filename, this.m_rdr.pc);
|
|
210
|
+
}
|
|
211
|
+
return this.Objects[objectIndex];
|
|
212
|
+
case TypeNull:
|
|
213
|
+
obj.ClassName = "Py_Null";
|
|
214
|
+
break;
|
|
215
|
+
case TypeNone:
|
|
216
|
+
obj.ClassName = "Py_None";
|
|
217
|
+
break;
|
|
218
|
+
case TypeStopiter:
|
|
219
|
+
obj.ClassName = "Py_StopIteration";
|
|
220
|
+
break;
|
|
221
|
+
case TypeEllipsis:
|
|
222
|
+
obj.ClassName = "Py_Ellipsis";
|
|
223
|
+
break;
|
|
224
|
+
case TypeFalse:
|
|
225
|
+
obj.ClassName = "Py_False";
|
|
226
|
+
break;
|
|
227
|
+
case TypeTrue:
|
|
228
|
+
obj.ClassName = "Py_True";
|
|
229
|
+
break;
|
|
230
|
+
case TypeInt:
|
|
231
|
+
obj.ClassName = "Py_Int";
|
|
232
|
+
obj.Value = this.m_rdr.readInt32();
|
|
233
|
+
break;
|
|
234
|
+
case TypeInt64:
|
|
235
|
+
obj.ClassName = "Py_VeryLong";
|
|
236
|
+
obj.Value = this.m_rdr.readBytes(8);
|
|
237
|
+
break;
|
|
238
|
+
case TypeLong:
|
|
239
|
+
let longValue = [];
|
|
240
|
+
let d = 0;
|
|
241
|
+
let n = this.m_rdr.readInt32();
|
|
242
|
+
if (n == 0) {
|
|
243
|
+
obj.ClassName = "Py_Long";
|
|
244
|
+
obj.Value = 0;
|
|
245
|
+
break;
|
|
246
|
+
}
|
|
247
|
+
let size = 1 + (Math.abs(n) - 1) / PyLong_MARSHAL_RATIO;
|
|
248
|
+
let shorts_in_top_digit = 1 + (Math.abs(n) - 1) % PyLong_MARSHAL_RATIO;
|
|
249
|
+
|
|
250
|
+
for (let idx = 0; idx < size - 1; idx++) {
|
|
251
|
+
d = 0;
|
|
252
|
+
for (let j = 0; j < PyLong_MARSHAL_RATIO; j++) {
|
|
253
|
+
let md = this.m_rdr.readInt16();
|
|
254
|
+
if (md < 0 || md > PyLong_MARSHAL_BASE) {
|
|
255
|
+
throw new Error("cannot demarshal a long data");
|
|
256
|
+
}
|
|
257
|
+
d += md << (j * PyLong_MARSHAL_SHIFT);
|
|
258
|
+
}
|
|
259
|
+
longValue.push(d);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
d = 0;
|
|
263
|
+
for (let j = 0; j < shorts_in_top_digit; j++) {
|
|
264
|
+
let md = this.m_rdr.readInt16();
|
|
265
|
+
if (md < 0 || md > PyLong_MARSHAL_BASE) {
|
|
266
|
+
throw new Error("cannot demarshal a long data");
|
|
267
|
+
}
|
|
268
|
+
d += md << (j * PyLong_MARSHAL_SHIFT);
|
|
269
|
+
}
|
|
270
|
+
longValue.push(d);
|
|
271
|
+
|
|
272
|
+
obj.ClassName = "Py_VeryLong";
|
|
273
|
+
obj.Value = longValue;
|
|
274
|
+
break;
|
|
275
|
+
case TypeFloat:
|
|
276
|
+
obj.ClassName = "Py_Float";
|
|
277
|
+
obj.Value = parseFloat(this.ReadString());
|
|
278
|
+
break;
|
|
279
|
+
case TypeBinaryFloat:
|
|
280
|
+
obj.ClassName = "Py_Float";
|
|
281
|
+
obj.Value = this.m_rdr.readDouble();
|
|
282
|
+
break;
|
|
283
|
+
case TypeComplex:
|
|
284
|
+
obj.ClassName = "Py_Complex";
|
|
285
|
+
obj.Value = [parseFloat(this.ReadString()), parseFloat(this.ReadString())];
|
|
286
|
+
break;
|
|
287
|
+
case TypeBinaryComplex:
|
|
288
|
+
obj.ClassName = "Py_Complex";
|
|
289
|
+
obj.Value = [this.m_rdr.readDouble(), this.m_rdr.readDouble()];
|
|
290
|
+
break;
|
|
291
|
+
case TypeInterned:
|
|
292
|
+
isInterned = true;
|
|
293
|
+
case TypeString:
|
|
294
|
+
value = this.m_rdr.readBytes(this.m_rdr.readUInt32()); // .toString("ascii");
|
|
295
|
+
obj.ClassName = "Py_String";
|
|
296
|
+
obj.Value = value;
|
|
297
|
+
if (isInterned) {
|
|
298
|
+
this.Strings.push(value);
|
|
299
|
+
}
|
|
300
|
+
break;
|
|
301
|
+
case TypeUnicode:
|
|
302
|
+
value = this.ReadString(this.m_rdr.readUInt32());
|
|
303
|
+
obj.ClassName = "Py_Unicode";
|
|
304
|
+
obj.Value = value;
|
|
305
|
+
break;
|
|
306
|
+
case TypeStringRef:
|
|
307
|
+
let listPos = this.m_rdr.readUInt32();
|
|
308
|
+
obj.ClassName = "Py_String";
|
|
309
|
+
obj.Value = (listPos < this.Strings.length ? this.Strings[listPos] : null);
|
|
310
|
+
break;
|
|
311
|
+
case TypeAsciiInterned:
|
|
312
|
+
case TypeShortAsciiInterned:
|
|
313
|
+
isInterned = true;
|
|
314
|
+
case TypeAscii:
|
|
315
|
+
case TypeShortAscii:
|
|
316
|
+
let ascii = this.m_rdr.readBytes([TypeAscii, TypeAsciiInterned].includes(objectType) ? this.m_rdr.readUInt32() : this.m_rdr.readByte()).toString("ascii");
|
|
317
|
+
obj.ClassName = "Py_String";
|
|
318
|
+
obj.Value = ascii;
|
|
319
|
+
if (isInterned) {
|
|
320
|
+
this.Strings.push(ascii);
|
|
321
|
+
}
|
|
322
|
+
break;
|
|
323
|
+
case TypeSmallTuple:
|
|
324
|
+
case TypeTuple:
|
|
325
|
+
let nTuples = objectType == TypeTuple ? this.m_rdr.readUInt32() : this.m_rdr.readByte();
|
|
326
|
+
let tuples = [];
|
|
327
|
+
for (let currentIndex = 0; currentIndex < nTuples; currentIndex++) {
|
|
328
|
+
tuples.push(this.ReadObject());
|
|
329
|
+
}
|
|
330
|
+
obj.ClassName = "Py_Tuple";
|
|
331
|
+
obj.Value = tuples;
|
|
332
|
+
break;
|
|
333
|
+
case TypeList:
|
|
334
|
+
let nListElements = this.m_rdr.readUInt32();
|
|
335
|
+
let list = [];
|
|
336
|
+
for (let currentIndex = 0; currentIndex < nListElements; currentIndex++) {
|
|
337
|
+
list.push(this.ReadObject());
|
|
338
|
+
}
|
|
339
|
+
obj.ClassName = "Py_List";
|
|
340
|
+
obj.Value = list;
|
|
341
|
+
break;
|
|
342
|
+
case TypeDict:
|
|
343
|
+
let dict = [];
|
|
344
|
+
while(true)
|
|
345
|
+
{
|
|
346
|
+
let key = this.ReadObject();
|
|
347
|
+
if (key.ClassName == "Py_Null")
|
|
348
|
+
break;
|
|
349
|
+
let dictValue = this.ReadObject();
|
|
350
|
+
dict.push({key, value: dictValue});
|
|
351
|
+
}
|
|
352
|
+
obj.ClassName = "Py_Dict";
|
|
353
|
+
obj.Value = dict;
|
|
354
|
+
break;
|
|
355
|
+
case TypeSet:
|
|
356
|
+
let nSetElements = this.m_rdr.readUInt32();
|
|
357
|
+
let set = [];
|
|
358
|
+
for (let currentIndex = 0; currentIndex < nSetElements; currentIndex++)
|
|
359
|
+
{
|
|
360
|
+
set.push(this.ReadObject());
|
|
361
|
+
}
|
|
362
|
+
obj.ClassName = "Py_Set";
|
|
363
|
+
obj.Value = set;
|
|
364
|
+
break;
|
|
365
|
+
case TypeFrozenset:
|
|
366
|
+
let nFSetElements = this.m_rdr.readUInt32();
|
|
367
|
+
let frozenSet = [];
|
|
368
|
+
for (let currentIndex = 0; currentIndex < nFSetElements; currentIndex++)
|
|
369
|
+
{
|
|
370
|
+
frozenSet.push(this.ReadObject());
|
|
371
|
+
}
|
|
372
|
+
obj.ClassName = "Py_FrozenSet";
|
|
373
|
+
obj.Value = frozenSet;
|
|
374
|
+
break;
|
|
375
|
+
case TypeCode:
|
|
376
|
+
case TypeCode2:
|
|
377
|
+
let codeObj = this.ReadCodeObject();
|
|
378
|
+
for (let prop of Object.keys(codeObj)) {
|
|
379
|
+
if (Object.hasOwn(codeObj, prop)) {
|
|
380
|
+
obj[prop] = codeObj[prop];
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
Object.setPrototypeOf(obj, Object.getPrototypeOf(codeObj));
|
|
384
|
+
break;
|
|
385
|
+
default:
|
|
386
|
+
if (charCode === 0) {
|
|
387
|
+
obj.ClassName = "Py_Null";
|
|
388
|
+
break;
|
|
389
|
+
}
|
|
390
|
+
throw new PycReader.LoadError(`Don't know how to handle object Type ${objectType}'`, this.m_filename, this.m_rdr.pc);
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
obj.Reader = this;
|
|
394
|
+
|
|
395
|
+
return obj;
|
|
396
|
+
} catch(ex) {
|
|
397
|
+
throw ex;
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
static ConvertBytesToString(bytes) {
|
|
402
|
+
return Buffer.from(bytes).toString("utf8");
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
ReadString(size) {
|
|
406
|
+
if (size === undefined) {
|
|
407
|
+
size = this.m_rdr.readByte();
|
|
408
|
+
}
|
|
409
|
+
if (!size) {
|
|
410
|
+
return "";
|
|
411
|
+
}
|
|
412
|
+
return this.m_rdr.readString(size);
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
ReadCodeObject() {
|
|
416
|
+
let codeObject = new PythonCodeObject();
|
|
417
|
+
|
|
418
|
+
const isNewCodeLayout = this.versionCompare(3, 11) >= 0;
|
|
419
|
+
|
|
420
|
+
let argCount = 0;
|
|
421
|
+
|
|
422
|
+
if (this.versionCompare(1, 3) >= 0 && this.versionCompare(2, 3) < 0) {
|
|
423
|
+
argCount = this.m_rdr.readUInt16();
|
|
424
|
+
} else if (this.versionCompare(2, 3) >= 0) {
|
|
425
|
+
argCount = this.m_rdr.readUInt32();
|
|
426
|
+
}
|
|
427
|
+
codeObject.ArgCount = argCount;
|
|
428
|
+
|
|
429
|
+
codeObject.PosOnlyArgCount = this.versionCompare(3, 8) >= 0 ? this.m_rdr.readUInt32() : 0;
|
|
430
|
+
codeObject.KWOnlyArgCount = this.versionCompare(3, 0) >= 0 ? this.m_rdr.readUInt32() : 0;
|
|
431
|
+
|
|
432
|
+
codeObject.NumLocals = 0;
|
|
433
|
+
if (this.versionCompare(1, 3) >= 0 && this.versionCompare(2, 3) < 0) {
|
|
434
|
+
codeObject.NumLocals = this.m_rdr.readUInt16();
|
|
435
|
+
} else if (this.versionCompare(2, 3) >= 0 && !isNewCodeLayout) {
|
|
436
|
+
codeObject.NumLocals = this.m_rdr.readUInt32();
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
codeObject.StackSize = 0;
|
|
440
|
+
if (this.versionCompare(1, 5) >= 0 && this.versionCompare(2, 3) < 0) {
|
|
441
|
+
codeObject.StackSize = this.m_rdr.readUInt16();
|
|
442
|
+
} else if (this.versionCompare(2, 3) >= 0) {
|
|
443
|
+
codeObject.StackSize = this.m_rdr.readUInt32();
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
codeObject.Flags = 0;
|
|
447
|
+
if (this.versionCompare(1, 3) >= 0 && this.versionCompare(2, 3) < 0) {
|
|
448
|
+
codeObject.Flags = this.m_rdr.readUInt16();
|
|
449
|
+
} else if (this.versionCompare(2, 3) >= 0) {
|
|
450
|
+
codeObject.Flags = this.m_rdr.readUInt32();
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
// Some fixtures carry malformed code objects (e.g., flags bytes are missing),
|
|
454
|
+
// which misaligns the marshal stream and makes us read code bytes as an unknown type.
|
|
455
|
+
// Heuristic: if the next byte is not a known marshal type but the previous 4th byte is,
|
|
456
|
+
// rewind by 4 bytes (assume flags were absent) so code/consts parsing can proceed.
|
|
457
|
+
const nextType = this.m_rdr.Reader?.[this.m_rdr.pc];
|
|
458
|
+
const prevType = this.m_rdr.pc >= 4 ? this.m_rdr.Reader?.[this.m_rdr.pc - 4] : null;
|
|
459
|
+
if (nextType !== undefined &&
|
|
460
|
+
!KnownTypes.has(String.fromCharCode(nextType & 0x7f)) &&
|
|
461
|
+
prevType !== undefined &&
|
|
462
|
+
KnownTypes.has(String.fromCharCode(prevType & 0x7f))) {
|
|
463
|
+
if (global.g_cliArgs?.debug) {
|
|
464
|
+
console.warn(`[ReadCodeObject] Realigning code object start: rewind 4 bytes (suspect missing flags). pc=${this.m_rdr.pc}`);
|
|
465
|
+
}
|
|
466
|
+
this.m_rdr.pc -= 4;
|
|
467
|
+
codeObject.FlagsMisaligned = true;
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
codeObject.codeOffset = this.m_rdr.pc;
|
|
471
|
+
codeObject.Code = this.ReadObject();
|
|
472
|
+
codeObject.Consts = this.ReadObject();
|
|
473
|
+
|
|
474
|
+
if (global.g_cliArgs?.debug && this.versionCompare(3, 13) >= 0) {
|
|
475
|
+
console.log(`[ReadCodeObject] name=${codeObject.Name || '?'}, Consts.ClassName=${codeObject.Consts?.ClassName}, Consts.length=${codeObject.Consts?.Value?.length}`);
|
|
476
|
+
if (codeObject.Consts?.Value) {
|
|
477
|
+
for (let i = 0; i < Math.min(3, codeObject.Consts.Value.length); i++) {
|
|
478
|
+
const c = codeObject.Consts.Value[i];
|
|
479
|
+
console.log(` Consts[${i}] = ${c?.ClassName || 'null/undefined'} (${typeof c})`);
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
codeObject.Names = this.ReadObject();
|
|
485
|
+
|
|
486
|
+
if (isNewCodeLayout) {
|
|
487
|
+
codeObject.LocalsPlusNames = this.ReadObject();
|
|
488
|
+
codeObject.VarKinds = this.ReadObject();
|
|
489
|
+
const {locals, cellVars, freeVars} = this.splitLocalsPlus(codeObject.LocalsPlusNames, codeObject.VarKinds);
|
|
490
|
+
codeObject.VarNames = new PythonObject("Py_Tuple", locals);
|
|
491
|
+
codeObject.CellVars = new PythonObject("Py_Tuple", cellVars);
|
|
492
|
+
codeObject.FreeVars = new PythonObject("Py_Tuple", freeVars);
|
|
493
|
+
codeObject.NumLocals = locals.length;
|
|
494
|
+
} else {
|
|
495
|
+
codeObject.VarNames = this.versionCompare(1, 3) >= 0 ? this.ReadObject() : new PythonObject("Py_Tuple", []);
|
|
496
|
+
codeObject.VarKinds = new PythonObject("Py_String", "");
|
|
497
|
+
codeObject.FreeVars = this.versionCompare(2, 1) >= 0 ? this.ReadObject() : new PythonObject("Py_Tuple", []);
|
|
498
|
+
codeObject.CellVars = this.versionCompare(2, 1) >= 0 ? this.ReadObject() : new PythonObject("Py_Tuple", []);
|
|
499
|
+
}
|
|
500
|
+
codeObject.FileName = this.ReadObject().toString();
|
|
501
|
+
|
|
502
|
+
if (!this.m_filename) {
|
|
503
|
+
this.m_filename = codeObject.FileName;
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
codeObject.Name = this.ReadObject().toString();
|
|
507
|
+
codeObject.QualName = this.versionCompare(3, 11) >= 0 ? this.ReadObject() : new PythonObject("Py_String", "");
|
|
508
|
+
|
|
509
|
+
codeObject.FirstLineNo = 0;
|
|
510
|
+
if (this.versionCompare(1, 5) >= 0 && this.versionCompare(2, 3) < 0) {
|
|
511
|
+
codeObject.FirstLineNo = this.m_rdr.readUInt16();
|
|
512
|
+
} else if (this.versionCompare(2, 3) >= 0) {
|
|
513
|
+
codeObject.FirstLineNo = this.m_rdr.readUInt32();
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
codeObject.Methods = {};
|
|
517
|
+
codeObject.LineNoTab = [];
|
|
518
|
+
if (this.versionCompare(1, 5) >= 0) {
|
|
519
|
+
this.UnpackLineNumbers(codeObject);
|
|
520
|
+
}
|
|
521
|
+
if (this.versionCompare(3, 11) >= 0) {
|
|
522
|
+
codeObject.exceptTable = this.ReadObject();
|
|
523
|
+
// Parse exception table into structured format
|
|
524
|
+
codeObject.ExceptionTable = this.ParseExceptionTable(codeObject.exceptTable);
|
|
525
|
+
} else {
|
|
526
|
+
codeObject.exceptTable = new PythonObject("Py_String", "");
|
|
527
|
+
codeObject.ExceptionTable = [];
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
return codeObject;
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
ParseExceptionTable(exceptTableObject) {
|
|
534
|
+
/**
|
|
535
|
+
* Parse Python 3.11+ exception table format (wordcode units, not delta encoded)
|
|
536
|
+
* Each entry: start, length, target, depth|lasti (all varints)
|
|
537
|
+
*/
|
|
538
|
+
if (!exceptTableObject || !exceptTableObject.Value || exceptTableObject.Value.length === 0) {
|
|
539
|
+
return [];
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
const data = exceptTableObject.Value;
|
|
543
|
+
const entries = [];
|
|
544
|
+
let pos = 0;
|
|
545
|
+
|
|
546
|
+
const decodeVarint = () => {
|
|
547
|
+
// Matches CPython 3.11+ _parse_varint (big-endian 6-bit chunks)
|
|
548
|
+
if (pos >= data.length) {
|
|
549
|
+
return 0;
|
|
550
|
+
}
|
|
551
|
+
let byte = data[pos++];
|
|
552
|
+
let result = byte & 0x3F;
|
|
553
|
+
while (byte & 0x40) {
|
|
554
|
+
if (pos >= data.length) break;
|
|
555
|
+
byte = data[pos++];
|
|
556
|
+
result = (result << 6) | (byte & 0x3F);
|
|
557
|
+
}
|
|
558
|
+
return result;
|
|
559
|
+
};
|
|
560
|
+
|
|
561
|
+
while (pos < data.length) {
|
|
562
|
+
const start = decodeVarint() * 2;
|
|
563
|
+
const length = decodeVarint() * 2;
|
|
564
|
+
const end = start + length;
|
|
565
|
+
const targetOffset = decodeVarint() * 2;
|
|
566
|
+
const depthLasti = decodeVarint();
|
|
567
|
+
const depth = depthLasti >> 1;
|
|
568
|
+
const lasti = depthLasti & 1;
|
|
569
|
+
|
|
570
|
+
entries.push({ start, end, target: targetOffset, depth, lasti });
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
return entries;
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
UnpackLineNumbers(codeObject) {
|
|
577
|
+
codeObject.LineNoTab = [];
|
|
578
|
+
let lineno = this.ReadObject();
|
|
579
|
+
codeObject.LineNoTabObject = lineno;
|
|
580
|
+
if (this.versionCompare(3, 11) >= 0) {
|
|
581
|
+
this.UnpackNewLineNumbers(codeObject);
|
|
582
|
+
return;
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
if (!lineno || !lineno.Value || lineno.Value.length === 0) {
|
|
586
|
+
const codeLen = codeObject.Code?.Value?.length || 0;
|
|
587
|
+
codeObject.LineNoTab = new Array(codeLen).fill(codeObject.FirstLineNo);
|
|
588
|
+
return;
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
let bytePos = 0, currentBytePos = 0;
|
|
592
|
+
let linePos = codeObject.FirstLineNo;
|
|
593
|
+
for (let idx = 0; idx < lineno.Value.length; idx += 2) {
|
|
594
|
+
bytePos += lineno.Value[idx];
|
|
595
|
+
while (currentBytePos < bytePos) {
|
|
596
|
+
codeObject.LineNoTab.push(linePos);
|
|
597
|
+
currentBytePos++;
|
|
598
|
+
}
|
|
599
|
+
linePos += lineno.Value[idx + 1];
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
while (currentBytePos < codeObject.Code.Value.length) {
|
|
603
|
+
codeObject.LineNoTab.push(linePos);
|
|
604
|
+
currentBytePos++;
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
getInstructionWordSize() {
|
|
609
|
+
return this.versionCompare(3, 6) >= 0 ? 2 : 1;
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
splitLocalsPlus(localsPlusNames, localsPlusKinds) {
|
|
613
|
+
let locals = [];
|
|
614
|
+
let cellVars = [];
|
|
615
|
+
let freeVars = [];
|
|
616
|
+
|
|
617
|
+
if (!localsPlusNames?.Value || !localsPlusKinds?.Value) {
|
|
618
|
+
return {locals, cellVars, freeVars};
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
const kindBuffer = Buffer.isBuffer(localsPlusKinds.Value)
|
|
622
|
+
? localsPlusKinds.Value
|
|
623
|
+
: Buffer.from(localsPlusKinds.Value);
|
|
624
|
+
|
|
625
|
+
for (let idx = 0; idx < localsPlusNames.Value.length; idx++) {
|
|
626
|
+
let name = localsPlusNames.Value[idx];
|
|
627
|
+
let kind = kindBuffer[idx] || 0;
|
|
628
|
+
let isLocal = (kind & 0x20) !== 0;
|
|
629
|
+
let isCell = (kind & 0x40) !== 0;
|
|
630
|
+
let isFree = (kind & 0x80) !== 0;
|
|
631
|
+
|
|
632
|
+
if (isLocal) {
|
|
633
|
+
locals.push(name);
|
|
634
|
+
}
|
|
635
|
+
if (isCell) {
|
|
636
|
+
cellVars.push(name);
|
|
637
|
+
}
|
|
638
|
+
if (isFree) {
|
|
639
|
+
freeVars.push(name);
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
return {locals, cellVars, freeVars};
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
scanVarint(buffer, offset) {
|
|
647
|
+
let idx = offset;
|
|
648
|
+
if (idx >= buffer.length) {
|
|
649
|
+
return {value: 0, next: idx};
|
|
650
|
+
}
|
|
651
|
+
let read = buffer[idx++];
|
|
652
|
+
let val = read & 0x3F;
|
|
653
|
+
let shift = 0;
|
|
654
|
+
while ((read & 0x40) && idx < buffer.length) {
|
|
655
|
+
read = buffer[idx++];
|
|
656
|
+
shift += 6;
|
|
657
|
+
val |= (read & 0x3F) << shift;
|
|
658
|
+
}
|
|
659
|
+
return {value: val, next: idx};
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
scanSignedVarint(buffer, offset) {
|
|
663
|
+
const {value, next} = this.scanVarint(buffer, offset);
|
|
664
|
+
const signed = (value & 1) ? -(value >> 1) : (value >> 1);
|
|
665
|
+
return {value: signed, next};
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
getLineDeltaFromEntry(buffer, offset) {
|
|
669
|
+
const firstByte = buffer[offset];
|
|
670
|
+
const code = (firstByte >> 3) & 0x0F;
|
|
671
|
+
switch (code) {
|
|
672
|
+
case 15: // PY_CODE_LOCATION_INFO_NONE
|
|
673
|
+
return 0;
|
|
674
|
+
case 13: // NO_COLUMNS
|
|
675
|
+
case 14: { // LONG
|
|
676
|
+
const {value} = this.scanSignedVarint(buffer, offset + 1);
|
|
677
|
+
return value;
|
|
678
|
+
}
|
|
679
|
+
case 11: // ONE_LINE1
|
|
680
|
+
return 1;
|
|
681
|
+
case 12: // ONE_LINE2
|
|
682
|
+
return 2;
|
|
683
|
+
default:
|
|
684
|
+
return 0;
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
advanceLineTableOffset(buffer, offset) {
|
|
689
|
+
let idx = offset;
|
|
690
|
+
while (idx < buffer.length && (buffer[idx] & 0x80) === 0) {
|
|
691
|
+
idx++;
|
|
692
|
+
}
|
|
693
|
+
return idx;
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
UnpackNewLineNumbers(codeObject) {
|
|
697
|
+
const lineTableObj = codeObject.LineNoTabObject;
|
|
698
|
+
const codeBytes = codeObject.Code?.Value || [];
|
|
699
|
+
const wordSize = this.getInstructionWordSize();
|
|
700
|
+
const totalLength = codeBytes.length;
|
|
701
|
+
const lineArray = new Array(totalLength).fill(codeObject.FirstLineNo);
|
|
702
|
+
|
|
703
|
+
if (!lineTableObj?.Value || !lineTableObj.Value.length) {
|
|
704
|
+
codeObject.LineNoTab = lineArray;
|
|
705
|
+
return;
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
const data = Buffer.isBuffer(lineTableObj.Value)
|
|
709
|
+
? lineTableObj.Value
|
|
710
|
+
: Buffer.from(lineTableObj.Value);
|
|
711
|
+
|
|
712
|
+
let offset = 0;
|
|
713
|
+
let computedLine = codeObject.FirstLineNo;
|
|
714
|
+
let currentStart = 0;
|
|
715
|
+
let currentEnd = 0;
|
|
716
|
+
let lastLine = codeObject.FirstLineNo;
|
|
717
|
+
|
|
718
|
+
while (offset < data.length) {
|
|
719
|
+
const firstByte = data[offset];
|
|
720
|
+
if ((firstByte & 0x80) === 0) {
|
|
721
|
+
offset++;
|
|
722
|
+
continue;
|
|
723
|
+
}
|
|
724
|
+
const lineDelta = this.getLineDeltaFromEntry(data, offset);
|
|
725
|
+
computedLine += lineDelta;
|
|
726
|
+
currentStart = currentEnd;
|
|
727
|
+
currentEnd = currentStart + (((firstByte & 0x07) + 1) * wordSize);
|
|
728
|
+
const codeLine = ((firstByte >> 3) & 0x0F) === 0x0F ? lastLine : computedLine;
|
|
729
|
+
for (let idx = currentStart; idx < currentEnd && idx < lineArray.length; idx++) {
|
|
730
|
+
lineArray[idx] = codeLine;
|
|
731
|
+
}
|
|
732
|
+
if (((firstByte >> 3) & 0x0F) !== 0x0F) {
|
|
733
|
+
lastLine = computedLine;
|
|
734
|
+
}
|
|
735
|
+
offset = this.advanceLineTableOffset(data, offset + 1);
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
codeObject.LineNoTab = lineArray;
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
static DumpObject(obj, level) {
|
|
742
|
+
let result = "";
|
|
743
|
+
level = level || 0;
|
|
744
|
+
|
|
745
|
+
for (let idx = 0; idx < level; idx++) {
|
|
746
|
+
result += " ";
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
try {
|
|
750
|
+
switch (obj.ClassName)
|
|
751
|
+
{
|
|
752
|
+
case "Py_Null":
|
|
753
|
+
result += "Py_NULL\n";
|
|
754
|
+
break;
|
|
755
|
+
case "Py_None":
|
|
756
|
+
result += "Py_None\n";
|
|
757
|
+
break;
|
|
758
|
+
case "Py_StopIteration":
|
|
759
|
+
result += `Py_StopIteration, Value = ${obj.toString()}\n`;
|
|
760
|
+
break;
|
|
761
|
+
case "Py_Ellipsis":
|
|
762
|
+
result += `Py_Ellipsis, Value = ${obj.toString()}\n`;
|
|
763
|
+
break;
|
|
764
|
+
case "Py_False":
|
|
765
|
+
result += "Py_False\n";
|
|
766
|
+
break;
|
|
767
|
+
case "Py_True":
|
|
768
|
+
result += "Py_True\n";
|
|
769
|
+
break;
|
|
770
|
+
case "Py_Int":
|
|
771
|
+
result += `Py_Int, Value = ${obj.toString()}\n`;
|
|
772
|
+
break;
|
|
773
|
+
case "Py_Long":
|
|
774
|
+
result += `Py_Long, Value = ${obj.toString()}\n`;
|
|
775
|
+
break;
|
|
776
|
+
case "Py_VeryLong":
|
|
777
|
+
result += `Py_VeryLong, Value = ${obj.toString()}\n`;
|
|
778
|
+
break;
|
|
779
|
+
case "Py_Float":
|
|
780
|
+
result += `Py_Float, Value = ${obj.toString()}\n`;
|
|
781
|
+
break;
|
|
782
|
+
case "Py_Complex":
|
|
783
|
+
result += `Py_Complex, Value = ${obj.toString()}\n`;
|
|
784
|
+
break;
|
|
785
|
+
case "Py_Unicode":
|
|
786
|
+
result += `Py_Unicode, Value = "${obj.toString()}"\n`;
|
|
787
|
+
break;
|
|
788
|
+
case "Py_String":
|
|
789
|
+
result += `Py_String, Value = "${obj.toString()}"\n`;
|
|
790
|
+
break;
|
|
791
|
+
case "Py_Tuple":
|
|
792
|
+
result += "Py_Typle:\n";
|
|
793
|
+
for (let item of obj.Value) {
|
|
794
|
+
result += PycReader.DumpObject(item, level + 1);
|
|
795
|
+
}
|
|
796
|
+
break;
|
|
797
|
+
case "Py_List":
|
|
798
|
+
result += "Py_List:\n";
|
|
799
|
+
for (let item of obj.Value) {
|
|
800
|
+
result += PycReader.DumpObject(item, level + 1);
|
|
801
|
+
}
|
|
802
|
+
break;
|
|
803
|
+
case "Py_Dict":
|
|
804
|
+
result += "Py_Dict:\n";
|
|
805
|
+
for (let pair of Object.entries(obj.Value)) {
|
|
806
|
+
result += "Dict Key:\n";
|
|
807
|
+
result += PycReader.DumpObject(pair[0], level + 1);
|
|
808
|
+
result += "Dict Value:\n";
|
|
809
|
+
result += PycReader.DumpObject(pair[1], level + 1);
|
|
810
|
+
}
|
|
811
|
+
break;
|
|
812
|
+
case "Py_Set":
|
|
813
|
+
result += "Py_Set:\n";
|
|
814
|
+
for (let item of obj.Value) {
|
|
815
|
+
result += PycReader.DumpObject(item, level + 1);
|
|
816
|
+
}
|
|
817
|
+
break;
|
|
818
|
+
case "Py_FrozenSet":
|
|
819
|
+
result += "Py_FrozenSet:\n";
|
|
820
|
+
for (let item of obj.Value) {
|
|
821
|
+
result += PycReader.DumpObject(item, level + 1);
|
|
822
|
+
}
|
|
823
|
+
break;
|
|
824
|
+
case "Py_CodeObject":
|
|
825
|
+
result += "Py_CodeObject\n";
|
|
826
|
+
let codeObject = obj;
|
|
827
|
+
if (codeObject == null)
|
|
828
|
+
break;
|
|
829
|
+
let pars = "";
|
|
830
|
+
if (codeObject.ArgCount > 0) {
|
|
831
|
+
for(let idx = 0; idx < codeObject.ArgCount; idx++) {
|
|
832
|
+
pars += pars == "" ? codeObject.VarNames.Value[idx].toString() : ", " + codeObject.VarNames.Value[idx].toString();
|
|
833
|
+
}
|
|
834
|
+
}
|
|
835
|
+
result += `Code Object: ${codeObject.Name && codeObject.Name.Value && codeObject.Name.toString()} (${pars})\n`;
|
|
836
|
+
result += `ArgCount = ${codeObject.ArgCount}\n`;
|
|
837
|
+
result += `NumLocals ${codeObject.NumLocals}\n`;
|
|
838
|
+
result += `StackSize ${codeObject.StackSize}\n`;
|
|
839
|
+
result += `Flags ${codeObject.Flags}\n`;
|
|
840
|
+
if (codeObject.Consts && codeObject.Consts.Value) {
|
|
841
|
+
result += "Consts:\n";
|
|
842
|
+
for (let item of codeObject.Consts.Value) {
|
|
843
|
+
result += PycReader.DumpObject(item, level + 1);
|
|
844
|
+
}
|
|
845
|
+
}
|
|
846
|
+
if (codeObject.Names && codeObject.Names.Value) {
|
|
847
|
+
result += "Names:\n";
|
|
848
|
+
for (let item of codeObject.Names.Value) {
|
|
849
|
+
result += PycReader.DumpObject(item, level + 1);
|
|
850
|
+
}
|
|
851
|
+
}
|
|
852
|
+
if (codeObject.VarNames && codeObject.VarNames.Value) {
|
|
853
|
+
result += "VarNames:\n";
|
|
854
|
+
for (let item of codeObject.VarNames.Value) {
|
|
855
|
+
result += PycReader.DumpObject(item, level + 1);
|
|
856
|
+
}
|
|
857
|
+
}
|
|
858
|
+
if (codeObject.FreeVars && codeObject.FreeVars.Value) {
|
|
859
|
+
result += "FreeVars:\n";
|
|
860
|
+
for (let item of codeObject.FreeVars.Value) {
|
|
861
|
+
result += PycReader.DumpObject(item, level + 1);
|
|
862
|
+
}
|
|
863
|
+
}
|
|
864
|
+
if (codeObject.CellVars && codeObject.CellVars.Value) {
|
|
865
|
+
result += "CellVars:\n";
|
|
866
|
+
for (let item of codeObject.CellVars.Value) {
|
|
867
|
+
result += PycReader.DumpObject(item, level + 1);
|
|
868
|
+
}
|
|
869
|
+
}
|
|
870
|
+
result += `FileName = ${codeObject.FileName && codeObject.FileName.Value && codeObject.FileName.toString()}\n`;
|
|
871
|
+
result += `Name = ${codeObject.Name && codeObject.Name.Value && codeObject.Name.toString()}\n`;
|
|
872
|
+
result += `FirstLineNo = ${codeObject.FirstLineNo}\n`;
|
|
873
|
+
break;
|
|
874
|
+
default:
|
|
875
|
+
result += `No such type ${obj.ClassName}. Value = ${obj.Value}\n`;
|
|
876
|
+
break;
|
|
877
|
+
}
|
|
878
|
+
} catch(ex) {
|
|
879
|
+
console.log(`DumpObject error: ${ex}`);
|
|
880
|
+
}
|
|
881
|
+
return result;
|
|
882
|
+
}
|
|
883
|
+
|
|
884
|
+
static GetMethodParametersString(codeObject)
|
|
885
|
+
{
|
|
886
|
+
let pars = "";
|
|
887
|
+
if (codeObject.ArgCount > 0) {
|
|
888
|
+
for (let idx = 0; idx < codeObject.ArgCount; idx++) {
|
|
889
|
+
pars += pars == "" ? codeObject.VarNames[idx] : ", " + codeObject.VarNames[idx];
|
|
890
|
+
}
|
|
891
|
+
}
|
|
892
|
+
return pars;
|
|
893
|
+
}
|
|
894
|
+
|
|
895
|
+
versionCompare(major, minor) {
|
|
896
|
+
return (this.m_version.major - major) * 100 + (this.m_version.minor - minor);
|
|
897
|
+
}
|
|
898
|
+
}
|
|
899
|
+
|
|
900
|
+
module.exports = {PycReader};
|
|
901
|
+
|
|
902
|
+
// Registering classes in global scope for propoer class deserialization.
|
|
903
|
+
for (let className of Object.keys(module.exports)) {
|
|
904
|
+
global[className] = new module.exports[className]();
|
|
905
|
+
}
|