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