pst-extractor 1.9.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.
Files changed (59) hide show
  1. package/dist/ColumnDescriptor.class.d.ts +26 -26
  2. package/dist/ColumnDescriptor.class.js +51 -51
  3. package/dist/DescriptorIndexNode.class.d.ts +25 -26
  4. package/dist/DescriptorIndexNode.class.js +53 -53
  5. package/dist/LZFu.class.d.ts +11 -12
  6. package/dist/LZFu.class.js +95 -95
  7. package/dist/NodeInfo.class.d.ts +33 -33
  8. package/dist/NodeInfo.class.js +52 -52
  9. package/dist/NodeMap.class.d.ts +35 -35
  10. package/dist/NodeMap.class.js +86 -86
  11. package/dist/OffsetIndexItem.class.d.ts +23 -24
  12. package/dist/OffsetIndexItem.class.js +45 -45
  13. package/dist/OutlookProperties.d.ts +275 -275
  14. package/dist/OutlookProperties.js +281 -281
  15. package/dist/PSTActivity.class.d.ts +103 -103
  16. package/dist/PSTActivity.class.js +144 -144
  17. package/dist/PSTAppointment.class.d.ts +270 -271
  18. package/dist/PSTAppointment.class.js +376 -376
  19. package/dist/PSTAttachment.class.d.ts +172 -172
  20. package/dist/PSTAttachment.class.js +317 -317
  21. package/dist/PSTContact.class.d.ts +884 -884
  22. package/dist/PSTContact.class.js +1227 -1227
  23. package/dist/PSTDescriptorItem.class.d.ts +45 -46
  24. package/dist/PSTDescriptorItem.class.js +99 -99
  25. package/dist/PSTFile.class.d.ts +215 -216
  26. package/dist/PSTFile.class.js +818 -818
  27. package/dist/PSTFolder.class.d.ts +129 -129
  28. package/dist/PSTFolder.class.js +318 -310
  29. package/dist/PSTMessage.class.d.ts +788 -789
  30. package/dist/PSTMessage.class.js +1321 -1321
  31. package/dist/PSTMessageStore.class.d.ts +13 -13
  32. package/dist/PSTMessageStore.class.js +17 -17
  33. package/dist/PSTNodeInputStream.class.d.ts +122 -123
  34. package/dist/PSTNodeInputStream.class.js +514 -514
  35. package/dist/PSTObject.class.d.ts +133 -134
  36. package/dist/PSTObject.class.js +326 -326
  37. package/dist/PSTRecipient.class.d.ts +65 -65
  38. package/dist/PSTRecipient.class.js +103 -103
  39. package/dist/PSTTable.class.d.ts +52 -52
  40. package/dist/PSTTable.class.js +175 -175
  41. package/dist/PSTTable7C.class.d.ts +45 -45
  42. package/dist/PSTTable7C.class.js +281 -281
  43. package/dist/PSTTableBC.class.d.ts +31 -31
  44. package/dist/PSTTableBC.class.js +111 -111
  45. package/dist/PSTTableItem.class.d.ts +47 -48
  46. package/dist/PSTTableItem.class.js +124 -124
  47. package/dist/PSTTask.class.d.ts +146 -146
  48. package/dist/PSTTask.class.js +205 -205
  49. package/dist/PSTUtil.class.d.ts +134 -135
  50. package/dist/PSTUtil.class.js +795 -795
  51. package/dist/RecurrencePattern.class.d.ts +49 -50
  52. package/dist/RecurrencePattern.class.js +120 -120
  53. package/dist/index.d.ts +6 -6
  54. package/dist/index.js +15 -15
  55. package/example/package.json +6 -6
  56. package/example/yarn.lock +95 -44
  57. package/junit.xml +68 -68
  58. package/package.json +26 -26
  59. package/readme.md +1 -3
