pst-extractor 1.8.0 → 1.10.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/dist/ColumnDescriptor.class.d.ts +26 -26
- package/dist/ColumnDescriptor.class.js +51 -48
- package/dist/DescriptorIndexNode.class.d.ts +25 -26
- package/dist/DescriptorIndexNode.class.js +53 -53
- package/dist/LZFu.class.d.ts +11 -12
- package/dist/LZFu.class.js +95 -95
- package/dist/NodeInfo.class.d.ts +33 -33
- package/dist/NodeInfo.class.js +52 -52
- package/dist/NodeMap.class.d.ts +35 -35
- package/dist/NodeMap.class.js +86 -83
- package/dist/OffsetIndexItem.class.d.ts +23 -24
- package/dist/OffsetIndexItem.class.js +45 -45
- package/dist/OutlookProperties.d.ts +275 -275
- package/dist/OutlookProperties.js +281 -281
- package/dist/PSTActivity.class.d.ts +103 -103
- package/dist/PSTActivity.class.js +144 -144
- package/dist/PSTAppointment.class.d.ts +270 -271
- package/dist/PSTAppointment.class.js +376 -376
- package/dist/PSTAttachment.class.d.ts +172 -172
- package/dist/PSTAttachment.class.js +317 -314
- package/dist/PSTContact.class.d.ts +884 -884
- package/dist/PSTContact.class.js +1227 -1227
- package/dist/PSTDescriptorItem.class.d.ts +45 -46
- package/dist/PSTDescriptorItem.class.js +99 -96
- package/dist/PSTFile.class.d.ts +215 -216
- package/dist/PSTFile.class.js +818 -792
- package/dist/PSTFolder.class.d.ts +129 -129
- package/dist/PSTFolder.class.js +318 -307
- package/dist/PSTMessage.class.d.ts +788 -789
- package/dist/PSTMessage.class.js +1321 -1318
- package/dist/PSTMessageStore.class.d.ts +13 -13
- package/dist/PSTMessageStore.class.js +17 -17
- package/dist/PSTNodeInputStream.class.d.ts +122 -123
- package/dist/PSTNodeInputStream.class.js +514 -488
- package/dist/PSTObject.class.d.ts +133 -134
- package/dist/PSTObject.class.js +326 -323
- package/dist/PSTRecipient.class.d.ts +65 -65
- package/dist/PSTRecipient.class.js +103 -103
- package/dist/PSTTable.class.d.ts +52 -52
- package/dist/PSTTable.class.js +175 -172
- package/dist/PSTTable7C.class.d.ts +45 -45
- package/dist/PSTTable7C.class.js +281 -278
- package/dist/PSTTableBC.class.d.ts +31 -31
- package/dist/PSTTableBC.class.js +111 -108
- package/dist/PSTTableItem.class.d.ts +47 -48
- package/dist/PSTTableItem.class.js +124 -121
- package/dist/PSTTask.class.d.ts +146 -146
- package/dist/PSTTask.class.js +205 -205
- package/dist/PSTUtil.class.d.ts +134 -135
- package/dist/PSTUtil.class.js +795 -790
- package/dist/RecurrencePattern.class.d.ts +49 -50
- package/dist/RecurrencePattern.class.js +120 -120
- package/dist/index.d.ts +6 -6
- package/dist/index.js +15 -15
- package/example/package.json +7 -7
- package/example/test-min.ts +31 -12
- package/example/{test-mem.ts → test.ts} +38 -30
- package/example/testdata/output.txt +278 -0
- package/example/testdata/outputBody.txt +3404 -0
- package/example/yarn.lock +112 -50
- package/junit.xml +36 -36
- package/package.json +28 -27
- package/readme.md +1 -3
- package/example/test-max.ts +0 -251
|
@@ -1,488 +1,514 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
this.
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
this.
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
if (
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
.
|
|
333
|
-
.
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
*
|
|
403
|
-
* @returns {
|
|
404
|
-
* @memberof PSTNodeInputStream
|
|
405
|
-
*/
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
*
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
}
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
}
|
|
488
|
-
|
|
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 (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
26
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
27
|
+
};
|
|
28
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
|
+
exports.PSTNodeInputStream = void 0;
|
|
30
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
31
|
+
const long_1 = __importDefault(require("long"));
|
|
32
|
+
const zlib = __importStar(require("zlib"));
|
|
33
|
+
const PSTDescriptorItem_class_1 = require("./PSTDescriptorItem.class");
|
|
34
|
+
const PSTUtil_class_1 = require("./PSTUtil.class");
|
|
35
|
+
const OffsetIndexItem_class_1 = require("./OffsetIndexItem.class");
|
|
36
|
+
const PSTFile_class_1 = require("./PSTFile.class");
|
|
37
|
+
class PSTNodeInputStream {
|
|
38
|
+
get currentLocation() {
|
|
39
|
+
return this._currentLocation;
|
|
40
|
+
}
|
|
41
|
+
set currentLocation(loc) {
|
|
42
|
+
this._currentLocation = loc;
|
|
43
|
+
}
|
|
44
|
+
get pstFile() {
|
|
45
|
+
return this._pstFile;
|
|
46
|
+
}
|
|
47
|
+
get length() {
|
|
48
|
+
return this._length;
|
|
49
|
+
}
|
|
50
|
+
get encrypted() {
|
|
51
|
+
return this._encrypted;
|
|
52
|
+
}
|
|
53
|
+
constructor(pstFile, arg, encrypted) {
|
|
54
|
+
this.skipPoints = [];
|
|
55
|
+
this.indexItems = [];
|
|
56
|
+
this.currentBlock = 0;
|
|
57
|
+
this.allData = null;
|
|
58
|
+
this.isZlib = false;
|
|
59
|
+
this._currentLocation = long_1.default.ZERO;
|
|
60
|
+
this._length = long_1.default.ZERO;
|
|
61
|
+
this._encrypted = false;
|
|
62
|
+
this.totalLoopCount = 0;
|
|
63
|
+
this._pstFile = pstFile;
|
|
64
|
+
if (arg instanceof OffsetIndexItem_class_1.OffsetIndexItem) {
|
|
65
|
+
this._encrypted =
|
|
66
|
+
pstFile.encryptionType == PSTFile_class_1.PSTFile.ENCRYPTION_TYPE_COMPRESSIBLE;
|
|
67
|
+
this.loadFromOffsetItem(arg);
|
|
68
|
+
}
|
|
69
|
+
else if (arg instanceof PSTDescriptorItem_class_1.PSTDescriptorItem) {
|
|
70
|
+
this._encrypted =
|
|
71
|
+
pstFile.encryptionType == PSTFile_class_1.PSTFile.ENCRYPTION_TYPE_COMPRESSIBLE;
|
|
72
|
+
// we want to get the first block of data and see what we are dealing with
|
|
73
|
+
this.loadFromOffsetItem(pstFile.getOffsetIndexNode(long_1.default.fromNumber(arg.offsetIndexIdentifier)));
|
|
74
|
+
}
|
|
75
|
+
else if (arg instanceof Buffer) {
|
|
76
|
+
this.allData = arg;
|
|
77
|
+
this._length = long_1.default.fromNumber(this.allData.length);
|
|
78
|
+
if (encrypted != undefined) {
|
|
79
|
+
this._encrypted = encrypted;
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
this._encrypted =
|
|
83
|
+
pstFile.encryptionType == PSTFile_class_1.PSTFile.ENCRYPTION_TYPE_COMPRESSIBLE;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
this.currentBlock = 0;
|
|
87
|
+
this.currentLocation = long_1.default.ZERO;
|
|
88
|
+
this.detectZlib();
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Checks if the node is ZL compressed and unzips if so.
|
|
92
|
+
* @private
|
|
93
|
+
* @returns
|
|
94
|
+
* @memberof PSTNodeInputStream
|
|
95
|
+
*/
|
|
96
|
+
detectZlib() {
|
|
97
|
+
// not really sure how this is meant to work, kind of going by feel here.
|
|
98
|
+
if (this.length.lt(4)) {
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
try {
|
|
102
|
+
if (this.read() === 0x78 && this.read() === 0x9c) {
|
|
103
|
+
let multiStreams = false;
|
|
104
|
+
if (this.indexItems.length > 1) {
|
|
105
|
+
const i = this.indexItems[1];
|
|
106
|
+
this.pstFile.seek(i.fileOffset);
|
|
107
|
+
multiStreams =
|
|
108
|
+
this.pstFile.read() === 0x78 && this.pstFile.read() === 0x9c;
|
|
109
|
+
}
|
|
110
|
+
// we are a compressed block, decompress the whole thing into a buffer
|
|
111
|
+
// and replace our contents with that. firstly, if we have blocks, use that as the length
|
|
112
|
+
let outputStream = null;
|
|
113
|
+
if (multiStreams) {
|
|
114
|
+
// debugger
|
|
115
|
+
// console.log('list of all index items')
|
|
116
|
+
// for (let i of this.indexItems) {
|
|
117
|
+
// console.log(i.toJSON());
|
|
118
|
+
// }
|
|
119
|
+
// console.log('----------------------')
|
|
120
|
+
for (const i of this.indexItems) {
|
|
121
|
+
const inData = Buffer.alloc(i.size);
|
|
122
|
+
this.pstFile.seek(i.fileOffset);
|
|
123
|
+
this.pstFile.readCompletely(inData);
|
|
124
|
+
const buf = zlib.unzipSync(inData);
|
|
125
|
+
outputStream = outputStream ? Buffer.concat([outputStream, buf]) : buf;
|
|
126
|
+
}
|
|
127
|
+
this.indexItems = [];
|
|
128
|
+
this.skipPoints = [];
|
|
129
|
+
}
|
|
130
|
+
else {
|
|
131
|
+
let compressedLength = this.length.toNumber();
|
|
132
|
+
if (this.indexItems.length > 0) {
|
|
133
|
+
compressedLength = 0;
|
|
134
|
+
for (const i of this.indexItems) {
|
|
135
|
+
compressedLength += i.size;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
const inData = Buffer.alloc(compressedLength);
|
|
139
|
+
this.seek(long_1.default.ZERO);
|
|
140
|
+
this.readCompletely(inData);
|
|
141
|
+
outputStream = zlib.unzipSync(inData);
|
|
142
|
+
}
|
|
143
|
+
this.allData = outputStream;
|
|
144
|
+
this.currentLocation = long_1.default.ZERO;
|
|
145
|
+
this.currentBlock = 0;
|
|
146
|
+
this._length = this.allData
|
|
147
|
+
? long_1.default.fromNumber(this.allData.length)
|
|
148
|
+
: long_1.default.ZERO;
|
|
149
|
+
}
|
|
150
|
+
this.seek(long_1.default.ZERO);
|
|
151
|
+
}
|
|
152
|
+
catch (err) {
|
|
153
|
+
console.error('PSTNodeInputStream::detectZlib Unable to decompress reportedly compressed block\n' +
|
|
154
|
+
err);
|
|
155
|
+
throw err;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Load data from offset in file.
|
|
160
|
+
* @private
|
|
161
|
+
* @param {OffsetIndexItem} offsetItem
|
|
162
|
+
* @returns
|
|
163
|
+
* @memberof PSTNodeInputStream
|
|
164
|
+
*/
|
|
165
|
+
loadFromOffsetItem(offsetItem) {
|
|
166
|
+
let bInternal = (offsetItem.indexIdentifier.toNumber() & 0x02) != 0;
|
|
167
|
+
const data = Buffer.alloc(offsetItem.size);
|
|
168
|
+
this.pstFile.seek(offsetItem.fileOffset);
|
|
169
|
+
this.pstFile.readCompletely(data);
|
|
170
|
+
if (bInternal) {
|
|
171
|
+
// All internal blocks are at least 8 bytes long...
|
|
172
|
+
if (offsetItem.size < 8) {
|
|
173
|
+
throw new Error('PSTNodeInputStream::loadFromOffsetItem Invalid internal block size');
|
|
174
|
+
}
|
|
175
|
+
if (data[0] == 0x1) {
|
|
176
|
+
bInternal = false;
|
|
177
|
+
// we are a xblock, or xxblock
|
|
178
|
+
this._length = PSTUtil_class_1.PSTUtil.convertLittleEndianBytesToLong(data, 4, 8);
|
|
179
|
+
// go through all of the blocks and create skip points.
|
|
180
|
+
this.getBlockSkipPoints(data);
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
// (Internal blocks aren't compressed)
|
|
185
|
+
if (bInternal) {
|
|
186
|
+
this._encrypted = false;
|
|
187
|
+
}
|
|
188
|
+
this.allData = data;
|
|
189
|
+
this._length = long_1.default.fromValue(this.allData.length);
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Get block skip points in file.
|
|
193
|
+
* @private
|
|
194
|
+
* @param {Buffer} data
|
|
195
|
+
* @memberof PSTNodeInputStream
|
|
196
|
+
*/
|
|
197
|
+
getBlockSkipPoints(data) {
|
|
198
|
+
if (data[0] != 0x1) {
|
|
199
|
+
throw new Error('PSTNodeInputStream::loadFromOffsetItem Unable to process XBlock, incorrect identifier');
|
|
200
|
+
}
|
|
201
|
+
const numberOfEntries = PSTUtil_class_1.PSTUtil.convertLittleEndianBytesToLong(data, 2, 4).toNumber();
|
|
202
|
+
let arraySize = 8;
|
|
203
|
+
if (this.pstFile.pstFileType == PSTFile_class_1.PSTFile.PST_TYPE_ANSI) {
|
|
204
|
+
arraySize = 4;
|
|
205
|
+
}
|
|
206
|
+
if (data[1] == 0x2) {
|
|
207
|
+
// XXBlock
|
|
208
|
+
let offset = 8;
|
|
209
|
+
for (let x = 0; x < numberOfEntries; x++) {
|
|
210
|
+
let bid = PSTUtil_class_1.PSTUtil.convertLittleEndianBytesToLong(data, offset, offset + arraySize);
|
|
211
|
+
bid = bid.and(0xfffffffe);
|
|
212
|
+
// get the details in this block and
|
|
213
|
+
const offsetItem = this.pstFile.getOffsetIndexNode(bid);
|
|
214
|
+
const blockData = Buffer.alloc(offsetItem.size);
|
|
215
|
+
this.pstFile.seek(offsetItem.fileOffset);
|
|
216
|
+
this.pstFile.readCompletely(blockData);
|
|
217
|
+
// recurse
|
|
218
|
+
this.getBlockSkipPoints(blockData);
|
|
219
|
+
offset += arraySize;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
else if (data[1] == 0x1) {
|
|
223
|
+
// normal XBlock
|
|
224
|
+
let offset = 8;
|
|
225
|
+
for (let x = 0; x < numberOfEntries; x++) {
|
|
226
|
+
let bid = PSTUtil_class_1.PSTUtil.convertLittleEndianBytesToLong(data, offset, offset + arraySize);
|
|
227
|
+
bid = bid.and(0xfffffffe);
|
|
228
|
+
// get the details in this block and add it to the list
|
|
229
|
+
const offsetItem = this.pstFile.getOffsetIndexNode(bid);
|
|
230
|
+
this.indexItems.push(offsetItem);
|
|
231
|
+
this.skipPoints.push(long_1.default.fromValue(this.currentLocation));
|
|
232
|
+
this.currentLocation = this.currentLocation.add(offsetItem.size);
|
|
233
|
+
offset += arraySize;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
/**
|
|
238
|
+
* Read from the stream.
|
|
239
|
+
* @param {Buffer} [output]
|
|
240
|
+
* @returns
|
|
241
|
+
* @memberof PSTNodeInputStream
|
|
242
|
+
*/
|
|
243
|
+
read(output) {
|
|
244
|
+
if (!output) {
|
|
245
|
+
return this.readSingleByte();
|
|
246
|
+
}
|
|
247
|
+
else {
|
|
248
|
+
return this.readBlock(output);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* Read a single byte from the input stream.
|
|
253
|
+
* @returns {number}
|
|
254
|
+
* @memberof PSTNodeInputStream
|
|
255
|
+
*/
|
|
256
|
+
readSingleByte() {
|
|
257
|
+
// first deal with items < 8K and we have all the data already
|
|
258
|
+
if (this.allData != null) {
|
|
259
|
+
if (this.currentLocation == this.length) {
|
|
260
|
+
// EOF
|
|
261
|
+
return -1;
|
|
262
|
+
}
|
|
263
|
+
let value = this.allData[this.currentLocation.toNumber()] & 0xff;
|
|
264
|
+
this.currentLocation = this.currentLocation.add(1);
|
|
265
|
+
if (this.encrypted) {
|
|
266
|
+
value = PSTUtil_class_1.PSTUtil.compEnc[value];
|
|
267
|
+
}
|
|
268
|
+
return value;
|
|
269
|
+
}
|
|
270
|
+
let item = this.indexItems[this.currentBlock];
|
|
271
|
+
let skipPoint = this.skipPoints[this.currentBlock];
|
|
272
|
+
if (this.currentLocation.add(1).greaterThan(skipPoint.add(item.size))) {
|
|
273
|
+
// got to move to the next block
|
|
274
|
+
this.currentBlock++;
|
|
275
|
+
if (this.currentBlock >= this.indexItems.length) {
|
|
276
|
+
return -1;
|
|
277
|
+
}
|
|
278
|
+
item = this.indexItems[this.currentBlock];
|
|
279
|
+
skipPoint = this.skipPoints[this.currentBlock];
|
|
280
|
+
}
|
|
281
|
+
// get the next byte.
|
|
282
|
+
const pos = item.fileOffset.add(this.currentLocation).subtract(skipPoint);
|
|
283
|
+
this.pstFile.seek(pos);
|
|
284
|
+
let output = this.pstFile.read();
|
|
285
|
+
if (output < 0) {
|
|
286
|
+
return -1;
|
|
287
|
+
}
|
|
288
|
+
if (this.encrypted) {
|
|
289
|
+
output = PSTUtil_class_1.PSTUtil.compEnc[output];
|
|
290
|
+
}
|
|
291
|
+
this.currentLocation = this.currentLocation.add(1);
|
|
292
|
+
return output;
|
|
293
|
+
}
|
|
294
|
+
/**
|
|
295
|
+
* Read a block from the input stream, ensuring buffer is completely filled.
|
|
296
|
+
* Recommended block size = 8176 (size used internally by PSTs)
|
|
297
|
+
* @param {Buffer} target
|
|
298
|
+
* @memberof PSTNodeInputStream
|
|
299
|
+
*/
|
|
300
|
+
readCompletely(target) {
|
|
301
|
+
let offset = 0;
|
|
302
|
+
let numRead = 0;
|
|
303
|
+
while (offset < target.length) {
|
|
304
|
+
numRead = this.readFromOffset(target, offset, target.length - offset);
|
|
305
|
+
if (numRead === -1) {
|
|
306
|
+
throw new Error('PSTNodeInputStream::readCompletely unexpected EOF encountered attempting to read from PSTInputStream');
|
|
307
|
+
}
|
|
308
|
+
offset += numRead;
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
/**
|
|
312
|
+
* Read a block from the input stream.
|
|
313
|
+
* Recommended block size = 8176 (size used internally by PSTs)
|
|
314
|
+
* @param {Buffer} output
|
|
315
|
+
* @returns {number}
|
|
316
|
+
* @memberof PSTNodeInputStream
|
|
317
|
+
*/
|
|
318
|
+
readBlock(output) {
|
|
319
|
+
// this method is implemented in an attempt to make things a bit faster
|
|
320
|
+
// than the byte-by-byte read() crap above.
|
|
321
|
+
// it's tricky 'cause we have to copy blocks from a few different areas.
|
|
322
|
+
if (this.currentLocation == this.length) {
|
|
323
|
+
// EOF
|
|
324
|
+
return -1;
|
|
325
|
+
}
|
|
326
|
+
// first deal with the small stuff
|
|
327
|
+
if (this.allData != null) {
|
|
328
|
+
const bytesRemaining = this.length
|
|
329
|
+
.subtract(this.currentLocation)
|
|
330
|
+
.toNumber();
|
|
331
|
+
if (output.length >= bytesRemaining) {
|
|
332
|
+
PSTUtil_class_1.PSTUtil.arraycopy(this.allData, this.currentLocation.toNumber(), output, 0, bytesRemaining);
|
|
333
|
+
if (this.encrypted) {
|
|
334
|
+
PSTUtil_class_1.PSTUtil.decode(output);
|
|
335
|
+
}
|
|
336
|
+
this.currentLocation = this.currentLocation.add(bytesRemaining); // should be = to this.length
|
|
337
|
+
return bytesRemaining;
|
|
338
|
+
}
|
|
339
|
+
else {
|
|
340
|
+
PSTUtil_class_1.PSTUtil.arraycopy(this.allData, this.currentLocation.toNumber(), output, 0, output.length);
|
|
341
|
+
if (this.encrypted) {
|
|
342
|
+
PSTUtil_class_1.PSTUtil.decode(output);
|
|
343
|
+
}
|
|
344
|
+
this.currentLocation = this.currentLocation.add(output.length);
|
|
345
|
+
return output.length;
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
let filled = false;
|
|
349
|
+
let totalBytesFilled = 0;
|
|
350
|
+
// while we still need to fill the array
|
|
351
|
+
while (!filled) {
|
|
352
|
+
// fill up the output from where we are
|
|
353
|
+
// get the current block, either to the end, or until the length of
|
|
354
|
+
// the output
|
|
355
|
+
const offset = this.indexItems[this.currentBlock];
|
|
356
|
+
const skipPoint = this.skipPoints[this.currentBlock];
|
|
357
|
+
const currentPosInBlock = this.currentLocation
|
|
358
|
+
.subtract(skipPoint)
|
|
359
|
+
.toNumber();
|
|
360
|
+
this.pstFile.seek(offset.fileOffset.add(currentPosInBlock));
|
|
361
|
+
const nextSkipPoint = skipPoint.add(offset.size);
|
|
362
|
+
let bytesRemaining = output.length - totalBytesFilled;
|
|
363
|
+
// if the total bytes remaining if going to take us past our size
|
|
364
|
+
if (bytesRemaining > this.length.subtract(this.currentLocation).toNumber()) {
|
|
365
|
+
// we only have so much to give
|
|
366
|
+
bytesRemaining = this.length.subtract(this.currentLocation).toNumber();
|
|
367
|
+
}
|
|
368
|
+
if (nextSkipPoint.greaterThanOrEqual(this.currentLocation.add(bytesRemaining))) {
|
|
369
|
+
// we can fill the output with the rest of our current block!
|
|
370
|
+
const chunk = Buffer.alloc(bytesRemaining);
|
|
371
|
+
this.pstFile.readCompletely(chunk);
|
|
372
|
+
PSTUtil_class_1.PSTUtil.arraycopy(chunk, 0, output, totalBytesFilled, bytesRemaining);
|
|
373
|
+
totalBytesFilled += bytesRemaining;
|
|
374
|
+
// we are done!
|
|
375
|
+
filled = true;
|
|
376
|
+
this.currentLocation = this.currentLocation.add(bytesRemaining);
|
|
377
|
+
}
|
|
378
|
+
else {
|
|
379
|
+
// we need to read out a whole chunk and keep going
|
|
380
|
+
const bytesToRead = offset.size - currentPosInBlock;
|
|
381
|
+
const chunk = Buffer.alloc(bytesToRead);
|
|
382
|
+
this.pstFile.readCompletely(chunk);
|
|
383
|
+
PSTUtil_class_1.PSTUtil.arraycopy(chunk, 0, output, totalBytesFilled, bytesToRead);
|
|
384
|
+
totalBytesFilled += bytesToRead;
|
|
385
|
+
this.currentBlock++;
|
|
386
|
+
this.currentLocation = this.currentLocation.add(bytesToRead);
|
|
387
|
+
}
|
|
388
|
+
this.totalLoopCount++;
|
|
389
|
+
}
|
|
390
|
+
// decode the array if required
|
|
391
|
+
if (this.encrypted) {
|
|
392
|
+
PSTUtil_class_1.PSTUtil.decode(output);
|
|
393
|
+
}
|
|
394
|
+
// fill up our chunk
|
|
395
|
+
// move to the next chunk
|
|
396
|
+
return totalBytesFilled;
|
|
397
|
+
}
|
|
398
|
+
/**
|
|
399
|
+
* Read from the offset.
|
|
400
|
+
* @param {Buffer} output
|
|
401
|
+
* @param {number} offset
|
|
402
|
+
* @param {number} length
|
|
403
|
+
* @returns {number}
|
|
404
|
+
* @memberof PSTNodeInputStream
|
|
405
|
+
*/
|
|
406
|
+
readFromOffset(output, offset, length) {
|
|
407
|
+
if (this.currentLocation == this.length) {
|
|
408
|
+
// EOF
|
|
409
|
+
return -1;
|
|
410
|
+
}
|
|
411
|
+
if (output.length < length) {
|
|
412
|
+
length = output.length;
|
|
413
|
+
}
|
|
414
|
+
const buf = Buffer.alloc(length);
|
|
415
|
+
const lengthRead = this.readBlock(buf);
|
|
416
|
+
PSTUtil_class_1.PSTUtil.arraycopy(buf, 0, output, offset, lengthRead);
|
|
417
|
+
return lengthRead;
|
|
418
|
+
}
|
|
419
|
+
/**
|
|
420
|
+
* Reset the file pointer (internally).
|
|
421
|
+
* @memberof PSTNodeInputStream
|
|
422
|
+
*/
|
|
423
|
+
reset() {
|
|
424
|
+
this.currentBlock = 0;
|
|
425
|
+
this._currentLocation = long_1.default.ZERO;
|
|
426
|
+
}
|
|
427
|
+
/**
|
|
428
|
+
* Get the offsets (block positions) used in the array
|
|
429
|
+
* @returns {long[]}
|
|
430
|
+
* @memberof PSTNodeInputStream
|
|
431
|
+
*/
|
|
432
|
+
getBlockOffsets() {
|
|
433
|
+
const output = [];
|
|
434
|
+
if (this.skipPoints.length === 0) {
|
|
435
|
+
const len = long_1.default.fromValue(this.length);
|
|
436
|
+
output.push(len);
|
|
437
|
+
}
|
|
438
|
+
else {
|
|
439
|
+
for (let x = 0; x < this.skipPoints.length; x++) {
|
|
440
|
+
const size = long_1.default.fromValue(this.indexItems[x].size);
|
|
441
|
+
output.push(this.skipPoints[x].add(size));
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
return output;
|
|
445
|
+
}
|
|
446
|
+
/**
|
|
447
|
+
* Seek within item.
|
|
448
|
+
* @param {long} location
|
|
449
|
+
* @returns
|
|
450
|
+
* @memberof PSTNodeInputStream
|
|
451
|
+
*/
|
|
452
|
+
seek(location) {
|
|
453
|
+
// not past the end!
|
|
454
|
+
if (location.greaterThan(this.length)) {
|
|
455
|
+
throw new Error('PSTNodeInputStream::seek Attempt to seek past end of item! size = ' +
|
|
456
|
+
this.length +
|
|
457
|
+
', seeking to:' +
|
|
458
|
+
location);
|
|
459
|
+
}
|
|
460
|
+
// are we already there?
|
|
461
|
+
if (this.currentLocation.equals(location)) {
|
|
462
|
+
return;
|
|
463
|
+
}
|
|
464
|
+
// get us to the right block
|
|
465
|
+
let skipPoint = long_1.default.ZERO;
|
|
466
|
+
this.currentBlock = 0;
|
|
467
|
+
if (this.allData == null) {
|
|
468
|
+
skipPoint = this.skipPoints[this.currentBlock + 1];
|
|
469
|
+
while (location.greaterThanOrEqual(skipPoint)) {
|
|
470
|
+
this.currentBlock++;
|
|
471
|
+
// is this the last block?
|
|
472
|
+
if (this.currentBlock == this.skipPoints.length - 1) {
|
|
473
|
+
// that's all folks
|
|
474
|
+
break;
|
|
475
|
+
}
|
|
476
|
+
else {
|
|
477
|
+
skipPoint = this.skipPoints[this.currentBlock + 1];
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
// now move us to the right position in there
|
|
482
|
+
this.currentLocation = location;
|
|
483
|
+
if (this.allData == null) {
|
|
484
|
+
const blockStart = this.indexItems[this.currentBlock].fileOffset;
|
|
485
|
+
const newFilePos = blockStart.add(location).subtract(skipPoint);
|
|
486
|
+
this.pstFile.seek(newFilePos);
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
/**
|
|
490
|
+
* Seek within stream and read a long.
|
|
491
|
+
* @param {long} location
|
|
492
|
+
* @param {number} bytes
|
|
493
|
+
* @returns {long}
|
|
494
|
+
* @memberof PSTNodeInputStream
|
|
495
|
+
*/
|
|
496
|
+
seekAndReadLong(location, bytes) {
|
|
497
|
+
this.seek(location);
|
|
498
|
+
const buffer = Buffer.alloc(bytes);
|
|
499
|
+
this.readCompletely(buffer);
|
|
500
|
+
return PSTUtil_class_1.PSTUtil.convertLittleEndianBytesToLong(buffer);
|
|
501
|
+
}
|
|
502
|
+
/**
|
|
503
|
+
* JSON the object, large buffers excluded.
|
|
504
|
+
* @returns {*}
|
|
505
|
+
* @memberof PSTNodeInputStream
|
|
506
|
+
*/
|
|
507
|
+
toJSON() {
|
|
508
|
+
return {
|
|
509
|
+
currentBlock: this.currentBlock,
|
|
510
|
+
isZlib: this.isZlib,
|
|
511
|
+
};
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
exports.PSTNodeInputStream = PSTNodeInputStream;
|