private void Parse(PstFileReader reader, uint offset) { reader.BaseStream.Position = offset; uint unknown1 = reader.ReadUInt32(); byte[] byteTable = reader.ReadBytes(496); type = reader.ReadUInt16(); ushort unknown2 = reader.ReadUInt16(); this.offset = reader.ReadUInt32(); crc = reader.ReadUInt32(); for (int i = 0; i < 496; i++) { table[i] = (byteTable[i] | 127) == 255 ? true : false; table[i + 1] = (byteTable[i] | 191) == 255 ? true : false; table[i + 2] = (byteTable[i] | 223) == 255 ? true : false; table[i + 3] = (byteTable[i] | 239) == 255 ? true : false; table[i + 4] = (byteTable[i] | 247) == 255 ? true : false; table[i + 5] = (byteTable[i] | 251) == 255 ? true : false; table[i + 6] = (byteTable[i] | 253) == 255 ? true : false; table[i + 7] = (byteTable[i] | 254) == 255 ? true : false; } }
internal TableBC(PstFileReader reader, byte[] tableBuffer, LocalDescriptorList localDescriptorList, DataStructure tableDataNode) { try { Parse(reader, tableBuffer, localDescriptorList, tableDataNode); } catch (Exception e) { System.Diagnostics.Trace.WriteLine(String.Format("\nTableBC parsing error - run ScanPST to correct, attempting to continue:\n{0}", e.Message)); } }
private void Parse(PstFileReader reader, byte[] tableBuffer) { ushort indexOffset = BitConverter.ToUInt16(tableBuffer, 0); ushort tableType = BitConverter.ToUInt16(tableBuffer, 2); uint tableValueReference = BitConverter.ToUInt32(tableBuffer, 4); if (tableType != 0xCC) { return; } index = new TableIndex(tableBuffer, indexOffset, reader.PstFile.Is64Bit); }
private void Parse(PstFileReader reader, byte[] tableBuffer, LocalDescriptorList localDescriptorList, DataStructure tableDataNode) { ushort indexOffset = BitConverter.ToUInt16(tableBuffer, 0); ushort tableType = BitConverter.ToUInt16(tableBuffer, 2); uint tableValueReference = BitConverter.ToUInt32(tableBuffer, 4); TableIndex index = new TableIndex(tableBuffer, indexOffset, reader.PstFile.Is64Bit); TableIndexItem tableHeader9CIndexItem = index.GetItem(tableValueReference); uint tableHeaderB5Reference = BitConverter.ToUInt32(tableBuffer, tableHeader9CIndexItem.StartOffset); TableIndexItem tableHeaderB5IndexItem = index.GetItem(tableHeaderB5Reference); byte[] tableHeaderB5Buffer = new byte[tableHeaderB5IndexItem.EndOffset - tableHeaderB5IndexItem.StartOffset]; System.Array.Copy(tableBuffer, tableHeaderB5IndexItem.StartOffset, tableHeaderB5Buffer, 0, tableHeaderB5Buffer.Length); TableHeaderB5 tableHeaderB5 = new TableHeaderB5(tableHeaderB5Buffer); if (tableHeaderB5.Type != 0xB5) { return; } if (tableHeaderB5.ValueEntriesIndexReference == 0) { return; } TableIndexItem valueEntiresIndexItem = index.GetItem(tableHeaderB5.ValueEntriesIndexReference); for (int i = 0; i < valueEntiresIndexItem.EndOffset - valueEntiresIndexItem.StartOffset; i += 20) { int startIndex = valueEntiresIndexItem.StartOffset + i; byte[] guid = new byte[16]; System.Array.Copy(tableBuffer, startIndex, guid, 0, 16); uint descriptorId = BitConverter.ToUInt16(tableBuffer, startIndex + 16); } }
internal TableCC(PstFileReader reader, byte[] tableBuffer) { this.tableBuffer = tableBuffer; Parse(reader, tableBuffer); }
private void Parse(PstFileReader reader, byte[] tableBuffer, LocalDescriptorList localDescriptorList, DataStructure tableDataNode) { ushort indexOffset = BitConverter.ToUInt16(tableBuffer, 0); ushort tableType = BitConverter.ToUInt16(tableBuffer, 2); uint tableValueReference = BitConverter.ToUInt32(tableBuffer, 4); TableIndex index = new TableIndex(tableBuffer, indexOffset, reader.PstFile.Is64Bit); TableIndexItem tableHeaderB5IndexItem = index.GetItem(tableValueReference); if (tableHeaderB5IndexItem == null) { return; } byte[] tableHeaderB5Buffer = new byte[8]; System.Array.Copy(tableBuffer, tableHeaderB5IndexItem.StartOffset, tableHeaderB5Buffer, 0, 8); TableHeaderB5 tableHeaderB5 = new TableHeaderB5(tableHeaderB5Buffer); BTreeOnHeapHeader bTreeOnHeapHeader = new BTreeOnHeapHeader(tableHeaderB5Buffer); if (tableHeaderB5.Type != 0xB5) { return; } if (tableHeaderB5.ValueEntriesIndexReference == 0) { return; } uint valueEntryReference = tableHeaderB5.ValueEntriesIndexReference; byte[] entryValueBuffer = null; if (bTreeOnHeapHeader.BIdxLevels == 2) { //Not implemented return; } else if (bTreeOnHeapHeader.BIdxLevels == 1) { TableIndexItem entryIndexItem = index.Items[(int)bTreeOnHeapHeader.HidRoot.Index]; byte[] level1EntryValueBuffer = new byte[entryIndexItem.EndOffset - entryIndexItem.StartOffset]; System.Array.Copy(tableBuffer, entryIndexItem.StartOffset, level1EntryValueBuffer, 0, level1EntryValueBuffer.Length); MemoryStream entryValueBufferMemoryStream = new MemoryStream(); for (int i = 0; i < level1EntryValueBuffer.Length; i += 6) { byte[] heapIdBuffer = new byte[4]; System.Array.Copy(level1EntryValueBuffer, i + 2, heapIdBuffer, 0, 4); HeapId heapId = new HeapId(heapIdBuffer); TableIndexItem tempEntryIndexItem = index.Items[(int)heapId.Index]; byte[] tempLevel1EntryValueBuffer = new byte[tempEntryIndexItem.EndOffset - tempEntryIndexItem.StartOffset]; System.Array.Copy(tableBuffer, tempEntryIndexItem.StartOffset, tempLevel1EntryValueBuffer, 0, tempLevel1EntryValueBuffer.Length); entryValueBufferMemoryStream.Write(tempLevel1EntryValueBuffer, 0, tempLevel1EntryValueBuffer.Length); } entryValueBuffer = entryValueBufferMemoryStream.ToArray(); } else { TableIndexItem entryIndexItem = index.GetItem(valueEntryReference); if (entryIndexItem != null) { entryValueBuffer = new byte[entryIndexItem.EndOffset - entryIndexItem.StartOffset]; System.Array.Copy(tableBuffer, entryIndexItem.StartOffset, entryValueBuffer, 0, entryValueBuffer.Length); } } if (entryValueBuffer != null) { for (int i = 0; i < entryValueBuffer.Length - 2; i += 8) { ushort tag = BitConverter.ToUInt16(entryValueBuffer, i); ushort type = BitConverter.ToUInt16(entryValueBuffer, i + 2); TableEntry entry = new TableEntry(reader.PstFile.Encoding); entry.PropertyTag = new PropertyTag(tag, type); if (entry.PropertyTag.Type == PropertyType.Boolean) { int intValue = BitConverter.ToInt32(entryValueBuffer, i + 4); if (intValue != 0) //true { entry.ValueBuffer = BitConverter.GetBytes((short)1); } else { entry.ValueBuffer = BitConverter.GetBytes((short)0); } } else if (entry.PropertyTag.Type == PropertyType.Short) { entry.ValueBuffer = new byte[2]; System.Array.Copy(entryValueBuffer, i + 4, entry.ValueBuffer, 0, 2); } else if (entry.PropertyTag.Type == PropertyType.Integer || entry.PropertyTag.Type == PropertyType.Float) { entry.ValueBuffer = new byte[4]; System.Array.Copy(entryValueBuffer, i + 4, entry.ValueBuffer, 0, 4); } else if (entry.PropertyTag.Type == PropertyType.Object) { uint valueReference = BitConverter.ToUInt32(entryValueBuffer, i + 4); if (valueReference == 0) { continue; } if (Util.IsInternalReference(valueReference)) { TableIndexItem indexItem = index.GetItem(valueReference); if (indexItem != null) { if (indexItem.EndOffset > indexItem.StartOffset) { entry.ValueBuffer = new byte[indexItem.EndOffset - indexItem.StartOffset]; if (tableBuffer.Length >= indexItem.StartOffset + entry.ValueBuffer.Length) { System.Array.Copy(tableBuffer, indexItem.StartOffset, entry.ValueBuffer, 0, entry.ValueBuffer.Length); } uint embeddedItemId = BitConverter.ToUInt32(entry.ValueBuffer, 0); if (localDescriptorList != null) { LocalDescriptorListElement element = localDescriptorList.Elements.ContainsKey(embeddedItemId) ? localDescriptorList.Elements[embeddedItemId] : null; if (element != null) { DataStructure dataNode = reader.PstFile.DataIndexTree.GetDataStructure(element.DataStructureId); if (dataNode != null) { entry.ValueBuffer = Util.GetBuffer(reader, dataNode); } } } } } } else { if (localDescriptorList != null) { LocalDescriptorListElement element = localDescriptorList.Elements.ContainsKey(valueReference) ? localDescriptorList.Elements[valueReference] : null; if (element != null) { DataStructure dataNode = reader.PstFile.DataIndexTree.GetDataStructure(element.DataStructureId); if (dataNode != null) { byte[] valueBuffer = Util.GetBuffer(reader, dataNode); entry.ValueBuffer = valueBuffer; } } } } } else if (entry.PropertyTag.Type == PropertyType.Long || entry.PropertyTag.Type == PropertyType.Double || entry.PropertyTag.Type == PropertyType.Currency || entry.PropertyTag.Type == PropertyType.ShortArray || entry.PropertyTag.Type == PropertyType.IntegerArray || entry.PropertyTag.Type == PropertyType.FloatArray || entry.PropertyTag.Type == PropertyType.LongArray || entry.PropertyTag.Type == PropertyType.DoubleArray || entry.PropertyTag.Type == PropertyType.CurrencyArray || entry.PropertyTag.Type == PropertyType.String || entry.PropertyTag.Type == PropertyType.String8 || entry.PropertyTag.Type == PropertyType.StringArray || entry.PropertyTag.Type == PropertyType.String8Array || entry.PropertyTag.Type == PropertyType.Binary || entry.PropertyTag.Type == PropertyType.BinaryArray || entry.PropertyTag.Type == PropertyType.Guid || entry.PropertyTag.Type == PropertyType.GuidArray || entry.PropertyTag.Type == PropertyType.ApplicationTime || entry.PropertyTag.Type == PropertyType.SystemTime) { uint valueReference = BitConverter.ToUInt32(entryValueBuffer, i + 4); if (valueReference == 0) { continue; } if (Util.IsInternalReference(valueReference)) { TableIndexItem indexItem = index.GetItem(valueReference); if (indexItem != null) { if (indexItem.EndOffset > indexItem.StartOffset) { entry.ValueBuffer = new byte[indexItem.EndOffset - indexItem.StartOffset]; if (tableBuffer.Length >= indexItem.StartOffset + entry.ValueBuffer.Length) { System.Array.Copy(tableBuffer, indexItem.StartOffset, entry.ValueBuffer, 0, entry.ValueBuffer.Length); } } } } else { if (localDescriptorList != null) { LocalDescriptorListElement element = localDescriptorList.Elements.ContainsKey(valueReference) ? localDescriptorList.Elements[valueReference] : null; if (element != null) { DataStructure dataNode = reader.PstFile.DataIndexTree.GetDataStructure(element.DataStructureId); if (dataNode != null) { byte[] valueBuffer = Util.GetBuffer(reader, dataNode); entry.ValueBuffer = valueBuffer; } } } } } Entries.Add(entry); } } }
private void Parse(PstFileReader reader, ItemDescriptor descriptor, Table table) { this.reader = reader; this.descriptor = descriptor; this.table = table; if (reader.PstFile == null) { throw new DataStructureException("Parse - reader.PstFile was null"); } if (reader.PstFile.MessageStore == null) { throw new DataStructureException("Parse - reader.PstFile.MessageStore was null"); } //Compute EntryID if (reader.PstFile.MessageStore.RecordKey != null) { entryId = new byte[24]; System.Array.Copy(reader.PstFile.MessageStore.RecordKey, 0, entryId, 4, 16); byte[] idBytes = BitConverter.GetBytes((uint)descriptor.Id); System.Array.Copy(idBytes, 0, entryId, 20, 4); } if (descriptor != null) { childrenCount = descriptor.Children.Count; } if (table.Entries[MapiPropertyTag.PR_DISPLAY_NAME] != null) { displayName = table.Entries[MapiPropertyTag.PR_DISPLAY_NAME].GetStringValue(); } if (table.Entries[MapiPropertyTag.PR_COMMENT] != null) { comment = table.Entries[MapiPropertyTag.PR_COMMENT].GetStringValue(); } if (table.Entries[MapiPropertyTag.PR_CONTENT_COUNT] != null) { itemCount = table.Entries[MapiPropertyTag.PR_CONTENT_COUNT].GetIntegerValue(); } if (table.Entries[MapiPropertyTag.PR_CONTENT_UNREAD] != null) { unreadItemCount = table.Entries[MapiPropertyTag.PR_CONTENT_UNREAD].GetIntegerValue(); } if (table.Entries[MapiPropertyTag.PR_SUBFOLDERS] != null) { hasSubFolders = table.Entries[MapiPropertyTag.PR_SUBFOLDERS].GetBooleanValue(); } if (table.Entries[MapiPropertyTag.PR_CONTAINER_CLASS] != null) { containerClass = table.Entries[MapiPropertyTag.PR_CONTAINER_CLASS].GetStringValue(); } }
private void Parse(PstFileReader reader, ulong offset) { reader.BaseStream.Position = (long)offset; root = new IndexNode(reader, offset, this); }
private void Parse(PstFileReader reader, byte[] tableBuffer, LocalDescriptorList localDescriptorList, DataStructure tableDataNode, bool isRecipientsTable) { ushort indexOffset = BitConverter.ToUInt16(tableBuffer, 0); ushort tableType = BitConverter.ToUInt16(tableBuffer, 2); uint tableValueReference = BitConverter.ToUInt32(tableBuffer, 4); TableIndex index = new TableIndex(tableBuffer, indexOffset, reader.PstFile.Is64Bit); TableIndexItem tableHeader7CIndexItem = index.GetItem(tableValueReference); if (tableHeader7CIndexItem == null) { return; } byte[] tableHeader7CBuffer = new byte[tableHeader7CIndexItem.EndOffset - tableHeader7CIndexItem.StartOffset]; if (tableHeader7CBuffer.Length > tableBuffer.Length - tableHeader7CIndexItem.StartOffset) { return; } System.Array.Copy(tableBuffer, tableHeader7CIndexItem.StartOffset, tableHeader7CBuffer, 0, tableHeader7CBuffer.Length); TableHeader7C tableHeader7C = new TableHeader7C(tableHeader7CBuffer); if (tableHeader7C.Type != 0x7C) { return; } TableIndexItem tableHeaderB5IndexItem = index.GetItem(tableHeader7C.B5HeaderReference); byte[] tableHeaderB5Buffer = new byte[8]; System.Array.Copy(tableBuffer, tableHeaderB5IndexItem.StartOffset, tableHeaderB5Buffer, 0, 8); TableHeaderB5 tableHeaderB5 = new TableHeaderB5(tableHeaderB5Buffer); BTreeOnHeapHeader bTreeOnHeapHeader = new BTreeOnHeapHeader(tableHeaderB5Buffer); if (tableHeaderB5.Type != 0xB5) { return; } if (tableHeader7C.ValueEntriesIndexReference == 0) { return; } byte[] entryValueBuffer = null; bool useB5Header = false; if (bTreeOnHeapHeader.BIdxLevels == 2) { //Not implemented return; } else if (bTreeOnHeapHeader.BIdxLevels == 1) { byte[] level1EntryValueBuffer = null; if (bTreeOnHeapHeader.HidRoot.Index > 0 && bTreeOnHeapHeader.HidRoot.BlockIndex == 0) { TableIndexItem entryIndexItem = index.Items.ContainsKey((int)bTreeOnHeapHeader.HidRoot.Index) ? index.Items[(int)bTreeOnHeapHeader.HidRoot.Index] : null; if (entryIndexItem != null) { level1EntryValueBuffer = new byte[entryIndexItem.EndOffset - entryIndexItem.StartOffset]; System.Array.Copy(tableBuffer, entryIndexItem.StartOffset, level1EntryValueBuffer, 0, level1EntryValueBuffer.Length); } } else if (bTreeOnHeapHeader.HidRoot.Index > 0 && bTreeOnHeapHeader.HidRoot.BlockIndex > 0) { if (index.SecondItems.Length >= bTreeOnHeapHeader.HidRoot.BlockIndex) { IDictionary <int, TableIndexItem> secondIndexTable = index.SecondItems[bTreeOnHeapHeader.HidRoot.BlockIndex - 1]; if (secondIndexTable != null) { TableIndexItem entryIndexItem = secondIndexTable.ContainsKey((int)bTreeOnHeapHeader.HidRoot.Index) ? secondIndexTable[(int)bTreeOnHeapHeader.HidRoot.Index] : null; if (entryIndexItem != null) { level1EntryValueBuffer = new byte[entryIndexItem.EndOffset - entryIndexItem.StartOffset]; System.Array.Copy(tableBuffer, entryIndexItem.StartOffset, level1EntryValueBuffer, 0, level1EntryValueBuffer.Length); } } } } MemoryStream entryValueBufferMemoryStream = new MemoryStream(); for (int i = 0; i < level1EntryValueBuffer.Length; i += 8) { byte[] heapIdBuffer = new byte[4]; System.Array.Copy(level1EntryValueBuffer, i + 4, heapIdBuffer, 0, 4); HeapId heapId = new HeapId(heapIdBuffer); if (heapId.Index > 0 && heapId.BlockIndex == 0) { TableIndexItem tempEntryIndexItem = index.Items.ContainsKey((int)heapId.Index) ? index.Items[(int)heapId.Index] : null; if (tempEntryIndexItem != null) { byte[] tempLevel1EntryValueBuffer = new byte[tempEntryIndexItem.EndOffset - tempEntryIndexItem.StartOffset]; System.Array.Copy(tableBuffer, tempEntryIndexItem.StartOffset, tempLevel1EntryValueBuffer, 0, tempLevel1EntryValueBuffer.Length); entryValueBufferMemoryStream.Write(tempLevel1EntryValueBuffer, 0, tempLevel1EntryValueBuffer.Length); } } else if (heapId.Index > 0 && heapId.BlockIndex > 0) { if (index.SecondItems.Length >= heapId.BlockIndex) { IDictionary <int, TableIndexItem> secondIndexTable = index.SecondItems[heapId.BlockIndex - 1]; if (secondIndexTable != null) { TableIndexItem tempEntryIndexItem = secondIndexTable.ContainsKey((int)heapId.Index) ? secondIndexTable[(int)heapId.Index] : null; if (tempEntryIndexItem != null) { byte[] tempLevel1EntryValueBuffer = new byte[tempEntryIndexItem.EndOffset - tempEntryIndexItem.StartOffset]; System.Array.Copy(tableBuffer, tempEntryIndexItem.StartOffset, tempLevel1EntryValueBuffer, 0, tempLevel1EntryValueBuffer.Length); entryValueBufferMemoryStream.Write(tempLevel1EntryValueBuffer, 0, tempLevel1EntryValueBuffer.Length); } } } } } entryValueBuffer = entryValueBufferMemoryStream.ToArray(); useB5Header = true; } else if (localDescriptorList != null) { LocalDescriptorListElement element = localDescriptorList.Elements.ContainsKey(tableHeader7C.ValueEntriesIndexReference) ? localDescriptorList.Elements[tableHeader7C.ValueEntriesIndexReference] : null; if (element == null && tableHeader7C.ValueEntriesIndexReference != 63 && !Util.IsInternalReference(tableHeader7C.ValueEntriesIndexReference)) { uint elementId = isRecipientsTable ? 1682u : 1649u; element = localDescriptorList.Elements.ContainsKey(elementId) ? localDescriptorList.Elements[elementId] : null; if (element != null && element.SubList != null) { element = element.SubList.Elements.ContainsKey(tableHeader7C.ValueEntriesIndexReference) ? element.SubList.Elements[tableHeader7C.ValueEntriesIndexReference] : null; } } if (element != null) { DataStructure dataNode = reader.PstFile.DataIndexTree.GetDataStructure(element.DataStructureId); if (dataNode != null) { entryValueBuffer = Util.GetBuffer(reader, dataNode); } } else { if (tableHeader7C.ValueEntriesIndexReference == 63) { TableIndexItem entryValueIndexItem = index.GetItem(tableHeaderB5.ValueEntriesIndexReference); if (entryValueIndexItem != null && tableBuffer.Length >= entryValueIndexItem.EndOffset) { entryValueBuffer = new byte[entryValueIndexItem.EndOffset - entryValueIndexItem.StartOffset]; System.Array.Copy(tableBuffer, entryValueIndexItem.StartOffset, entryValueBuffer, 0, entryValueBuffer.Length); } useB5Header = true; } else { TableIndexItem entryValueIndexItem = index.GetItem(tableHeader7C.ValueEntriesIndexReference); if (entryValueIndexItem != null && tableBuffer.Length >= entryValueIndexItem.EndOffset) { entryValueBuffer = new byte[entryValueIndexItem.EndOffset - entryValueIndexItem.StartOffset]; System.Array.Copy(tableBuffer, entryValueIndexItem.StartOffset, entryValueBuffer, 0, entryValueBuffer.Length); } } } } else { if (tableHeader7C.ValueEntriesIndexReference == 63) { TableIndexItem entryValueIndexItem = index.GetItem(tableHeaderB5.ValueEntriesIndexReference); if (entryValueIndexItem != null && tableBuffer.Length >= entryValueIndexItem.EndOffset) { entryValueBuffer = new byte[entryValueIndexItem.EndOffset - entryValueIndexItem.StartOffset]; System.Array.Copy(tableBuffer, entryValueIndexItem.StartOffset, entryValueBuffer, 0, entryValueBuffer.Length); } useB5Header = true; } else { TableIndexItem entryValueIndexItem = index.GetItem(tableHeader7C.ValueEntriesIndexReference); if (entryValueIndexItem != null && tableBuffer.Length >= entryValueIndexItem.EndOffset) { entryValueBuffer = new byte[entryValueIndexItem.EndOffset - entryValueIndexItem.StartOffset]; System.Array.Copy(tableBuffer, entryValueIndexItem.StartOffset, entryValueBuffer, 0, entryValueBuffer.Length); } } } if (entryValueBuffer == null) { return; } int entriesArraySize = entryValueBuffer.Length / tableHeader7C.ValueArraySize; if (useB5Header) { entriesArraySize = entryValueBuffer.Length / (tableHeaderB5.EntryIdSize + tableHeaderB5.EntryValueSize); } EntriesArray = new TableEntryList[entriesArraySize]; for (int m = 0; m < entriesArraySize; m++) { EntriesArray[m] = new TableEntryList(); for (int i = 0; i < tableHeader7C.EntryDefinitions.Count; i++) { Table7CEntryDefinition entryDefinition = tableHeader7C.EntryDefinitions[i]; TableEntry entry = new TableEntry(reader.PstFile.Encoding); entry.PropertyTag = new PropertyTag(entryDefinition.EntryId, entryDefinition.EntryValueType); int offset = m * tableHeader7C.ValueArraySize + entryDefinition.ValueArrayEntryOffset; if (useB5Header) { offset = m * (tableHeaderB5.EntryIdSize + tableHeaderB5.EntryValueSize); } if (entryValueBuffer.Length < offset) { if (isRecipientsTable) { Console.Error.WriteLine("\rWarning: Bad entry Recipients Property Table..skipping entry"); } else { Console.Error.WriteLine("\rWarning: Bad entry in Table 7c..skipping entry"); } } else if (entry.PropertyTag.Type == PropertyType.Short || entry.PropertyTag.Type == PropertyType.Boolean) { entry.ValueBuffer = new byte[2]; System.Array.Copy(entryValueBuffer, offset, entry.ValueBuffer, 0, 2); } else if (entry.PropertyTag.Type == PropertyType.Integer || entry.PropertyTag.Type == PropertyType.Float) { entry.ValueBuffer = new byte[4]; System.Array.Copy(entryValueBuffer, offset, entry.ValueBuffer, 0, 4); } else if (!useB5Header && (entry.PropertyTag.Type == PropertyType.Long || entry.PropertyTag.Type == PropertyType.Double || entry.PropertyTag.Type == PropertyType.Currency)) { entry.ValueBuffer = new byte[8]; System.Array.Copy(entryValueBuffer, offset, entry.ValueBuffer, 0, 8); } else if (entry.PropertyTag.Type == PropertyType.Long || entry.PropertyTag.Type == PropertyType.Double || entry.PropertyTag.Type == PropertyType.Currency || entry.PropertyTag.Type == PropertyType.ShortArray || entry.PropertyTag.Type == PropertyType.IntegerArray || entry.PropertyTag.Type == PropertyType.FloatArray || entry.PropertyTag.Type == PropertyType.LongArray || entry.PropertyTag.Type == PropertyType.DoubleArray || entry.PropertyTag.Type == PropertyType.CurrencyArray || entry.PropertyTag.Type == PropertyType.String || entry.PropertyTag.Type == PropertyType.String8 || entry.PropertyTag.Type == PropertyType.StringArray || entry.PropertyTag.Type == PropertyType.String8Array || entry.PropertyTag.Type == PropertyType.Binary || entry.PropertyTag.Type == PropertyType.BinaryArray || entry.PropertyTag.Type == PropertyType.Object || entry.PropertyTag.Type == PropertyType.Guid || entry.PropertyTag.Type == PropertyType.GuidArray || entry.PropertyTag.Type == PropertyType.ApplicationTime || entry.PropertyTag.Type == PropertyType.SystemTime) { uint valueReference = 0; if (useB5Header && tableHeaderB5.EntryValueSize == 2) { valueReference = BitConverter.ToUInt16(entryValueBuffer, offset); } else { valueReference = BitConverter.ToUInt32(entryValueBuffer, offset); } if (valueReference == 0) { continue; } if (Util.IsInternalReference(valueReference)) { TableIndexItem indexItem = index.GetItem(valueReference); if (indexItem != null) { if (indexItem.EndOffset > indexItem.StartOffset) { entry.ValueBuffer = new byte[indexItem.EndOffset - indexItem.StartOffset]; if (tableBuffer.Length >= indexItem.StartOffset + entry.ValueBuffer.Length) { System.Array.Copy(tableBuffer, indexItem.StartOffset, entry.ValueBuffer, 0, entry.ValueBuffer.Length); } } } } else { if (localDescriptorList != null) { LocalDescriptorListElement element = localDescriptorList.Elements.ContainsKey(valueReference) ? localDescriptorList.Elements[valueReference] : null; if (element == null) { LocalDescriptorListElement recipientElement = localDescriptorList.Elements.ContainsKey((uint)1682) ? localDescriptorList.Elements[(uint)1682] : null; if (recipientElement != null && recipientElement.SubList != null) { element = recipientElement.SubList.Elements.ContainsKey(valueReference) ? recipientElement.SubList.Elements[valueReference] : null; } } if (element != null) { DataStructure dataNode = reader.PstFile.DataIndexTree.GetDataStructure(element.DataStructureId); if (dataNode != null) { entry.ValueBuffer = Util.GetBuffer(reader, dataNode); } } } } } EntriesArray[m].Add(entry); } } //Try to recover recipients table if email address is null in all entries int emptyEmailAddressCount = 0; for (int k = 0; k < EntriesArray.Length; k++) { if (EntriesArray[k][MapiPropertyTag.PR_EMAIL_ADDRESS] != null && EntriesArray[k][MapiPropertyTag.PR_EMAIL_ADDRESS].ValueBuffer == null) { emptyEmailAddressCount++; } else if (EntriesArray[k][MapiPropertyTag.PR_EMAIL_ADDRESS] == null && EntriesArray[k][MapiPropertyTag.PR_RECIPIENT_TYPE] != null) { emptyEmailAddressCount++; } } if (emptyEmailAddressCount > (int)(EntriesArray.Length / 2)) { TableInfo tableInfo = new TableInfo(tableHeader7CBuffer); IDictionary <uint, byte[]> rowTable = new Dictionary <uint, byte[]>(); int rowLength = tableInfo.EndOffsetCellExistenceBlock; IList <TableRowId> rowIds = new List <TableRowId>(); for (int i = 0; i < entryValueBuffer.Length; i += entryValueBuffer.Length / entriesArraySize) { byte[] rowIdBuffer = new byte[entryValueBuffer.Length / entriesArraySize]; if (entryValueBuffer.Length >= i + rowIdBuffer.Length) { System.Array.Copy(entryValueBuffer, i, rowIdBuffer, 0, rowIdBuffer.Length); TableRowId rowId = new TableRowId(rowIdBuffer); rowIds.Add(rowId); } } if (localDescriptorList != null) { LocalDescriptorListElement element = localDescriptorList.Elements.ContainsKey((uint)0x692) ? localDescriptorList.Elements[(uint)0x692] : null; if (element != null) { if (element.SubList == null || !element.SubList.Elements.ContainsKey((uint)63) || element.SubList.Elements[(uint)63] == null) { return; } LocalDescriptorListElement subElement = element.SubList.Elements[(uint)63]; DataStructure dataNode = reader.PstFile.DataIndexTree.GetDataStructure(subElement.DataStructureId); if (dataNode != null) { byte[] rowMatrix = Util.GetBuffer(reader, dataNode); int tableSize = reader.PstFile.Is64Bit ? 8176 : 8180; int tableCount = 1; for (int r = 0; r <= rowMatrix.Length - rowLength; r += rowLength) { if (((tableSize * tableCount) - r) < rowLength) { r = tableSize * tableCount++; } byte[] rowBuffer = new byte[rowLength]; System.Array.Copy(rowMatrix, r, rowBuffer, 0, rowBuffer.Length); uint dwRowId = BitConverter.ToUInt32(rowBuffer, 0); if (!rowTable.ContainsKey(dwRowId)) { rowTable.Add(dwRowId, rowBuffer); } else { //Console.WriteLine("Warning: existing row key:" + dwRowId); } } int cellExistenceBlockLength = tableInfo.EndOffsetCellExistenceBlock - tableInfo.EndOffset1ByteDataValue; EntriesArray = new TableEntryList[rowIds.Count]; for (int i = 0; i < rowIds.Count; i++) { EntriesArray[i] = new TableEntryList(); byte[] rowBuffer = rowTable.ContainsKey(rowIds[i].Id) ? rowTable[rowIds[i].Id] : null; if (rowBuffer != null) { for (int c = 0; c < tableInfo.Columns.Count; c++) { TableColumnDescription columnDescription = tableInfo.Columns[c]; byte[] cellExistenceBlock = new byte[cellExistenceBlockLength]; System.Array.Copy(rowBuffer, rowBuffer.Length - cellExistenceBlockLength, cellExistenceBlock, 0, cellExistenceBlock.Length); int cellExistenceBlockValue = cellExistenceBlock[columnDescription.IBit / 8] & (1 << (7 - (columnDescription.IBit % 8))); if (cellExistenceBlockValue != 0) //true { PropertyTag propertyTag = new PropertyTag(columnDescription.Tag); TableEntry entry = new TableEntry(reader.PstFile.Encoding); byte[] valueBuffer = new byte[columnDescription.CountBytes]; System.Array.Copy(rowBuffer, columnDescription.Offset, valueBuffer, 0, valueBuffer.Length); if (propertyTag.Type == PropertyType.Boolean) { if (valueBuffer[0] != 0) //true { valueBuffer = BitConverter.GetBytes((short)1); } else { valueBuffer = BitConverter.GetBytes((short)0); } } else if (propertyTag.Type == PropertyType.Long || propertyTag.Type == PropertyType.Double || propertyTag.Type == PropertyType.Currency || propertyTag.Type == PropertyType.ApplicationTime || propertyTag.Type == PropertyType.SystemTime || propertyTag.Type == PropertyType.Guid) { HeapId heapId = new HeapId(valueBuffer); TableIndexItem indexItem = index.Items.ContainsKey((int)heapId.Index) ? index.Items[(int)heapId.Index] : null; if (indexItem != null) { valueBuffer = new byte[indexItem.EndOffset - indexItem.StartOffset]; System.Array.Copy(tableBuffer, indexItem.StartOffset, valueBuffer, 0, valueBuffer.Length); } } else if (propertyTag.Type == PropertyType.String || propertyTag.Type == PropertyType.String8 || propertyTag.Type == PropertyType.Binary || propertyTag.Type == PropertyType.Object || propertyTag.Type == PropertyType.ShortArray || propertyTag.Type == PropertyType.IntegerArray || propertyTag.Type == PropertyType.FloatArray || propertyTag.Type == PropertyType.LongArray || propertyTag.Type == PropertyType.DoubleArray || propertyTag.Type == PropertyType.CurrencyArray || propertyTag.Type == PropertyType.StringArray || propertyTag.Type == PropertyType.String8Array || propertyTag.Type == PropertyType.BinaryArray || propertyTag.Type == PropertyType.GuidArray) { HeapId heapId = new HeapId(valueBuffer); if (heapId.Index > 0 && heapId.BlockIndex == 0) { TableIndexItem indexItem = index.Items.ContainsKey((int)heapId.Index) ? index.Items[(int)heapId.Index] : null; if (indexItem != null) { valueBuffer = new byte[indexItem.EndOffset - indexItem.StartOffset]; System.Array.Copy(tableBuffer, indexItem.StartOffset, valueBuffer, 0, valueBuffer.Length); } } else if (heapId.Index > 0 && heapId.BlockIndex > 0) { if (index.SecondItems.Length >= heapId.BlockIndex) { IDictionary <int, TableIndexItem> secondIndexTable = index.SecondItems[heapId.BlockIndex - 1]; if (secondIndexTable != null) { TableIndexItem indexItem = secondIndexTable.ContainsKey((int)heapId.Index) ? secondIndexTable[(int)heapId.Index] : null; if (indexItem != null) { valueBuffer = new byte[indexItem.EndOffset - indexItem.StartOffset]; System.Array.Copy(tableBuffer, indexItem.StartOffset, valueBuffer, 0, valueBuffer.Length); } } } } } entry.PropertyTag = propertyTag; entry.ValueBuffer = valueBuffer; EntriesArray[i].Add(entry); } } } } } } } } }
internal Table7C(PstFileReader reader, byte[] tableBuffer, LocalDescriptorList localDescriptorList, DataStructure tableDataNode, bool isRecipientsTable) { Parse(reader, tableBuffer, localDescriptorList, tableDataNode, isRecipientsTable); }
private void Parse(Stream stream, System.Text.Encoding encoding) { this.encoding = encoding; this.stream = stream; this.reader = new PstFileReader(this, stream); uint signature = reader.ReadUInt32();//offset 0 if (signature != 0x4e444221) { Close(); throw new FileFormatException("Invalid file format!"); } uint crc32 = reader.ReadUInt32(); //offset 4 ushort contentType = reader.ReadUInt16(); //offset 8 ushort dataVersion = reader.ReadUInt16(); //offset 10 ushort contentVersion = reader.ReadUInt16(); //offset 12 byte creationPlatform = reader.ReadByte(); //offset 14 byte accessPlatform = reader.ReadByte(); //offset 15 uint unknown1 = reader.ReadUInt32(); //offset 16 uint unknown2 = reader.ReadUInt32(); //offset 20 if (dataVersion == 0x0015 || dataVersion == 0x0017) { is64Bit = true; } if (!is64Bit) { //32-bit file uint unknown3 = reader.ReadUInt32(); //offset 24 uint unknown4 = reader.ReadUInt32(); //offset 28 uint unknown5 = reader.ReadUInt32(); //offset 32 byte[] unknownArray1 = reader.ReadBytes(32); //offset 36 byte[] unknownArray2 = reader.ReadBytes(32); byte[] unknownArray3 = reader.ReadBytes(32); byte[] unknownArray4 = reader.ReadBytes(32); uint unknown6 = reader.ReadUInt32(); //offset 164 size = reader.ReadInt32(); //offset 168 uint lastDataAllocationTableOffset = reader.ReadUInt32(); //offset 172 uint unknown7 = reader.ReadUInt32(); //offset 176 uint unknown8 = reader.ReadUInt32(); //offset 180 descriptorIndexBackPointer = reader.ReadUInt32(); descriptorIndex = reader.ReadUInt32(); dataIndexBackPointer = reader.ReadUInt32(); dataIndex = reader.ReadUInt32(); uint unknown9 = reader.ReadUInt32(); //offset 200 byte[] dataAllocationTableMap = reader.ReadBytes(128); //offset 204 byte[] indexNodeAllocationTableMap = reader.ReadBytes(128); //offset 332 byte senitinal = reader.ReadByte(); //offset 460 encryptionType = EnumUtil.ParseEncryptionType(reader.ReadByte()); //offset 461 //AllocationTable dataAllocationTable = new AllocationTable(reader, 17408); //offset 0x4400 //AllocationTable indexNodeAllocationTable = new AllocationTable(reader, 17920); //offset 0x4600 } else { //64-bit file ulong unknown3 = reader.ReadUInt64(); //offset 24 ulong unknown4 = reader.ReadUInt64(); //offset 32 uint unknown5 = reader.ReadUInt32(); //offset 40 byte[] unknownArray1 = reader.ReadBytes(32); //offset 36 byte[] unknownArray2 = reader.ReadBytes(32); byte[] unknownArray3 = reader.ReadBytes(32); byte[] unknownArray4 = reader.ReadBytes(32); uint unknown61 = reader.ReadUInt32(); //offset 172 uint unknown62 = reader.ReadUInt32(); //offset 176 uint unknown63 = reader.ReadUInt32(); //offset 180 size = reader.ReadInt64(); //offset 184 ulong lastDataAllocationTableOffset = reader.ReadUInt64(); //offset 192 ulong unknown7 = reader.ReadUInt64(); //offset 200 ulong unknown8 = reader.ReadUInt64(); //offset 208 descriptorIndexBackPointer = reader.ReadUInt64(); //offset 216 descriptorIndex = reader.ReadUInt64(); //offset 224 dataIndexBackPointer = reader.ReadUInt64(); //offset 232 dataIndex = reader.ReadUInt64(); //offset 240 uint unknown9 = reader.ReadUInt32(); //offset 248 uint unknown10 = reader.ReadUInt32(); //offset 252 byte[] dataAllocationTableMap = reader.ReadBytes(128); //offset 256 byte[] indexNodeAllocationTableMap = reader.ReadBytes(128); //offset 384 byte senitinal = reader.ReadByte(); //offset 512 encryptionType = EnumUtil.ParseEncryptionType(reader.ReadByte()); //offset 513 } descriptorIndexTree = new IndexTree(reader, descriptorIndex); descriptorIndexTree.SetParent(); //set parent folder dataIndexTree = new IndexTree(reader, dataIndex); ulong nameToIdMapId = 97; ulong messageStoreId = 33; ulong rootId = 290; ulong mailboxRootId = 32802; //32802 or 32834 Table nameToIdMapTable = null; Table messageStoreTable = null; Table rootTable = null; Table mailboxRootTable = null; ItemDescriptor nameToIdMapItemDescriptor = descriptorIndexTree.Nodes.ContainsKey(nameToIdMapId) ? (ItemDescriptor)descriptorIndexTree.Nodes[nameToIdMapId] : null; ItemDescriptor messageStoreItemDescriptor = descriptorIndexTree.Nodes.ContainsKey(messageStoreId) ? (ItemDescriptor)descriptorIndexTree.Nodes[messageStoreId] : null; ItemDescriptor rootItemDescriptor = descriptorIndexTree.Nodes.ContainsKey(rootId) ? (ItemDescriptor)descriptorIndexTree.Nodes[rootId] : null; ItemDescriptor mailboxRootItemDescriptor = descriptorIndexTree.Nodes.ContainsKey(mailboxRootId) ? (ItemDescriptor)descriptorIndexTree.Nodes[mailboxRootId] : null; if (mailboxRootItemDescriptor == null) { mailboxRootItemDescriptor = descriptorIndexTree.Nodes.ContainsKey((ulong)32834) ? (ItemDescriptor)descriptorIndexTree.Nodes[(ulong)32834] : null; } if (nameToIdMapItemDescriptor == null) { throw new DataStructureException("Unresolvable Data Structure issue with: nameToIdMapItemDescriptor"); } DataStructure nameToIdMapLocalDescriptorListNode = Util.GetLocalDescriptionListNode(reader.PstFile.DataIndexTree, nameToIdMapItemDescriptor.LocalDescriptorListId); DataStructure nameToIdMapDataNode = reader.PstFile.DataIndexTree.GetDataStructure(nameToIdMapItemDescriptor.TableId); if (nameToIdMapDataNode != null) { LocalDescriptorList nameToIdMapLocalDescriptorList = Util.GetLocalDescriptorList(reader, nameToIdMapLocalDescriptorListNode); nameToIdMapTable = Util.GetTable(reader, nameToIdMapDataNode, nameToIdMapLocalDescriptorList); } if (messageStoreItemDescriptor == null) { throw new DataStructureException("Unresolvable Data Structure issue with: messageStoreItemDescriptor"); } DataStructure messageStoreLocalDescriptorListNode = Util.GetLocalDescriptionListNode(reader.PstFile.DataIndexTree, messageStoreItemDescriptor.LocalDescriptorListId); DataStructure messageStoreDataNode = reader.PstFile.DataIndexTree.GetDataStructure(messageStoreItemDescriptor.TableId); if (messageStoreDataNode != null) { LocalDescriptorList messageStoreLocalDescriptorList = Util.GetLocalDescriptorList(reader, messageStoreLocalDescriptorListNode); messageStoreTable = Util.GetTable(reader, messageStoreDataNode, messageStoreLocalDescriptorList); } if (rootItemDescriptor == null) { throw new DataStructureException("Unresolvable Data Structure issue with: rootItemDescriptor"); } DataStructure rootLocalDescriptorListNode = Util.GetLocalDescriptionListNode(reader.PstFile.DataIndexTree, rootItemDescriptor.LocalDescriptorListId); DataStructure rootDataNode = reader.PstFile.DataIndexTree.GetDataStructure(rootItemDescriptor.TableId); if (rootDataNode != null) { LocalDescriptorList rootLocalDescriptorList = Util.GetLocalDescriptorList(reader, rootLocalDescriptorListNode); rootTable = Util.GetTable(reader, rootDataNode, rootLocalDescriptorList); } if (mailboxRootItemDescriptor != null) { DataStructure mailboxRootLocalDescriptorListNode = Util.GetLocalDescriptionListNode(reader.PstFile.DataIndexTree, mailboxRootItemDescriptor.LocalDescriptorListId); DataStructure mailboxRootDataNode = reader.PstFile.DataIndexTree.GetDataStructure(mailboxRootItemDescriptor.TableId); if (mailboxRootDataNode != null) { LocalDescriptorList mailboxRootLocalDescriptorList = Util.GetLocalDescriptorList(reader, mailboxRootLocalDescriptorListNode); mailboxRootTable = Util.GetTable(reader, mailboxRootDataNode, mailboxRootLocalDescriptorList); } } if (nameToIdMapTable != null) { nameToIdMap = new NameToIdMap(nameToIdMapTable); FillNamedIdToTag(); } if (messageStoreTable != null) { messageStore = new MessageStore(messageStoreTable); } if (rootTable != null) { root = new Folder(reader, rootItemDescriptor, rootTable); } if (mailboxRootItemDescriptor != null && mailboxRootTable != null) { mailboxRoot = new Folder(reader, mailboxRootItemDescriptor, mailboxRootTable); } }
internal AllocationTable(PstFileReader reader, uint offset) { Parse(reader, offset); }
private void Parse(PstFileReader reader, ulong offset, IndexTree tree) { // PRGX: make sure offset is valid if (offset > (ulong)reader.BaseStream.Length) { throw new DataStructureException("Parse - offset beyond length of stream"); } reader.BaseStream.Position = (long)offset; if (!reader.PstFile.Is64Bit) { //32bit byte[] itemsBuffer = reader.ReadBytes(496); this.itemCount = reader.ReadByte(); this.maximumItemCount = reader.ReadByte(); this.itemSize = reader.ReadByte(); this.level = reader.ReadByte(); this.type = reader.ReadUInt16(); this.backPointer = reader.ReadUInt32(); this.crc = reader.ReadUInt32(); if (type == 0x8080 && level > 0) { for (int i = 0; i < itemCount; i++) { byte[] itemBuffer = new byte[12]; System.Array.Copy(itemsBuffer, i * 12, itemBuffer, 0, 12); DataStructureIndexNodeItem item = new DataStructureIndexNodeItem(); item.Id = BitConverter.ToUInt32(itemBuffer, 0); item.BackPointer = BitConverter.ToUInt32(itemBuffer, 4); item.Offset = BitConverter.ToUInt32(itemBuffer, 8); items.Add(item); IndexNode childIndexNode = new IndexNode(reader, item.Offset, tree); childIndexNode.Parent = this; this.children.Add(childIndexNode); } } else if (type == 0x8080 && level == 0) { for (int i = 0; i < itemCount; i++) { byte[] itemBuffer = new byte[12]; System.Array.Copy(itemsBuffer, i * 12, itemBuffer, 0, 12); DataStructure item = new DataStructure(itemBuffer); item.Id = BitConverter.ToUInt32(itemBuffer, 0); item.Offset = BitConverter.ToUInt32(itemBuffer, 4); item.Size = BitConverter.ToUInt16(itemBuffer, 8); item.Flag = BitConverter.ToUInt16(itemBuffer, 10); items.Add(item); tree.Nodes.Add(item.Id, item); } } else if (type == 0x8181 && level > 0) { for (int i = 0; i < itemCount; i++) { byte[] itemBuffer = new byte[12]; System.Array.Copy(itemsBuffer, i * 12, itemBuffer, 0, 12); ItemDescriptorIndexNodeItem item = new ItemDescriptorIndexNodeItem(); item.Id = BitConverter.ToUInt32(itemBuffer, 0); item.BackPointer = BitConverter.ToUInt32(itemBuffer, 4); item.Offset = BitConverter.ToUInt32(itemBuffer, 8); items.Add(item); IndexNode childIndexNode = new IndexNode(reader, item.Offset, tree); childIndexNode.Parent = this; this.children.Add(childIndexNode); } } else if (type == 0x8181 && level == 0) { for (int i = 0; i < itemCount; i++) { byte[] itemBuffer = new byte[16]; System.Array.Copy(itemsBuffer, i * 16, itemBuffer, 0, 16); ItemDescriptor item = new ItemDescriptor(); item.Id = BitConverter.ToUInt32(itemBuffer, 0); item.TableId = BitConverter.ToUInt32(itemBuffer, 4); item.LocalDescriptorListId = BitConverter.ToUInt32(itemBuffer, 8); item.ParentItemDescriptorId = BitConverter.ToUInt32(itemBuffer, 12); items.Add(item); tree.Nodes.Add(item.Id, item); //root folder is parent to self. if (item.Id == 290) { item.ParentItemDescriptorId = 0; } } } else { throw new ApplicationException("Unknown IndexNode type!"); } } else { //64bit byte[] itemsBuffer = reader.ReadBytes(488); this.itemCount = reader.ReadByte(); this.maximumItemCount = reader.ReadByte(); this.itemSize = reader.ReadByte(); this.level = reader.ReadByte(); uint emptyValue = reader.ReadUInt32(); this.type = reader.ReadUInt16(); ushort unknow1 = reader.ReadUInt16(); this.crc = reader.ReadUInt32(); this.backPointer = reader.ReadUInt64(); if (type == 0x8080 && level > 0) { for (int i = 0; i < itemCount; i++) { byte[] itemBuffer = new byte[24]; System.Array.Copy(itemsBuffer, i * 24, itemBuffer, 0, 24); DataStructureIndexNodeItem item = new DataStructureIndexNodeItem(); item.Id = BitConverter.ToUInt64(itemBuffer, 0); item.BackPointer = BitConverter.ToUInt64(itemBuffer, 8); item.Offset = BitConverter.ToUInt64(itemBuffer, 16); // PRGX: offset from start of file is only valid when greater than zero if (item.Offset > 0 && item.Offset < (ulong)reader.BaseStream.Length) { items.Add(item); IndexNode childIndexNode = new IndexNode(reader, item.Offset, tree); childIndexNode.Parent = this; this.children.Add(childIndexNode); } } } else if (type == 0x8080 && level == 0) { for (int i = 0; i < itemCount; i++) { byte[] itemBuffer = new byte[24]; System.Array.Copy(itemsBuffer, i * 24, itemBuffer, 0, 24); DataStructure item = new DataStructure(itemBuffer); item.Id = BitConverter.ToUInt64(itemBuffer, 0); item.Offset = BitConverter.ToUInt64(itemBuffer, 8); item.Size = BitConverter.ToUInt16(itemBuffer, 16); item.Flag = BitConverter.ToUInt16(itemBuffer, 18); // PRGX: offset from start of file is only valid when greater than zero if (item.Offset > 0 && !tree.Nodes.ContainsKey(item.Id)) { items.Add(item); tree.Nodes.Add(item.Id, item); } } } else if (type == 0x8181 && level > 0) { for (int i = 0; i < itemCount; i++) { byte[] itemBuffer = new byte[24]; System.Array.Copy(itemsBuffer, i * 24, itemBuffer, 0, 24); ItemDescriptorIndexNodeItem item = new ItemDescriptorIndexNodeItem(); item.Id = BitConverter.ToUInt64(itemBuffer, 0); item.BackPointer = BitConverter.ToUInt64(itemBuffer, 8); item.Offset = BitConverter.ToUInt64(itemBuffer, 16); // PRGX: offset from start of file is only valid when greater than zero if (item.Offset > 0) { items.Add(item); IndexNode childIndexNode = new IndexNode(reader, item.Offset, tree); childIndexNode.Parent = this; this.children.Add(childIndexNode); } } } else if ((type == 0x8181 || type == 0x0) && level == 0) { for (int i = 0; i < itemCount; i++) { byte[] itemBuffer = new byte[32]; System.Array.Copy(itemsBuffer, i * 32, itemBuffer, 0, 32); ItemDescriptor item = new ItemDescriptor(); item.Id = BitConverter.ToUInt64(itemBuffer, 0); item.TableId = BitConverter.ToUInt64(itemBuffer, 8); item.LocalDescriptorListId = BitConverter.ToUInt64(itemBuffer, 16); item.ParentItemDescriptorId = BitConverter.ToUInt32(itemBuffer, 24); if (item.Id > 0 && !tree.Nodes.ContainsKey(item.Id)) { items.Add(item); tree.Nodes.Add(item.Id, item); //root folder is parent to self. if (item.Id == 290) { item.ParentItemDescriptorId = 0; } } } } else { throw new ApplicationException("Unknown IndexNode type: " + type + " level: " + level); } } }
internal IndexNode(PstFileReader reader, ulong offset, IndexTree tree) { Parse(reader, offset, tree); }
internal TableAC(PstFileReader reader, byte[] tableBuffer, LocalDescriptorList localDescriptorList, DataStructure tableDataNode) { Parse(reader, tableBuffer, localDescriptorList, tableDataNode); }
internal Folder(PstFileReader reader, ItemDescriptor descriptor, Table table) { Parse(reader, descriptor, table); }
private void Parse(PstFileReader reader, byte[] tableBuffer, LocalDescriptorList localDescriptorList, DataStructure tableDataNode) { ushort indexOffset = BitConverter.ToUInt16(tableBuffer, 0); ushort tableType = BitConverter.ToUInt16(tableBuffer, 2); uint tableValueReference = BitConverter.ToUInt32(tableBuffer, 4); TableIndex index = new TableIndex(tableBuffer, indexOffset, reader.PstFile.Is64Bit); TableIndexItem tableHeaderACIndexItem = index.GetItem(tableValueReference); byte[] tableHeaderACBuffer = new byte[tableHeaderACIndexItem.EndOffset - tableHeaderACIndexItem.StartOffset]; System.Array.Copy(tableBuffer, tableHeaderACIndexItem.StartOffset, tableHeaderACBuffer, 0, tableHeaderACBuffer.Length); TableHeaderAC tableHeaderAC = new TableHeaderAC(tableHeaderACBuffer); if (tableHeaderAC.Type != 0xAC) { return; } byte[] entryDefinitionsBuffer = null; if (tableHeaderAC.TableEntryDefinitionReference < 0x8000) { TableIndexItem tableEntryDefinitionIndexItem = index.GetItem(tableHeaderAC.TableEntryDefinitionReference); entryDefinitionsBuffer = new byte[tableEntryDefinitionIndexItem.EndOffset - tableEntryDefinitionIndexItem.StartOffset]; System.Array.Copy(tableBuffer, tableEntryDefinitionIndexItem.StartOffset, entryDefinitionsBuffer, 0, entryDefinitionsBuffer.Length); } else { if (localDescriptorList != null) { LocalDescriptorListElement element = localDescriptorList.Elements.ContainsKey(tableHeaderAC.TableEntryDefinitionReference) ? localDescriptorList.Elements[tableHeaderAC.TableEntryDefinitionReference] : null; if (element != null) { DataStructure dataNode = reader.PstFile.DataIndexTree.GetDataStructure(element.DataStructureId); if (dataNode != null) { entryDefinitionsBuffer = Util.GetBuffer(reader, dataNode); } } } } if (entryDefinitionsBuffer == null) { return; } IList <TableACEntryDefinition> entryDefinitions = new List <TableACEntryDefinition>(); for (int i = 0; i < tableHeaderAC.EntryDefinitionCount; i++) { TableACEntryDefinition entry = new TableACEntryDefinition(); entry.EntryValueType = BitConverter.ToUInt16(entryDefinitionsBuffer, i * 16); entry.EntryId = BitConverter.ToUInt16(entryDefinitionsBuffer, i * 16 + 2); entry.ValueArrayEntryOffset = BitConverter.ToUInt16(entryDefinitionsBuffer, i * 16 + 4); entry.ValueArrayEntrySize = BitConverter.ToUInt16(entryDefinitionsBuffer, i * 16 + 6); entry.ValueArrayEntryNumber = BitConverter.ToUInt16(entryDefinitionsBuffer, i * 16 + 8); entry.DescriptorId = BitConverter.ToUInt32(entryDefinitionsBuffer, i * 16 + 12); entryDefinitions.Add(entry); } TableIndexItem tableHeaderB5IndexItem = index.GetItem(tableHeaderAC.B5HeaderReference); byte[] tableHeaderB5Buffer = new byte[8]; System.Array.Copy(tableBuffer, tableHeaderB5IndexItem.StartOffset, tableHeaderB5Buffer, 0, 8); TableHeaderB5 tableHeaderB5 = new TableHeaderB5(tableHeaderB5Buffer); if (tableHeaderB5.Type != 0xB5) { return; } byte[] entryValueBuffer = null; if (tableHeaderAC.ValueEntriesIndexReference == 0) { return; } if (localDescriptorList != null) { LocalDescriptorListElement element = localDescriptorList.Elements.ContainsKey(tableHeaderAC.ValueEntriesIndexReference) ? localDescriptorList.Elements[tableHeaderAC.ValueEntriesIndexReference] : null; if (element != null) { DataStructure dataNode = reader.PstFile.DataIndexTree.GetDataStructure(element.DataStructureId); if (dataNode != null) { entryValueBuffer = Util.GetBuffer(reader, dataNode); } } else { TableIndexItem entryValueIndexItem = index.GetItem(tableHeaderAC.ValueEntriesIndexReference); entryValueBuffer = new byte[entryValueIndexItem.EndOffset - entryValueIndexItem.StartOffset]; System.Array.Copy(tableBuffer, entryValueIndexItem.StartOffset, entryValueBuffer, 0, entryValueBuffer.Length); } } if (entryValueBuffer == null) { return; } for (int i = 0; i < entryDefinitions.Count; i++) { TableACEntryDefinition entryDefinition = entryDefinitions[i]; TableEntry entry = new TableEntry(reader.PstFile.Encoding); entry.PropertyTag = new PropertyTag(entryDefinition.EntryId, entryDefinition.EntryValueType); if (entry.PropertyTag.Type == PropertyType.Short || entry.PropertyTag.Type == PropertyType.Boolean) { entry.ValueBuffer = new byte[2]; System.Array.Copy(entryValueBuffer, entryDefinition.ValueArrayEntryOffset, entry.ValueBuffer, 0, 2); } else if (entry.PropertyTag.Type == PropertyType.Integer || entry.PropertyTag.Type == PropertyType.Float) { entry.ValueBuffer = new byte[4]; System.Array.Copy(entryValueBuffer, entryDefinition.ValueArrayEntryOffset, entry.ValueBuffer, 0, 4); } else if (entry.PropertyTag.Type == PropertyType.Long || entry.PropertyTag.Type == PropertyType.Double || entry.PropertyTag.Type == PropertyType.Currency || entry.PropertyTag.Type == PropertyType.ApplicationTime || entry.PropertyTag.Type == PropertyType.SystemTime) { entry.ValueBuffer = new byte[8]; System.Array.Copy(entryValueBuffer, entryDefinition.ValueArrayEntryOffset, entry.ValueBuffer, 0, 8); } else if (entry.PropertyTag.Type == PropertyType.ShortArray || entry.PropertyTag.Type == PropertyType.IntegerArray || entry.PropertyTag.Type == PropertyType.FloatArray || entry.PropertyTag.Type == PropertyType.LongArray || entry.PropertyTag.Type == PropertyType.DoubleArray || entry.PropertyTag.Type == PropertyType.CurrencyArray || entry.PropertyTag.Type == PropertyType.String || entry.PropertyTag.Type == PropertyType.String8 || entry.PropertyTag.Type == PropertyType.StringArray || entry.PropertyTag.Type == PropertyType.String8Array || entry.PropertyTag.Type == PropertyType.Object || entry.PropertyTag.Type == PropertyType.Binary || entry.PropertyTag.Type == PropertyType.BinaryArray || entry.PropertyTag.Type == PropertyType.Guid || entry.PropertyTag.Type == PropertyType.GuidArray) { if (entryDefinition.DescriptorId > 0) { if (localDescriptorList != null) { LocalDescriptorListElement element = localDescriptorList.Elements.ContainsKey(entryDefinition.DescriptorId) ? localDescriptorList.Elements[entryDefinition.DescriptorId] : null; if (element != null) { DataStructure dataNode = reader.PstFile.DataIndexTree.GetDataStructure(element.DataStructureId); if (dataNode != null) { byte[] valueBuffer = Util.GetBuffer(reader, dataNode); if (valueBuffer != null && valueBuffer.Length > 3) { ushort tableA5Type = BitConverter.ToUInt16(valueBuffer, 2); if (tableA5Type == 0xA5) { TableA5 tableA5 = new TableA5(reader, valueBuffer); valueBuffer = tableA5.GetValue(entryDefinition.ValueArrayEntryOffset); } } entry.ValueBuffer = valueBuffer; } } } } else { uint valueReference = BitConverter.ToUInt32(entryValueBuffer, entryDefinition.ValueArrayEntryOffset); if (valueReference == 0) { continue; } if (Util.IsInternalReference(valueReference)) { TableIndexItem indexItem = index.GetItem(valueReference); if (indexItem != null) { if (indexItem.EndOffset > indexItem.StartOffset) { entry.ValueBuffer = new byte[indexItem.EndOffset - indexItem.StartOffset]; if (tableBuffer.Length >= indexItem.StartOffset + entry.ValueBuffer.Length) { System.Array.Copy(tableBuffer, indexItem.StartOffset, entry.ValueBuffer, 0, entry.ValueBuffer.Length); } } } } else { if (localDescriptorList != null) { LocalDescriptorListElement element = localDescriptorList.Elements.ContainsKey(valueReference) ? localDescriptorList.Elements[valueReference] : null; if (element != null) { DataStructure dataNode = reader.PstFile.DataIndexTree.GetDataStructure(element.DataStructureId); if (dataNode != null) { byte[] valueBuffer = Util.GetBuffer(reader, dataNode); if (valueBuffer != null && valueBuffer.Length > 3) { ushort tableA5Type = BitConverter.ToUInt16(valueBuffer, 2); if (tableA5Type == 0xA5) { TableA5 tableA5 = new TableA5(reader, valueBuffer); valueBuffer = tableA5.GetValue(entryDefinition.ValueArrayEntryOffset); } } entry.ValueBuffer = valueBuffer; } } } } } } Entries.Add(entry); } }
internal IndexTree(PstFileReader reader, ulong offset) { Parse(reader, offset); }