@@ -1,818 +1,818 @@
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.PSTFile = void 0;
30
- const fs = __importStar(require("fs"));
31
- const long_1 = __importDefault(require("long"));
32
- const DescriptorIndexNode_class_1 = require("./DescriptorIndexNode.class");
33
- const OffsetIndexItem_class_1 = require("./OffsetIndexItem.class");
34
- const PSTDescriptorItem_class_1 = require("./PSTDescriptorItem.class");
35
- const PSTFolder_class_1 = require("./PSTFolder.class");
36
- const PSTMessageStore_class_1 = require("./PSTMessageStore.class");
37
- const PSTNodeInputStream_class_1 = require("./PSTNodeInputStream.class");
38
- const PSTTableBC_class_1 = require("./PSTTableBC.class");
39
- const PSTUtil_class_1 = require("./PSTUtil.class");
40
- const NodeMap_class_1 = require("./NodeMap.class");
41
- // eslint-disable-next-line @typescript-eslint/no-var-requires
42
- const uuidparse = require('uuid-parse');
43
- class PSTFile {
44
- constructor(arg) {
45
- this.guidMap = new Map([
46
- ['00020329-0000-0000-C000-000000000046', 0],
47
- ['00062008-0000-0000-C000-000000000046', 1],
48
- ['00062004-0000-0000-C000-000000000046', 2],
49
- ['00020386-0000-0000-C000-000000000046', 3],
50
- ['00062002-0000-0000-C000-000000000046', 4],
51
- ['6ED8DA90-450B-101B-98DA-00AA003F1305', 5],
52
- ['0006200A-0000-0000-C000-000000000046', 6],
53
- ['41F28F13-83F4-4114-A584-EEDB5A6B0BFF', 7],
54
- ['0006200E-0000-0000-C000-000000000046', 8],
55
- ['00062041-0000-0000-C000-000000000046', 9],
56
- ['00062003-0000-0000-C000-000000000046', 10],
57
- ['4442858E-A9E3-4E80-B900-317A210CC15B', 11],
58
- ['00020328-0000-0000-C000-000000000046', 12],
59
- ['71035549-0739-4DCB-9163-00F0580DBBDF', 13],
60
- ['00062040-0000-0000-C000-000000000046', 14],
61
- ]);
62
- // the type of encryption the files uses
63
- this._encryptionType = 0;
64
- // type of file (e.g. ANSI)
65
- this._pstFileType = 0;
66
- this._pstFilename = '';
67
- // b-tree
68
- this.childrenDescriptorTree = null;
69
- // in-memory file buffer (instead of filesystem)
70
- this.pstBuffer = Buffer.alloc(0);
71
- // position in file
72
- this.position = 0;
73
- if (arg instanceof Buffer) {
74
- // use an in-memory buffer of PST
75
- this.pstBuffer = arg;
76
- this.pstFD = -1;
77
- }
78
- else {
79
- // use PST in filesystem
80
- this._pstFilename = arg;
81
- this.pstFD = fs.openSync(this._pstFilename, 'r');
82
- }
83
- // confirm first 4 bytes are !BDN
84
- const buffer = Buffer.alloc(514);
85
- this.readSync(buffer, 514, 0);
86
- const key = '!BDN';
87
- if (buffer[0] != key.charCodeAt(0) ||
88
- buffer[1] != key.charCodeAt(1) ||
89
- buffer[2] != key.charCodeAt(2) ||
90
- buffer[3] != key.charCodeAt(3)) {
91
- throw new Error('PSTFile::open Invalid file header (expected: "!BDN"): ' + buffer);
92
- }
93
- // make sure we are using a supported version of a PST...
94
- if (buffer[10] === PSTFile.PST_TYPE_ANSI_2) {
95
- buffer[10] = PSTFile.PST_TYPE_ANSI;
96
- }
97
- if (buffer[10] !== PSTFile.PST_TYPE_ANSI &&
98
- buffer[10] !== PSTFile.PST_TYPE_UNICODE &&
99
- buffer[10] !== PSTFile.PST_TYPE_2013_UNICODE) {
100
- throw new Error('PSTFile::open Unrecognised PST File version: ' + buffer[10]);
101
- }
102
- this._pstFileType = buffer[10];
103
- // make sure no encryption
104
- if (this._pstFileType === PSTFile.PST_TYPE_ANSI) {
105
- this._encryptionType = buffer[461];
106
- }
107
- else {
108
- this._encryptionType = buffer[513];
109
- }
110
- if (this._encryptionType === 0x02) {
111
- throw new Error('PSTFile::open PST is encrypted');
112
- }
113
- // build out name to id map
114
- this.processNameToIDMap();
115
- }
116
- get encryptionType() {
117
- return this._encryptionType;
118
- }
119
- get pstFileType() {
120
- return this._pstFileType;
121
- }
122
- get pstFilename() {
123
- return this._pstFilename;
124
- }
125
- /**
126
- * Close the file.
127
- * @memberof PSTFile
128
- */
129
- close() {
130
- if (this.pstFD > 0) {
131
- fs.closeSync(this.pstFD);
132
- }
133
- }
134
- /**
135
- * Process name to ID map.
136
- * @private
137
- * @memberof PSTFile
138
- */
139
- processNameToIDMap() {
140
- const nameToIdMapDescriptorNode = this.getDescriptorIndexNode(long_1.default.fromNumber(97));
141
- // get the descriptors if we have them
142
- let localDescriptorItems = null;
143
- if (nameToIdMapDescriptorNode.localDescriptorsOffsetIndexIdentifier.toNumber() !=
144
- 0) {
145
- localDescriptorItems = this.getPSTDescriptorItems(nameToIdMapDescriptorNode.localDescriptorsOffsetIndexIdentifier);
146
- }
147
- // process the map
148
- const off = this.getOffsetIndexNode(nameToIdMapDescriptorNode.dataOffsetIndexIdentifier);
149
- const nodein = new PSTNodeInputStream_class_1.PSTNodeInputStream(this, off);
150
- const bcTable = new PSTTableBC_class_1.PSTTableBC(nodein);
151
- const tableItems = bcTable.getItems();
152
- // Get the guids
153
- const guidEntry = tableItems.get(2);
154
- if (!guidEntry) {
155
- throw new Error('PSTFile::processNameToIDMap guidEntry is null');
156
- }
157
- const guids = this.getData(guidEntry, localDescriptorItems);
158
- const nGuids = Math.trunc(guids.length / 16);
159
- const guidIndexes = [];
160
- let offset = 0;
161
- for (let i = 0; i < nGuids; ++i) {
162
- let leftQuad = PSTUtil_class_1.PSTUtil.convertLittleEndianBytesToLong(guids, offset, offset + 4);
163
- leftQuad = leftQuad.shiftLeft(32);
164
- let midQuad = PSTUtil_class_1.PSTUtil.convertLittleEndianBytesToLong(guids, offset + 4, offset + 6);
165
- midQuad = midQuad.shiftLeft(16);
166
- const rightQuad = PSTUtil_class_1.PSTUtil.convertLittleEndianBytesToLong(guids, offset + 6, offset + 8);
167
- const mostSigBits = leftQuad.or(midQuad).or(rightQuad);
168
- const leastSigBits = PSTUtil_class_1.PSTUtil.convertBigEndianBytesToLong(guids, offset + 8, offset + 16);
169
- // weird that need to cast below to any to get tsc error to go away - why?
170
- // see https://github.com/Microsoft/TypeScript/issues/6436
171
- const mostBuffer = mostSigBits.toBytes();
172
- const leastBuffer = leastSigBits.toBytes();
173
- const arrUID = mostBuffer.concat(leastBuffer);
174
- const strUID = uuidparse.unparse(arrUID).toUpperCase();
175
- const guid = this.guidMap.get(strUID);
176
- if (guid) {
177
- guidIndexes[i] = guid;
178
- }
179
- else {
180
- guidIndexes[i] = -1; // We don't know this guid
181
- }
182
- // console.log('PSTFile:: processNameToIdMap idx: ' + i + ', ' + strUID + ', ' + guidIndexes[i]);
183
- offset += 16;
184
- }
185
- // if we have a reference to an internal descriptor
186
- const mapEntries = tableItems.get(3);
187
- if (!mapEntries) {
188
- throw new Error('PSTFile::processNameToIDMap mapEntries is null');
189
- }
190
- const nameToIdByte = this.getData(mapEntries, localDescriptorItems);
191
- const stringMapEntries = tableItems.get(4);
192
- if (!stringMapEntries) {
193
- throw new Error('PSTFile::processNameToIDMap stringMapEntries is null');
194
- }
195
- const stringNameToIdByte = this.getData(stringMapEntries, localDescriptorItems);
196
- // process the entries
197
- for (let x = 0; x + 8 < nameToIdByte.length; x += 8) {
198
- const key = PSTUtil_class_1.PSTUtil.convertLittleEndianBytesToLong(nameToIdByte, x, x + 4).toNumber();
199
- let guid = PSTUtil_class_1.PSTUtil.convertLittleEndianBytesToLong(nameToIdByte, x + 4, x + 6).toNumber();
200
- let propId = PSTUtil_class_1.PSTUtil.convertLittleEndianBytesToLong(nameToIdByte, x + 6, x + 8).toNumber();
201
- if ((guid & 0x0001) == 0) {
202
- // identifier is numeric
203
- propId += 0x8000;
204
- guid >>= 1;
205
- let guidIndex;
206
- if (guid == 1) {
207
- guidIndex = PSTFile.PS_MAPI;
208
- }
209
- else if (guid == 2) {
210
- guidIndex = PSTFile.PS_PUBLIC_STRINGS;
211
- }
212
- else {
213
- guidIndex = guidIndexes[guid - 3];
214
- }
215
- PSTFile.nodeMap.setId(key, propId, guidIndex);
216
- }
217
- else {
218
- // identifier is a string
219
- // key is byte offset into the String stream in which the string name of the property is stored.
220
- const len = PSTUtil_class_1.PSTUtil.convertLittleEndianBytesToLong(stringNameToIdByte, key, key + 4).toNumber();
221
- const keyByteValue = Buffer.alloc(len);
222
- PSTUtil_class_1.PSTUtil.arraycopy(stringNameToIdByte, key + 4, keyByteValue, 0, keyByteValue.length);
223
- propId += 0x8000;
224
- PSTFile.nodeMap.setId(keyByteValue.toString('utf16le').replace(/\0/g, ''), propId);
225
- }
226
- }
227
- }
228
- /**
229
- * Get data from a descriptor and store in buffer.
230
- * @private
231
- * @param {PSTTableItem} item
232
- * @param {Map<number, PSTDescriptorItem>} localDescriptorItems
233
- * @returns {Buffer}
234
- * @memberof PSTFile
235
- */
236
- getData(item, localDescriptorItems) {
237
- if (item.data.length != 0) {
238
- return item.data;
239
- }
240
- if (localDescriptorItems == null) {
241
- throw new Error('PSTFile::getData External reference but no localDescriptorItems in PSTFile.getData()');
242
- }
243
- if (item.entryValueType != 0x0102) {
244
- throw new Error('PSTFile::getData Attempting to get non-binary data in PSTFile.getData()');
245
- }
246
- const mapDescriptorItem = localDescriptorItems.get(item.entryValueReference);
247
- if (mapDescriptorItem == null) {
248
- throw new Error('PSTFile::getData Descriptor not found: ' + item.entryValueReference);
249
- }
250
- return mapDescriptorItem.getData();
251
- }
252
- /**
253
- * Get name to ID map item.
254
- * @param {number} key
255
- * @param {number} idx
256
- * @returns {number}
257
- * @memberof PSTFile
258
- */
259
- getNameToIdMapItem(key, idx) {
260
- return PSTFile.nodeMap.getId(key, idx);
261
- }
262
- /**
263
- * Get public string to id map item.
264
- * @static
265
- * @param {string} key
266
- * @returns {number}
267
- * @memberof PSTFile
268
- */
269
- static getPublicStringToIdMapItem(key) {
270
- return PSTFile.nodeMap.getId(key);
271
- }
272
- /**
273
- * Get property name from id.
274
- * @static
275
- * @param {number} propertyId
276
- * @param {boolean} bNamed
277
- * @returns {string}
278
- * @memberof PSTFile
279
- */
280
- static getPropertyName(propertyId, bNamed) {
281
- return PSTUtil_class_1.PSTUtil.propertyName.get(propertyId);
282
- }
283
- /**
284
- * Get name to id map key.
285
- * @static
286
- * @param {number} propId
287
- * @returns {long}
288
- * @memberof PSTFile
289
- */
290
- static getNameToIdMapKey(propId) {
291
- return PSTFile.nodeMap.getNumericName(propId);
292
- }
293
- /**
294
- * Get the message store of the PST file. Note that this doesn't really
295
- * have much information, better to look under the root folder.
296
- * @returns {PSTMessageStore}
297
- * @memberof PSTFile
298
- */
299
- getMessageStore() {
300
- const messageStoreDescriptor = this.getDescriptorIndexNode(long_1.default.fromNumber(PSTFile.MESSAGE_STORE_DESCRIPTOR_IDENTIFIER));
301
- return new PSTMessageStore_class_1.PSTMessageStore(this, messageStoreDescriptor);
302
- }
303
- /**
304
- * Get the root folder for the PST file
305
- * @returns {PSTFolder}
306
- * @memberof PSTFile
307
- */
308
- getRootFolder() {
309
- const rootFolderDescriptor = this.getDescriptorIndexNode(long_1.default.fromValue(PSTFile.ROOT_FOLDER_DESCRIPTOR_IDENTIFIER));
310
- const output = new PSTFolder_class_1.PSTFolder(this, rootFolderDescriptor);
311
- return output;
312
- }
313
- /**
314
- * Read a leaf in the b-tree.
315
- * @param {long} bid
316
- * @returns {PSTNodeInputStream}
317
- * @memberof PSTFile
318
- */
319
- readLeaf(bid) {
320
- // get the index node for the descriptor index
321
- const offsetItem = this.getOffsetIndexNode(bid);
322
- return new PSTNodeInputStream_class_1.PSTNodeInputStream(this, offsetItem);
323
- }
324
- /**
325
- * Read the size of the specified leaf.
326
- * @param {long} bid
327
- * @returns {number}
328
- * @memberof PSTFile
329
- */
330
- getLeafSize(bid) {
331
- const offsetItem = this.getOffsetIndexNode(bid);
332
- // Internal block?
333
- if ((offsetItem.indexIdentifier.toNumber() & 0x02) == 0) {
334
- // No, return the raw size
335
- return offsetItem.size;
336
- }
337
- // we only need the first 8 bytes
338
- const data = Buffer.alloc(8);
339
- this.seek(offsetItem.fileOffset);
340
- this.readCompletely(data);
341
- // we are an array, get the sum of the sizes...
342
- return PSTUtil_class_1.PSTUtil.convertLittleEndianBytesToLong(data, 4, 8).toNumber();
343
- }
344
- /**
345
- * Get file offset, which is sorted in 8 little endian bytes
346
- * @private
347
- * @param {long} startOffset
348
- * @returns {long}
349
- * @memberof PSTFile
350
- */
351
- extractLEFileOffset(startOffset) {
352
- let offset = long_1.default.ZERO;
353
- if (this._pstFileType == PSTFile.PST_TYPE_ANSI) {
354
- this.seek(startOffset);
355
- const buffer = Buffer.alloc(4);
356
- this.readCompletely(buffer);
357
- offset = offset.or(buffer[3] & 0xff);
358
- offset = offset.shiftLeft(8);
359
- offset = offset.or(buffer[2] & 0xff);
360
- offset = offset.shiftLeft(8);
361
- offset = offset.or(buffer[1] & 0xff);
362
- offset = offset.shiftLeft(8);
363
- offset = offset.or(buffer[0] & 0xff);
364
- }
365
- else {
366
- this.seek(startOffset);
367
- const buffer = Buffer.alloc(8);
368
- this.readCompletely(buffer);
369
- offset = offset.or(buffer[7] & 0xff);
370
- let tmpLongValue;
371
- for (let x = 6; x >= 0; x--) {
372
- offset = offset.shiftLeft(8);
373
- tmpLongValue = buffer[x] & 0xff;
374
- offset = offset.or(tmpLongValue);
375
- }
376
- }
377
- return offset;
378
- }
379
- /**
380
- * Navigate PST B-tree and find a specific item.
381
- * @private
382
- * @param {long} index
383
- * @param {boolean} descTree
384
- * @returns {Buffer}
385
- * @memberof PSTFile
386
- */
387
- findBtreeItem(index, descTree) {
388
- let btreeStartOffset;
389
- let fileTypeAdjustment;
390
- // first find the starting point for the offset index
391
- if (this._pstFileType === PSTFile.PST_TYPE_ANSI) {
392
- btreeStartOffset = this.extractLEFileOffset(long_1.default.fromValue(196));
393
- if (descTree) {
394
- btreeStartOffset = this.extractLEFileOffset(long_1.default.fromValue(188));
395
- }
396
- }
397
- else {
398
- btreeStartOffset = this.extractLEFileOffset(long_1.default.fromValue(240));
399
- if (descTree) {
400
- btreeStartOffset = this.extractLEFileOffset(long_1.default.fromValue(224));
401
- }
402
- }
403
- // okay, what we want to do is navigate the tree until you reach the bottom....
404
- // try and read the index b-tree
405
- let buffer = Buffer.alloc(2);
406
- if (this._pstFileType === PSTFile.PST_TYPE_ANSI) {
407
- fileTypeAdjustment = 500;
408
- }
409
- else if (this._pstFileType === PSTFile.PST_TYPE_2013_UNICODE) {
410
- fileTypeAdjustment = 0x1000 - 24;
411
- }
412
- else {
413
- fileTypeAdjustment = 496;
414
- }
415
- this.seek(btreeStartOffset.add(fileTypeAdjustment));
416
- this.readCompletely(buffer);
417
- const b2 = Buffer.alloc(2);
418
- b2[0] = 0xff80;
419
- b2[1] = 0xff81;
420
- // ensure apples to apples comparison
421
- while ((buffer[0] === b2[0] && buffer[1] === b2[0] && !descTree) ||
422
- (buffer[0] === b2[1] && buffer[1] === b2[1] && descTree)) {
423
- // get the rest of the data
424
- let len;
425
- if (this._pstFileType == PSTFile.PST_TYPE_ANSI) {
426
- len = 496;
427
- }
428
- else if (this._pstFileType == PSTFile.PST_TYPE_2013_UNICODE) {
429
- len = 4056;
430
- }
431
- else {
432
- len = 488;
433
- }
434
- const branchNodeItems = Buffer.alloc(len);
435
- this.seek(btreeStartOffset);
436
- this.readCompletely(branchNodeItems);
437
- // console.log('PSTFile::findBtreeItem btreeStartOffset = ' + btreeStartOffset);
438
- let numberOfItems = 0;
439
- if (this._pstFileType === PSTFile.PST_TYPE_2013_UNICODE) {
440
- const numberOfItemsBytes = Buffer.alloc(2);
441
- this.readCompletely(numberOfItemsBytes);
442
- numberOfItems = PSTUtil_class_1.PSTUtil.convertLittleEndianBytesToLong(numberOfItemsBytes).toNumber();
443
- this.readCompletely(numberOfItemsBytes);
444
- }
445
- else {
446
- numberOfItems = this.read();
447
- this.read(); // maxNumberOfItems
448
- }
449
- const itemSize = this.read(); // itemSize
450
- const levelsToLeaf = this.read();
451
- if (levelsToLeaf > 0) {
452
- let found = false;
453
- for (let x = 0; x < numberOfItems; x++) {
454
- if (this._pstFileType == PSTFile.PST_TYPE_ANSI) {
455
- const indexIdOfFirstChildNode = this.extractLEFileOffset(btreeStartOffset.add(x * 12));
456
- if (indexIdOfFirstChildNode > index) {
457
- // get the address for the child first node in this group
458
- btreeStartOffset = this.extractLEFileOffset(btreeStartOffset.add((x - 1) * 12 + 8));
459
- this.seek(btreeStartOffset.add(500));
460
- this.readCompletely(buffer);
461
- found = true;
462
- break;
463
- }
464
- }
465
- else {
466
- const indexIdOfFirstChildNode = this.extractLEFileOffset(btreeStartOffset.add(x * 24));
467
- if (indexIdOfFirstChildNode.greaterThan(index)) {
468
- // get the address for the child first node in this group
469
- btreeStartOffset = this.extractLEFileOffset(btreeStartOffset.add((x - 1) * 24 + 16));
470
- this.seek(btreeStartOffset.add(fileTypeAdjustment));
471
- this.readCompletely(buffer);
472
- found = true;
473
- break;
474
- }
475
- }
476
- }
477
- if (!found) {
478
- // it must be in the very last branch...
479
- if (this._pstFileType == PSTFile.PST_TYPE_ANSI) {
480
- btreeStartOffset = this.extractLEFileOffset(btreeStartOffset.add((numberOfItems - 1) * 12 + 8));
481
- this.seek(btreeStartOffset.add(500));
482
- this.readCompletely(buffer);
483
- }
484
- else {
485
- btreeStartOffset = this.extractLEFileOffset(btreeStartOffset.add((numberOfItems - 1) * 24 + 16));
486
- this.seek(btreeStartOffset.add(fileTypeAdjustment));
487
- this.readCompletely(buffer);
488
- }
489
- }
490
- }
491
- else {
492
- // we are at the bottom of the tree...
493
- // we want to get our file offset!
494
- for (let x = 0; x < numberOfItems; x++) {
495
- if (this._pstFileType == PSTFile.PST_TYPE_ANSI) {
496
- if (descTree) {
497
- // The 32-bit descriptor index b-tree leaf node item
498
- buffer = Buffer.alloc(4);
499
- this.seek(btreeStartOffset.add(x * 16));
500
- this.readCompletely(buffer);
501
- if (PSTUtil_class_1.PSTUtil.convertLittleEndianBytesToLong(buffer).equals(index)) {
502
- // give me the offset index please!
503
- buffer = Buffer.alloc(16);
504
- this.seek(btreeStartOffset.add(x * 16));
505
- this.readCompletely(buffer);
506
- return buffer;
507
- }
508
- }
509
- else {
510
- // The 32-bit (file) offset index item
511
- const indexIdOfFirstChildNode = this.extractLEFileOffset(btreeStartOffset.add(x * 12));
512
- if (indexIdOfFirstChildNode.equals(index)) {
513
- // we found it!
514
- buffer = Buffer.alloc(12);
515
- this.seek(btreeStartOffset.add(x * 12));
516
- this.readCompletely(buffer);
517
- // console.log('PSTFile::findBtreeItem ' + index.toString() + ' found!');
518
- return buffer;
519
- }
520
- }
521
- }
522
- else {
523
- if (descTree) {
524
- // The 64-bit descriptor index b-tree leaf node item
525
- buffer = Buffer.alloc(4);
526
- this.seek(btreeStartOffset.add(x * 32));
527
- this.readCompletely(buffer);
528
- if (PSTUtil_class_1.PSTUtil.convertLittleEndianBytesToLong(buffer).equals(index)) {
529
- // give me the offset index please!
530
- buffer = Buffer.alloc(32);
531
- this.seek(btreeStartOffset.add(x * 32));
532
- this.readCompletely(buffer);
533
- // console.log('PSTFile::findBtreeItem ' + index.toString() + ' found!');
534
- return buffer;
535
- }
536
- }
537
- else {
538
- // The 64-bit (file) offset index item
539
- const indexIdOfFirstChildNode = this.extractLEFileOffset(btreeStartOffset.add(x * 24));
540
- if (indexIdOfFirstChildNode.equals(index)) {
541
- // we found it
542
- buffer = Buffer.alloc(24);
543
- this.seek(btreeStartOffset.add(x * 24));
544
- this.readCompletely(buffer);
545
- // console.log('PSTFile::findBtreeItem ' + index.toString() + ' found!');
546
- return buffer;
547
- }
548
- }
549
- }
550
- }
551
- throw new Error('PSTFile::findBtreeItem Unable to find ' +
552
- index +
553
- ' is desc: ' +
554
- descTree);
555
- }
556
- }
557
- throw new Error('PSTFile::findBtreeItem Unable to find node: ' +
558
- index +
559
- ' is desc: ' +
560
- descTree);
561
- }
562
- /**
563
- * Get a descriptor index node in the b-tree
564
- * @param {long} id
565
- * @returns {DescriptorIndexNode}
566
- * @memberof PSTFile
567
- */
568
- getDescriptorIndexNode(id) {
569
- // console.log('PSTFile::getDescriptorIndexNode ' + id.toString())
570
- return new DescriptorIndexNode_class_1.DescriptorIndexNode(this.findBtreeItem(id, true), this._pstFileType);
571
- }
572
- /**
573
- * Get an offset index node in the b-tree
574
- * @param {long} id
575
- * @returns {OffsetIndexItem}
576
- * @memberof PSTFile
577
- */
578
- getOffsetIndexNode(id) {
579
- return new OffsetIndexItem_class_1.OffsetIndexItem(this.findBtreeItem(id, false), this._pstFileType);
580
- }
581
- getPSTDescriptorItems(arg) {
582
- let inputStream = arg;
583
- if (typeof arg === 'object' && arg.hasOwnProperty('low')) {
584
- inputStream = this.readLeaf(arg);
585
- }
586
- // make sure the signature is correct
587
- inputStream.seek(long_1.default.ZERO);
588
- const sig = inputStream.read();
589
- if (sig != 0x2) {
590
- throw new Error('PSTFile::getPSTDescriptorItems Unable to process descriptor node, bad signature: ' +
591
- sig);
592
- }
593
- const output = new Map();
594
- const numberOfItems = inputStream.seekAndReadLong(long_1.default.fromValue(2), 2);
595
- let offset;
596
- if (this._pstFileType === PSTFile.PST_TYPE_ANSI) {
597
- offset = 4;
598
- }
599
- else {
600
- offset = 8;
601
- }
602
- const data = Buffer.alloc(inputStream.length.toNumber());
603
- inputStream.seek(long_1.default.ZERO);
604
- inputStream.readCompletely(data);
605
- for (let x = 0; x < numberOfItems.toNumber(); x++) {
606
- const item = new PSTDescriptorItem_class_1.PSTDescriptorItem(data, offset, this);
607
- output.set(item.descriptorIdentifier, item);
608
- if (this._pstFileType === PSTFile.PST_TYPE_ANSI) {
609
- offset += 12;
610
- }
611
- else {
612
- offset += 24;
613
- }
614
- }
615
- return output;
616
- }
617
- /**
618
- * Build the children descriptor tree, used as a fallback when the nodes
619
- * that list file contents are broken.
620
- * @returns
621
- * @memberof PSTFile
622
- */
623
- getChildDescriptorTree() {
624
- if (!this.childrenDescriptorTree) {
625
- let btreeStartOffset = long_1.default.ZERO;
626
- if (this._pstFileType === PSTFile.PST_TYPE_ANSI) {
627
- btreeStartOffset = this.extractLEFileOffset(long_1.default.fromValue(188));
628
- }
629
- else {
630
- btreeStartOffset = this.extractLEFileOffset(long_1.default.fromValue(224));
631
- }
632
- this.childrenDescriptorTree = new Map();
633
- this.processDescriptorBTree(btreeStartOffset);
634
- }
635
- return this.childrenDescriptorTree;
636
- }
637
- /**
638
- * Recursively walk PST descriptor tree and create internal version.
639
- * @private
640
- * @param {long} btreeStartOffset
641
- * @memberof PSTFile
642
- */
643
- processDescriptorBTree(btreeStartOffset) {
644
- let fileTypeAdjustment;
645
- let temp = Buffer.alloc(2);
646
- if (this._pstFileType === PSTFile.PST_TYPE_ANSI) {
647
- fileTypeAdjustment = 500;
648
- }
649
- else if (this._pstFileType === PSTFile.PST_TYPE_2013_UNICODE) {
650
- fileTypeAdjustment = 0x1000 - 24;
651
- }
652
- else {
653
- fileTypeAdjustment = 496;
654
- }
655
- this.seek(btreeStartOffset.add(fileTypeAdjustment));
656
- this.readCompletely(temp);
657
- if (temp[0] == 129 && temp[1] == 129) {
658
- if (this._pstFileType === PSTFile.PST_TYPE_ANSI) {
659
- this.seek(btreeStartOffset.add(496));
660
- }
661
- else if (this._pstFileType === PSTFile.PST_TYPE_2013_UNICODE) {
662
- this.seek(btreeStartOffset.add(4056));
663
- }
664
- else {
665
- this.seek(btreeStartOffset.add(488));
666
- }
667
- let numberOfItems = 0;
668
- if (this._pstFileType === PSTFile.PST_TYPE_2013_UNICODE) {
669
- const numberOfItemsBytes = Buffer.alloc(2);
670
- this.readCompletely(numberOfItemsBytes);
671
- numberOfItems = PSTUtil_class_1.PSTUtil.convertLittleEndianBytesToLong(numberOfItemsBytes).toNumber();
672
- this.readCompletely(numberOfItemsBytes);
673
- const maxNumberOfItems = PSTUtil_class_1.PSTUtil.convertLittleEndianBytesToLong(numberOfItemsBytes).toNumber();
674
- }
675
- else {
676
- numberOfItems = this.read();
677
- this.read(); // maxNumberOfItems
678
- }
679
- this.read(); // itemSize
680
- const levelsToLeaf = this.read();
681
- if (levelsToLeaf > 0) {
682
- for (let x = 0; x < numberOfItems; x++) {
683
- if (this._pstFileType === PSTFile.PST_TYPE_ANSI) {
684
- const branchNodeItemStartIndex = btreeStartOffset.add(12 * x);
685
- const nextLevelStartsAt = this.extractLEFileOffset(branchNodeItemStartIndex.add(8));
686
- this.processDescriptorBTree(nextLevelStartsAt);
687
- }
688
- else {
689
- const branchNodeItemStartIndex = btreeStartOffset.add(24 * x);
690
- const nextLevelStartsAt = this.extractLEFileOffset(branchNodeItemStartIndex.add(16));
691
- this.processDescriptorBTree(nextLevelStartsAt);
692
- }
693
- }
694
- }
695
- else {
696
- for (let x = 0; x < numberOfItems; x++) {
697
- if (this._pstFileType === PSTFile.PST_TYPE_ANSI) {
698
- this.seek(btreeStartOffset.add(x * 16));
699
- temp = Buffer.alloc(16);
700
- this.readCompletely(temp);
701
- }
702
- else {
703
- this.seek(btreeStartOffset.add(x * 32));
704
- temp = Buffer.alloc(32);
705
- this.readCompletely(temp);
706
- }
707
- const tempNode = new DescriptorIndexNode_class_1.DescriptorIndexNode(temp, this._pstFileType);
708
- // we don't want to be children of ourselves...
709
- if (tempNode.parentDescriptorIndexIdentifier ==
710
- tempNode.descriptorIdentifier) {
711
- // skip!
712
- }
713
- else if (this.childrenDescriptorTree.has(tempNode.parentDescriptorIndexIdentifier)) {
714
- // add this entry to the existing list of children
715
- const children = this.childrenDescriptorTree.get(tempNode.parentDescriptorIndexIdentifier);
716
- if (!children) {
717
- throw new Error('PSTFile::processDescriptorBTree children is null');
718
- }
719
- children.push(tempNode);
720
- }
721
- else {
722
- // create a new entry and add this one to that
723
- const children = [];
724
- children.push(tempNode);
725
- this.childrenDescriptorTree.set(tempNode.parentDescriptorIndexIdentifier, children);
726
- }
727
- }
728
- }
729
- }
730
- else {
731
- throw new Error('PSTFile::processDescriptorBTree Unable to read descriptor node, is not a descriptor');
732
- }
733
- }
734
- /*
735
- Basic file functions.
736
- */
737
- /**
738
- * Read a single byte from the PST file.
739
- * @param {number} [position]
740
- * @returns {number}
741
- * @memberof PSTFile
742
- */
743
- read(position) {
744
- const pos = position ? position : this.position;
745
- const buffer = Buffer.alloc(1);
746
- const bytesRead = this.readSync(buffer, buffer.length, pos);
747
- this.position = position ? position + bytesRead : this.position + bytesRead;
748
- return buffer[0];
749
- }
750
- /**
751
- * Read a complete section from the file, storing in the supplied buffer.
752
- * @param {Buffer} buffer
753
- * @param {number} [position]
754
- * @returns
755
- * @memberof PSTFile
756
- */
757
- readCompletely(buffer, position) {
758
- const pos = position ? position : this.position;
759
- const bytesRead = this.readSync(buffer, buffer.length, pos);
760
- this.position = position ? position + bytesRead : this.position + bytesRead;
761
- }
762
- /**
763
- * Read from either file system, or in memory buffer.
764
- * @param {Buffer} buffer
765
- * @param {number} length
766
- * @param {number} position
767
- * @returns {number} of bytes read
768
- * @memberof PSTFile
769
- */
770
- readSync(buffer, length, position) {
771
- if (this.pstFD > 0) {
772
- // read from file system
773
- return fs.readSync(this.pstFD, buffer, 0, length, position);
774
- }
775
- else {
776
- // copy from in-memory buffer
777
- this.pstBuffer.copy(buffer, 0, position, position + length);
778
- return length;
779
- }
780
- }
781
- /**
782
- * Seek to a specific position in PST file.
783
- * @param {long} index
784
- * @memberof PSTFile
785
- */
786
- seek(index) {
787
- this.position = index.toNumber();
788
- }
789
- /**
790
- * JSON stringify the object properties.
791
- * @returns {string}
792
- * @memberof PSTFile
793
- */
794
- toJSON() {
795
- return this;
796
- }
797
- }
798
- exports.PSTFile = PSTFile;
799
- PSTFile.ENCRYPTION_TYPE_NONE = 0;
800
- PSTFile.ENCRYPTION_TYPE_COMPRESSIBLE = 1;
801
- PSTFile.MESSAGE_STORE_DESCRIPTOR_IDENTIFIER = 33;
802
- PSTFile.ROOT_FOLDER_DESCRIPTOR_IDENTIFIER = 290;
803
- PSTFile.PST_TYPE_ANSI = 14;
804
- PSTFile.PST_TYPE_ANSI_2 = 15;
805
- PSTFile.PST_TYPE_UNICODE = 23;
806
- PSTFile.PST_TYPE_2013_UNICODE = 36;
807
- PSTFile.PS_PUBLIC_STRINGS = 0;
808
- PSTFile.PS_INTERNET_HEADERS = 3;
809
- PSTFile.PSETID_Messaging = 7;
810
- PSTFile.PSETID_Note = 8;
811
- PSTFile.PSETID_PostRss = 9;
812
- PSTFile.PSETID_Task = 10;
813
- PSTFile.PSETID_UnifiedMessaging = 11;
814
- PSTFile.PS_MAPI = 12;
815
- PSTFile.PSETID_AirSync = 13;
816
- PSTFile.PSETID_Sharing = 14;
817
- // node tree maps
818
- PSTFile.nodeMap = new NodeMap_class_1.NodeMap();
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.PSTFile = void 0;
30
+ const fs = __importStar(require("fs"));
31
+ const long_1 = __importDefault(require("long"));
32
+ const DescriptorIndexNode_class_1 = require("./DescriptorIndexNode.class");
33
+ const OffsetIndexItem_class_1 = require("./OffsetIndexItem.class");
34
+ const PSTDescriptorItem_class_1 = require("./PSTDescriptorItem.class");
35
+ const PSTFolder_class_1 = require("./PSTFolder.class");
36
+ const PSTMessageStore_class_1 = require("./PSTMessageStore.class");
37
+ const PSTNodeInputStream_class_1 = require("./PSTNodeInputStream.class");
38
+ const PSTTableBC_class_1 = require("./PSTTableBC.class");
39
+ const PSTUtil_class_1 = require("./PSTUtil.class");
40
+ const NodeMap_class_1 = require("./NodeMap.class");
41
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
42
+ const uuidparse = require('uuid-parse');
43
+ class PSTFile {
44
+ get encryptionType() {
45
+ return this._encryptionType;
46
+ }
47
+ get pstFileType() {
48
+ return this._pstFileType;
49
+ }
50
+ get pstFilename() {
51
+ return this._pstFilename;
52
+ }
53
+ constructor(arg) {
54
+ this.guidMap = new Map([
55
+ ['00020329-0000-0000-C000-000000000046', 0],
56
+ ['00062008-0000-0000-C000-000000000046', 1],
57
+ ['00062004-0000-0000-C000-000000000046', 2],
58
+ ['00020386-0000-0000-C000-000000000046', 3],
59
+ ['00062002-0000-0000-C000-000000000046', 4],
60
+ ['6ED8DA90-450B-101B-98DA-00AA003F1305', 5],
61
+ ['0006200A-0000-0000-C000-000000000046', 6],
62
+ ['41F28F13-83F4-4114-A584-EEDB5A6B0BFF', 7],
63
+ ['0006200E-0000-0000-C000-000000000046', 8],
64
+ ['00062041-0000-0000-C000-000000000046', 9],
65
+ ['00062003-0000-0000-C000-000000000046', 10],
66
+ ['4442858E-A9E3-4E80-B900-317A210CC15B', 11],
67
+ ['00020328-0000-0000-C000-000000000046', 12],
68
+ ['71035549-0739-4DCB-9163-00F0580DBBDF', 13],
69
+ ['00062040-0000-0000-C000-000000000046', 14],
70
+ ]);
71
+ // the type of encryption the files uses
72
+ this._encryptionType = 0;
73
+ // type of file (e.g. ANSI)
74
+ this._pstFileType = 0;
75
+ this._pstFilename = '';
76
+ // b-tree
77
+ this.childrenDescriptorTree = null;
78
+ // in-memory file buffer (instead of filesystem)
79
+ this.pstBuffer = Buffer.alloc(0);
80
+ // position in file
81
+ this.position = 0;
82
+ if (arg instanceof Buffer) {
83
+ // use an in-memory buffer of PST
84
+ this.pstBuffer = arg;
85
+ this.pstFD = -1;
86
+ }
87
+ else {
88
+ // use PST in filesystem
89
+ this._pstFilename = arg;
90
+ this.pstFD = fs.openSync(this._pstFilename, 'r');
91
+ }
92
+ // confirm first 4 bytes are !BDN
93
+ const buffer = Buffer.alloc(514);
94
+ this.readSync(buffer, 514, 0);
95
+ const key = '!BDN';
96
+ if (buffer[0] != key.charCodeAt(0) ||
97
+ buffer[1] != key.charCodeAt(1) ||
98
+ buffer[2] != key.charCodeAt(2) ||
99
+ buffer[3] != key.charCodeAt(3)) {
100
+ throw new Error('PSTFile::open Invalid file header (expected: "!BDN"): ' + buffer);
101
+ }
102
+ // make sure we are using a supported version of a PST...
103
+ if (buffer[10] === PSTFile.PST_TYPE_ANSI_2) {
104
+ buffer[10] = PSTFile.PST_TYPE_ANSI;
105
+ }
106
+ if (buffer[10] !== PSTFile.PST_TYPE_ANSI &&
107
+ buffer[10] !== PSTFile.PST_TYPE_UNICODE &&
108
+ buffer[10] !== PSTFile.PST_TYPE_2013_UNICODE) {
109
+ throw new Error('PSTFile::open Unrecognised PST File version: ' + buffer[10]);
110
+ }
111
+ this._pstFileType = buffer[10];
112
+ // make sure no encryption
113
+ if (this._pstFileType === PSTFile.PST_TYPE_ANSI) {
114
+ this._encryptionType = buffer[461];
115
+ }
116
+ else {
117
+ this._encryptionType = buffer[513];
118
+ }
119
+ if (this._encryptionType === 0x02) {
120
+ throw new Error('PSTFile::open PST is encrypted');
121
+ }
122
+ // build out name to id map
123
+ this.processNameToIDMap();
124
+ }
125
+ /**
126
+ * Close the file.
127
+ * @memberof PSTFile
128
+ */
129
+ close() {
130
+ if (this.pstFD > 0) {
131
+ fs.closeSync(this.pstFD);
132
+ }
133
+ }
134
+ /**
135
+ * Process name to ID map.
136
+ * @private
137
+ * @memberof PSTFile
138
+ */
139
+ processNameToIDMap() {
140
+ const nameToIdMapDescriptorNode = this.getDescriptorIndexNode(long_1.default.fromNumber(97));
141
+ // get the descriptors if we have them
142
+ let localDescriptorItems = null;
143
+ if (nameToIdMapDescriptorNode.localDescriptorsOffsetIndexIdentifier.toNumber() !=
144
+ 0) {
145
+ localDescriptorItems = this.getPSTDescriptorItems(nameToIdMapDescriptorNode.localDescriptorsOffsetIndexIdentifier);
146
+ }
147
+ // process the map
148
+ const off = this.getOffsetIndexNode(nameToIdMapDescriptorNode.dataOffsetIndexIdentifier);
149
+ const nodein = new PSTNodeInputStream_class_1.PSTNodeInputStream(this, off);
150
+ const bcTable = new PSTTableBC_class_1.PSTTableBC(nodein);
151
+ const tableItems = bcTable.getItems();
152
+ // Get the guids
153
+ const guidEntry = tableItems.get(2);
154
+ if (!guidEntry) {
155
+ throw new Error('PSTFile::processNameToIDMap guidEntry is null');
156
+ }
157
+ const guids = this.getData(guidEntry, localDescriptorItems);
158
+ const nGuids = Math.trunc(guids.length / 16);
159
+ const guidIndexes = [];
160
+ let offset = 0;
161
+ for (let i = 0; i < nGuids; ++i) {
162
+ let leftQuad = PSTUtil_class_1.PSTUtil.convertLittleEndianBytesToLong(guids, offset, offset + 4);
163
+ leftQuad = leftQuad.shiftLeft(32);
164
+ let midQuad = PSTUtil_class_1.PSTUtil.convertLittleEndianBytesToLong(guids, offset + 4, offset + 6);
165
+ midQuad = midQuad.shiftLeft(16);
166
+ const rightQuad = PSTUtil_class_1.PSTUtil.convertLittleEndianBytesToLong(guids, offset + 6, offset + 8);
167
+ const mostSigBits = leftQuad.or(midQuad).or(rightQuad);
168
+ const leastSigBits = PSTUtil_class_1.PSTUtil.convertBigEndianBytesToLong(guids, offset + 8, offset + 16);
169
+ // weird that need to cast below to any to get tsc error to go away - why?
170
+ // see https://github.com/Microsoft/TypeScript/issues/6436
171
+ const mostBuffer = mostSigBits.toBytes();
172
+ const leastBuffer = leastSigBits.toBytes();
173
+ const arrUID = mostBuffer.concat(leastBuffer);
174
+ const strUID = uuidparse.unparse(arrUID).toUpperCase();
175
+ const guid = this.guidMap.get(strUID);
176
+ if (guid) {
177
+ guidIndexes[i] = guid;
178
+ }
179
+ else {
180
+ guidIndexes[i] = -1; // We don't know this guid
181
+ }
182
+ // console.log('PSTFile:: processNameToIdMap idx: ' + i + ', ' + strUID + ', ' + guidIndexes[i]);
183
+ offset += 16;
184
+ }
185
+ // if we have a reference to an internal descriptor
186
+ const mapEntries = tableItems.get(3);
187
+ if (!mapEntries) {
188
+ throw new Error('PSTFile::processNameToIDMap mapEntries is null');
189
+ }
190
+ const nameToIdByte = this.getData(mapEntries, localDescriptorItems);
191
+ const stringMapEntries = tableItems.get(4);
192
+ if (!stringMapEntries) {
193
+ throw new Error('PSTFile::processNameToIDMap stringMapEntries is null');
194
+ }
195
+ const stringNameToIdByte = this.getData(stringMapEntries, localDescriptorItems);
196
+ // process the entries
197
+ for (let x = 0; x + 8 < nameToIdByte.length; x += 8) {
198
+ const key = PSTUtil_class_1.PSTUtil.convertLittleEndianBytesToLong(nameToIdByte, x, x + 4).toNumber();
199
+ let guid = PSTUtil_class_1.PSTUtil.convertLittleEndianBytesToLong(nameToIdByte, x + 4, x + 6).toNumber();
200
+ let propId = PSTUtil_class_1.PSTUtil.convertLittleEndianBytesToLong(nameToIdByte, x + 6, x + 8).toNumber();
201
+ if ((guid & 0x0001) == 0) {
202
+ // identifier is numeric
203
+ propId += 0x8000;
204
+ guid >>= 1;
205
+ let guidIndex;
206
+ if (guid == 1) {
207
+ guidIndex = PSTFile.PS_MAPI;
208
+ }
209
+ else if (guid == 2) {
210
+ guidIndex = PSTFile.PS_PUBLIC_STRINGS;
211
+ }
212
+ else {
213
+ guidIndex = guidIndexes[guid - 3];
214
+ }
215
+ PSTFile.nodeMap.setId(key, propId, guidIndex);
216
+ }
217
+ else {
218
+ // identifier is a string
219
+ // key is byte offset into the String stream in which the string name of the property is stored.
220
+ const len = PSTUtil_class_1.PSTUtil.convertLittleEndianBytesToLong(stringNameToIdByte, key, key + 4).toNumber();
221
+ const keyByteValue = Buffer.alloc(len);
222
+ PSTUtil_class_1.PSTUtil.arraycopy(stringNameToIdByte, key + 4, keyByteValue, 0, keyByteValue.length);
223
+ propId += 0x8000;
224
+ PSTFile.nodeMap.setId(keyByteValue.toString('utf16le').replace(/\0/g, ''), propId);
225
+ }
226
+ }
227
+ }
228
+ /**
229
+ * Get data from a descriptor and store in buffer.
230
+ * @private
231
+ * @param {PSTTableItem} item
232
+ * @param {Map<number, PSTDescriptorItem>} localDescriptorItems
233
+ * @returns {Buffer}
234
+ * @memberof PSTFile
235
+ */
236
+ getData(item, localDescriptorItems) {
237
+ if (item.data.length != 0) {
238
+ return item.data;
239
+ }
240
+ if (localDescriptorItems == null) {
241
+ throw new Error('PSTFile::getData External reference but no localDescriptorItems in PSTFile.getData()');
242
+ }
243
+ if (item.entryValueType != 0x0102) {
244
+ throw new Error('PSTFile::getData Attempting to get non-binary data in PSTFile.getData()');
245
+ }
246
+ const mapDescriptorItem = localDescriptorItems.get(item.entryValueReference);
247
+ if (mapDescriptorItem == null) {
248
+ throw new Error('PSTFile::getData Descriptor not found: ' + item.entryValueReference);
249
+ }
250
+ return mapDescriptorItem.getData();
251
+ }
252
+ /**
253
+ * Get name to ID map item.
254
+ * @param {number} key
255
+ * @param {number} idx
256
+ * @returns {number}
257
+ * @memberof PSTFile
258
+ */
259
+ getNameToIdMapItem(key, idx) {
260
+ return PSTFile.nodeMap.getId(key, idx);
261
+ }
262
+ /**
263
+ * Get public string to id map item.
264
+ * @static
265
+ * @param {string} key
266
+ * @returns {number}
267
+ * @memberof PSTFile
268
+ */
269
+ static getPublicStringToIdMapItem(key) {
270
+ return PSTFile.nodeMap.getId(key);
271
+ }
272
+ /**
273
+ * Get property name from id.
274
+ * @static
275
+ * @param {number} propertyId
276
+ * @param {boolean} bNamed
277
+ * @returns {string}
278
+ * @memberof PSTFile
279
+ */
280
+ static getPropertyName(propertyId, bNamed) {
281
+ return PSTUtil_class_1.PSTUtil.propertyName.get(propertyId);
282
+ }
283
+ /**
284
+ * Get name to id map key.
285
+ * @static
286
+ * @param {number} propId
287
+ * @returns {long}
288
+ * @memberof PSTFile
289
+ */
290
+ static getNameToIdMapKey(propId) {
291
+ return PSTFile.nodeMap.getNumericName(propId);
292
+ }
293
+ /**
294
+ * Get the message store of the PST file. Note that this doesn't really
295
+ * have much information, better to look under the root folder.
296
+ * @returns {PSTMessageStore}
297
+ * @memberof PSTFile
298
+ */
299
+ getMessageStore() {
300
+ const messageStoreDescriptor = this.getDescriptorIndexNode(long_1.default.fromNumber(PSTFile.MESSAGE_STORE_DESCRIPTOR_IDENTIFIER));
301
+ return new PSTMessageStore_class_1.PSTMessageStore(this, messageStoreDescriptor);
302
+ }
303
+ /**
304
+ * Get the root folder for the PST file
305
+ * @returns {PSTFolder}
306
+ * @memberof PSTFile
307
+ */
308
+ getRootFolder() {
309
+ const rootFolderDescriptor = this.getDescriptorIndexNode(long_1.default.fromValue(PSTFile.ROOT_FOLDER_DESCRIPTOR_IDENTIFIER));
310
+ const output = new PSTFolder_class_1.PSTFolder(this, rootFolderDescriptor);
311
+ return output;
312
+ }
313
+ /**
314
+ * Read a leaf in the b-tree.
315
+ * @param {long} bid
316
+ * @returns {PSTNodeInputStream}
317
+ * @memberof PSTFile
318
+ */
319
+ readLeaf(bid) {
320
+ // get the index node for the descriptor index
321
+ const offsetItem = this.getOffsetIndexNode(bid);
322
+ return new PSTNodeInputStream_class_1.PSTNodeInputStream(this, offsetItem);
323
+ }
324
+ /**
325
+ * Read the size of the specified leaf.
326
+ * @param {long} bid
327
+ * @returns {number}
328
+ * @memberof PSTFile
329
+ */
330
+ getLeafSize(bid) {
331
+ const offsetItem = this.getOffsetIndexNode(bid);
332
+ // Internal block?
333
+ if ((offsetItem.indexIdentifier.toNumber() & 0x02) == 0) {
334
+ // No, return the raw size
335
+ return offsetItem.size;
336
+ }
337
+ // we only need the first 8 bytes
338
+ const data = Buffer.alloc(8);
339
+ this.seek(offsetItem.fileOffset);
340
+ this.readCompletely(data);
341
+ // we are an array, get the sum of the sizes...
342
+ return PSTUtil_class_1.PSTUtil.convertLittleEndianBytesToLong(data, 4, 8).toNumber();
343
+ }
344
+ /**
345
+ * Get file offset, which is sorted in 8 little endian bytes
346
+ * @private
347
+ * @param {long} startOffset
348
+ * @returns {long}
349
+ * @memberof PSTFile
350
+ */
351
+ extractLEFileOffset(startOffset) {
352
+ let offset = long_1.default.ZERO;
353
+ if (this._pstFileType == PSTFile.PST_TYPE_ANSI) {
354
+ this.seek(startOffset);
355
+ const buffer = Buffer.alloc(4);
356
+ this.readCompletely(buffer);
357
+ offset = offset.or(buffer[3] & 0xff);
358
+ offset = offset.shiftLeft(8);
359
+ offset = offset.or(buffer[2] & 0xff);
360
+ offset = offset.shiftLeft(8);
361
+ offset = offset.or(buffer[1] & 0xff);
362
+ offset = offset.shiftLeft(8);
363
+ offset = offset.or(buffer[0] & 0xff);
364
+ }
365
+ else {
366
+ this.seek(startOffset);
367
+ const buffer = Buffer.alloc(8);
368
+ this.readCompletely(buffer);
369
+ offset = offset.or(buffer[7] & 0xff);
370
+ let tmpLongValue;
371
+ for (let x = 6; x >= 0; x--) {
372
+ offset = offset.shiftLeft(8);
373
+ tmpLongValue = buffer[x] & 0xff;
374
+ offset = offset.or(tmpLongValue);
375
+ }
376
+ }
377
+ return offset;
378
+ }
379
+ /**
380
+ * Navigate PST B-tree and find a specific item.
381
+ * @private
382
+ * @param {long} index
383
+ * @param {boolean} descTree
384
+ * @returns {Buffer}
385
+ * @memberof PSTFile
386
+ */
387
+ findBtreeItem(index, descTree) {
388
+ let btreeStartOffset;
389
+ let fileTypeAdjustment;
390
+ // first find the starting point for the offset index
391
+ if (this._pstFileType === PSTFile.PST_TYPE_ANSI) {
392
+ btreeStartOffset = this.extractLEFileOffset(long_1.default.fromValue(196));
393
+ if (descTree) {
394
+ btreeStartOffset = this.extractLEFileOffset(long_1.default.fromValue(188));
395
+ }
396
+ }
397
+ else {
398
+ btreeStartOffset = this.extractLEFileOffset(long_1.default.fromValue(240));
399
+ if (descTree) {
400
+ btreeStartOffset = this.extractLEFileOffset(long_1.default.fromValue(224));
401
+ }
402
+ }
403
+ // okay, what we want to do is navigate the tree until you reach the bottom....
404
+ // try and read the index b-tree
405
+ let buffer = Buffer.alloc(2);
406
+ if (this._pstFileType === PSTFile.PST_TYPE_ANSI) {
407
+ fileTypeAdjustment = 500;
408
+ }
409
+ else if (this._pstFileType === PSTFile.PST_TYPE_2013_UNICODE) {
410
+ fileTypeAdjustment = 0x1000 - 24;
411
+ }
412
+ else {
413
+ fileTypeAdjustment = 496;
414
+ }
415
+ this.seek(btreeStartOffset.add(fileTypeAdjustment));
416
+ this.readCompletely(buffer);
417
+ const b2 = Buffer.alloc(2);
418
+ b2[0] = 0xff80;
419
+ b2[1] = 0xff81;
420
+ // ensure apples to apples comparison
421
+ while ((buffer[0] === b2[0] && buffer[1] === b2[0] && !descTree) ||
422
+ (buffer[0] === b2[1] && buffer[1] === b2[1] && descTree)) {
423
+ // get the rest of the data
424
+ let len;
425
+ if (this._pstFileType == PSTFile.PST_TYPE_ANSI) {
426
+ len = 496;
427
+ }
428
+ else if (this._pstFileType == PSTFile.PST_TYPE_2013_UNICODE) {
429
+ len = 4056;
430
+ }
431
+ else {
432
+ len = 488;
433
+ }
434
+ const branchNodeItems = Buffer.alloc(len);
435
+ this.seek(btreeStartOffset);
436
+ this.readCompletely(branchNodeItems);
437
+ // console.log('PSTFile::findBtreeItem btreeStartOffset = ' + btreeStartOffset);
438
+ let numberOfItems = 0;
439
+ if (this._pstFileType === PSTFile.PST_TYPE_2013_UNICODE) {
440
+ const numberOfItemsBytes = Buffer.alloc(2);
441
+ this.readCompletely(numberOfItemsBytes);
442
+ numberOfItems = PSTUtil_class_1.PSTUtil.convertLittleEndianBytesToLong(numberOfItemsBytes).toNumber();
443
+ this.readCompletely(numberOfItemsBytes);
444
+ }
445
+ else {
446
+ numberOfItems = this.read();
447
+ this.read(); // maxNumberOfItems
448
+ }
449
+ const itemSize = this.read(); // itemSize
450
+ const levelsToLeaf = this.read();
451
+ if (levelsToLeaf > 0) {
452
+ let found = false;
453
+ for (let x = 0; x < numberOfItems; x++) {
454
+ if (this._pstFileType == PSTFile.PST_TYPE_ANSI) {
455
+ const indexIdOfFirstChildNode = this.extractLEFileOffset(btreeStartOffset.add(x * 12));
456
+ if (indexIdOfFirstChildNode > index) {
457
+ // get the address for the child first node in this group
458
+ btreeStartOffset = this.extractLEFileOffset(btreeStartOffset.add((x - 1) * 12 + 8));
459
+ this.seek(btreeStartOffset.add(500));
460
+ this.readCompletely(buffer);
461
+ found = true;
462
+ break;
463
+ }
464
+ }
465
+ else {
466
+ const indexIdOfFirstChildNode = this.extractLEFileOffset(btreeStartOffset.add(x * 24));
467
+ if (indexIdOfFirstChildNode.greaterThan(index)) {
468
+ // get the address for the child first node in this group
469
+ btreeStartOffset = this.extractLEFileOffset(btreeStartOffset.add((x - 1) * 24 + 16));
470
+ this.seek(btreeStartOffset.add(fileTypeAdjustment));
471
+ this.readCompletely(buffer);
472
+ found = true;
473
+ break;
474
+ }
475
+ }
476
+ }
477
+ if (!found) {
478
+ // it must be in the very last branch...
479
+ if (this._pstFileType == PSTFile.PST_TYPE_ANSI) {
480
+ btreeStartOffset = this.extractLEFileOffset(btreeStartOffset.add((numberOfItems - 1) * 12 + 8));
481
+ this.seek(btreeStartOffset.add(500));
482
+ this.readCompletely(buffer);
483
+ }
484
+ else {
485
+ btreeStartOffset = this.extractLEFileOffset(btreeStartOffset.add((numberOfItems - 1) * 24 + 16));
486
+ this.seek(btreeStartOffset.add(fileTypeAdjustment));
487
+ this.readCompletely(buffer);
488
+ }
489
+ }
490
+ }
491
+ else {
492
+ // we are at the bottom of the tree...
493
+ // we want to get our file offset!
494
+ for (let x = 0; x < numberOfItems; x++) {
495
+ if (this._pstFileType == PSTFile.PST_TYPE_ANSI) {
496
+ if (descTree) {
497
+ // The 32-bit descriptor index b-tree leaf node item
498
+ buffer = Buffer.alloc(4);
499
+ this.seek(btreeStartOffset.add(x * 16));
500
+ this.readCompletely(buffer);
501
+ if (PSTUtil_class_1.PSTUtil.convertLittleEndianBytesToLong(buffer).equals(index)) {
502
+ // give me the offset index please!
503
+ buffer = Buffer.alloc(16);
504
+ this.seek(btreeStartOffset.add(x * 16));
505
+ this.readCompletely(buffer);
506
+ return buffer;
507
+ }
508
+ }
509
+ else {
510
+ // The 32-bit (file) offset index item
511
+ const indexIdOfFirstChildNode = this.extractLEFileOffset(btreeStartOffset.add(x * 12));
512
+ if (indexIdOfFirstChildNode.equals(index)) {
513
+ // we found it!
514
+ buffer = Buffer.alloc(12);
515
+ this.seek(btreeStartOffset.add(x * 12));
516
+ this.readCompletely(buffer);
517
+ // console.log('PSTFile::findBtreeItem ' + index.toString() + ' found!');
518
+ return buffer;
519
+ }
520
+ }
521
+ }
522
+ else {
523
+ if (descTree) {
524
+ // The 64-bit descriptor index b-tree leaf node item
525
+ buffer = Buffer.alloc(4);
526
+ this.seek(btreeStartOffset.add(x * 32));
527
+ this.readCompletely(buffer);
528
+ if (PSTUtil_class_1.PSTUtil.convertLittleEndianBytesToLong(buffer).equals(index)) {
529
+ // give me the offset index please!
530
+ buffer = Buffer.alloc(32);
531
+ this.seek(btreeStartOffset.add(x * 32));
532
+ this.readCompletely(buffer);
533
+ // console.log('PSTFile::findBtreeItem ' + index.toString() + ' found!');
534
+ return buffer;
535
+ }
536
+ }
537
+ else {
538
+ // The 64-bit (file) offset index item
539
+ const indexIdOfFirstChildNode = this.extractLEFileOffset(btreeStartOffset.add(x * 24));
540
+ if (indexIdOfFirstChildNode.equals(index)) {
541
+ // we found it
542
+ buffer = Buffer.alloc(24);
543
+ this.seek(btreeStartOffset.add(x * 24));
544
+ this.readCompletely(buffer);
545
+ // console.log('PSTFile::findBtreeItem ' + index.toString() + ' found!');
546
+ return buffer;
547
+ }
548
+ }
549
+ }
550
+ }
551
+ throw new Error('PSTFile::findBtreeItem Unable to find ' +
552
+ index +
553
+ ' is desc: ' +
554
+ descTree);
555
+ }
556
+ }
557
+ throw new Error('PSTFile::findBtreeItem Unable to find node: ' +
558
+ index +
559
+ ' is desc: ' +
560
+ descTree);
561
+ }
562
+ /**
563
+ * Get a descriptor index node in the b-tree
564
+ * @param {long} id
565
+ * @returns {DescriptorIndexNode}
566
+ * @memberof PSTFile
567
+ */
568
+ getDescriptorIndexNode(id) {
569
+ // console.log('PSTFile::getDescriptorIndexNode ' + id.toString())
570
+ return new DescriptorIndexNode_class_1.DescriptorIndexNode(this.findBtreeItem(id, true), this._pstFileType);
571
+ }
572
+ /**
573
+ * Get an offset index node in the b-tree
574
+ * @param {long} id
575
+ * @returns {OffsetIndexItem}
576
+ * @memberof PSTFile
577
+ */
578
+ getOffsetIndexNode(id) {
579
+ return new OffsetIndexItem_class_1.OffsetIndexItem(this.findBtreeItem(id, false), this._pstFileType);
580
+ }
581
+ getPSTDescriptorItems(arg) {
582
+ let inputStream = arg;
583
+ if (typeof arg === 'object' && arg.hasOwnProperty('low')) {
584
+ inputStream = this.readLeaf(arg);
585
+ }
586
+ // make sure the signature is correct
587
+ inputStream.seek(long_1.default.ZERO);
588
+ const sig = inputStream.read();
589
+ if (sig != 0x2) {
590
+ throw new Error('PSTFile::getPSTDescriptorItems Unable to process descriptor node, bad signature: ' +
591
+ sig);
592
+ }
593
+ const output = new Map();
594
+ const numberOfItems = inputStream.seekAndReadLong(long_1.default.fromValue(2), 2);
595
+ let offset;
596
+ if (this._pstFileType === PSTFile.PST_TYPE_ANSI) {
597
+ offset = 4;
598
+ }
599
+ else {
600
+ offset = 8;
601
+ }
602
+ const data = Buffer.alloc(inputStream.length.toNumber());
603
+ inputStream.seek(long_1.default.ZERO);
604
+ inputStream.readCompletely(data);
605
+ for (let x = 0; x < numberOfItems.toNumber(); x++) {
606
+ const item = new PSTDescriptorItem_class_1.PSTDescriptorItem(data, offset, this);
607
+ output.set(item.descriptorIdentifier, item);
608
+ if (this._pstFileType === PSTFile.PST_TYPE_ANSI) {
609
+ offset += 12;
610
+ }
611
+ else {
612
+ offset += 24;
613
+ }
614
+ }
615
+ return output;
616
+ }
617
+ /**
618
+ * Build the children descriptor tree, used as a fallback when the nodes
619
+ * that list file contents are broken.
620
+ * @returns
621
+ * @memberof PSTFile
622
+ */
623
+ getChildDescriptorTree() {
624
+ if (!this.childrenDescriptorTree) {
625
+ let btreeStartOffset = long_1.default.ZERO;
626
+ if (this._pstFileType === PSTFile.PST_TYPE_ANSI) {
627
+ btreeStartOffset = this.extractLEFileOffset(long_1.default.fromValue(188));
628
+ }
629
+ else {
630
+ btreeStartOffset = this.extractLEFileOffset(long_1.default.fromValue(224));
631
+ }
632
+ this.childrenDescriptorTree = new Map();
633
+ this.processDescriptorBTree(btreeStartOffset);
634
+ }
635
+ return this.childrenDescriptorTree;
636
+ }
637
+ /**
638
+ * Recursively walk PST descriptor tree and create internal version.
639
+ * @private
640
+ * @param {long} btreeStartOffset
641
+ * @memberof PSTFile
642
+ */
643
+ processDescriptorBTree(btreeStartOffset) {
644
+ let fileTypeAdjustment;
645
+ let temp = Buffer.alloc(2);
646
+ if (this._pstFileType === PSTFile.PST_TYPE_ANSI) {
647
+ fileTypeAdjustment = 500;
648
+ }
649
+ else if (this._pstFileType === PSTFile.PST_TYPE_2013_UNICODE) {
650
+ fileTypeAdjustment = 0x1000 - 24;
651
+ }
652
+ else {
653
+ fileTypeAdjustment = 496;
654
+ }
655
+ this.seek(btreeStartOffset.add(fileTypeAdjustment));
656
+ this.readCompletely(temp);
657
+ if (temp[0] == 129 && temp[1] == 129) {
658
+ if (this._pstFileType === PSTFile.PST_TYPE_ANSI) {
659
+ this.seek(btreeStartOffset.add(496));
660
+ }
661
+ else if (this._pstFileType === PSTFile.PST_TYPE_2013_UNICODE) {
662
+ this.seek(btreeStartOffset.add(4056));
663
+ }
664
+ else {
665
+ this.seek(btreeStartOffset.add(488));
666
+ }
667
+ let numberOfItems = 0;
668
+ if (this._pstFileType === PSTFile.PST_TYPE_2013_UNICODE) {
669
+ const numberOfItemsBytes = Buffer.alloc(2);
670
+ this.readCompletely(numberOfItemsBytes);
671
+ numberOfItems = PSTUtil_class_1.PSTUtil.convertLittleEndianBytesToLong(numberOfItemsBytes).toNumber();
672
+ this.readCompletely(numberOfItemsBytes);
673
+ const maxNumberOfItems = PSTUtil_class_1.PSTUtil.convertLittleEndianBytesToLong(numberOfItemsBytes).toNumber();
674
+ }
675
+ else {
676
+ numberOfItems = this.read();
677
+ this.read(); // maxNumberOfItems
678
+ }
679
+ this.read(); // itemSize
680
+ const levelsToLeaf = this.read();
681
+ if (levelsToLeaf > 0) {
682
+ for (let x = 0; x < numberOfItems; x++) {
683
+ if (this._pstFileType === PSTFile.PST_TYPE_ANSI) {
684
+ const branchNodeItemStartIndex = btreeStartOffset.add(12 * x);
685
+ const nextLevelStartsAt = this.extractLEFileOffset(branchNodeItemStartIndex.add(8));
686
+ this.processDescriptorBTree(nextLevelStartsAt);
687
+ }
688
+ else {
689
+ const branchNodeItemStartIndex = btreeStartOffset.add(24 * x);
690
+ const nextLevelStartsAt = this.extractLEFileOffset(branchNodeItemStartIndex.add(16));
691
+ this.processDescriptorBTree(nextLevelStartsAt);
692
+ }
693
+ }
694
+ }
695
+ else {
696
+ for (let x = 0; x < numberOfItems; x++) {
697
+ if (this._pstFileType === PSTFile.PST_TYPE_ANSI) {
698
+ this.seek(btreeStartOffset.add(x * 16));
699
+ temp = Buffer.alloc(16);
700
+ this.readCompletely(temp);
701
+ }
702
+ else {
703
+ this.seek(btreeStartOffset.add(x * 32));
704
+ temp = Buffer.alloc(32);
705
+ this.readCompletely(temp);
706
+ }
707
+ const tempNode = new DescriptorIndexNode_class_1.DescriptorIndexNode(temp, this._pstFileType);
708
+ // we don't want to be children of ourselves...
709
+ if (tempNode.parentDescriptorIndexIdentifier ==
710
+ tempNode.descriptorIdentifier) {
711
+ // skip!
712
+ }
713
+ else if (this.childrenDescriptorTree.has(tempNode.parentDescriptorIndexIdentifier)) {
714
+ // add this entry to the existing list of children
715
+ const children = this.childrenDescriptorTree.get(tempNode.parentDescriptorIndexIdentifier);
716
+ if (!children) {
717
+ throw new Error('PSTFile::processDescriptorBTree children is null');
718
+ }
719
+ children.push(tempNode);
720
+ }
721
+ else {
722
+ // create a new entry and add this one to that
723
+ const children = [];
724
+ children.push(tempNode);
725
+ this.childrenDescriptorTree.set(tempNode.parentDescriptorIndexIdentifier, children);
726
+ }
727
+ }
728
+ }
729
+ }
730
+ else {
731
+ throw new Error('PSTFile::processDescriptorBTree Unable to read descriptor node, is not a descriptor');
732
+ }
733
+ }
734
+ /*
735
+ Basic file functions.
736
+ */
737
+ /**
738
+ * Read a single byte from the PST file.
739
+ * @param {number} [position]
740
+ * @returns {number}
741
+ * @memberof PSTFile
742
+ */
743
+ read(position) {
744
+ const pos = position ? position : this.position;
745
+ const buffer = Buffer.alloc(1);
746
+ const bytesRead = this.readSync(buffer, buffer.length, pos);
747
+ this.position = position ? position + bytesRead : this.position + bytesRead;
748
+ return buffer[0];
749
+ }
750
+ /**
751
+ * Read a complete section from the file, storing in the supplied buffer.
752
+ * @param {Buffer} buffer
753
+ * @param {number} [position]
754
+ * @returns
755
+ * @memberof PSTFile
756
+ */
757
+ readCompletely(buffer, position) {
758
+ const pos = position ? position : this.position;
759
+ const bytesRead = this.readSync(buffer, buffer.length, pos);
760
+ this.position = position ? position + bytesRead : this.position + bytesRead;
761
+ }
762
+ /**
763
+ * Read from either file system, or in memory buffer.
764
+ * @param {Buffer} buffer
765
+ * @param {number} length
766
+ * @param {number} position
767
+ * @returns {number} of bytes read
768
+ * @memberof PSTFile
769
+ */
770
+ readSync(buffer, length, position) {
771
+ if (this.pstFD > 0) {
772
+ // read from file system
773
+ return fs.readSync(this.pstFD, buffer, 0, length, position);
774
+ }
775
+ else {
776
+ // copy from in-memory buffer
777
+ this.pstBuffer.copy(buffer, 0, position, position + length);
778
+ return length;
779
+ }
780
+ }
781
+ /**
782
+ * Seek to a specific position in PST file.
783
+ * @param {long} index
784
+ * @memberof PSTFile
785
+ */
786
+ seek(index) {
787
+ this.position = index.toNumber();
788
+ }
789
+ /**
790
+ * JSON stringify the object properties.
791
+ * @returns {string}
792
+ * @memberof PSTFile
793
+ */
794
+ toJSON() {
795
+ return this;
796
+ }
797
+ }
798
+ exports.PSTFile = PSTFile;
799
+ PSTFile.ENCRYPTION_TYPE_NONE = 0;
800
+ PSTFile.ENCRYPTION_TYPE_COMPRESSIBLE = 1;
801
+ PSTFile.MESSAGE_STORE_DESCRIPTOR_IDENTIFIER = 33;
802
+ PSTFile.ROOT_FOLDER_DESCRIPTOR_IDENTIFIER = 290;
803
+ PSTFile.PST_TYPE_ANSI = 14;
804
+ PSTFile.PST_TYPE_ANSI_2 = 15;
805
+ PSTFile.PST_TYPE_UNICODE = 23;
806
+ PSTFile.PST_TYPE_2013_UNICODE = 36;
807
+ PSTFile.PS_PUBLIC_STRINGS = 0;
808
+ PSTFile.PS_INTERNET_HEADERS = 3;
809
+ PSTFile.PSETID_Messaging = 7;
810
+ PSTFile.PSETID_Note = 8;
811
+ PSTFile.PSETID_PostRss = 9;
812
+ PSTFile.PSETID_Task = 10;
813
+ PSTFile.PSETID_UnifiedMessaging = 11;
814
+ PSTFile.PS_MAPI = 12;
815
+ PSTFile.PSETID_AirSync = 13;
816
+ PSTFile.PSETID_Sharing = 14;
817
+ // node tree maps
818
+ PSTFile.nodeMap = new NodeMap_class_1.NodeMap();