public static byte[] GetExternalPropertyBytes(HeapOnNode heap, SubnodeBTree subnodeBTree, HeapOrNodeID heapOrNodeID) { if (heapOrNodeID.IsEmpty) { return(new byte[0]); } else if (heapOrNodeID.IsHeapID) { byte[] result = heap.GetHeapItem(heapOrNodeID.HeapID); return(result); } else { // indicates that the item is stored in the subnode block, and the NID is the local NID under the subnode Subnode subnode = subnodeBTree.GetSubnode(heapOrNodeID.NodeID); if (subnode != null) { if (subnode.DataTree == null) { return(new byte[0]); } else { return(subnode.DataTree.GetData()); } } else { throw new MissingSubnodeException(); } } }
public void SaveChanges(SubnodeBTree parentSubnodeBTree, NodeID subnodeID) { SaveChanges(); // We can optimize and only update when root block is changed. // Note however that multiple SaveChanges() may be called before this method. parentSubnodeBTree.UpdateSubnodeEntry(subnodeID, this.DataTree, this.SubnodeBTree); }
public static Subnode GetSubnode(PSTFile file, SubnodeLeafEntry entry) { DataTree dataTree = null; if (entry.bidData.Value != 0) { Block rootDataBlock = file.FindBlockByBlockID(entry.bidData); if (rootDataBlock == null) { throw new Exception("Cannot get subnode: missing data tree root block"); } dataTree = new DataTree(file, rootDataBlock); } SubnodeBTree subnodeBTree = null; if (entry.bidSub.Value != 0) { Block rootSubnodeBlock = file.FindBlockByBlockID(entry.bidSub); if (rootSubnodeBlock == null) { throw new Exception("Missing Subnode BTree Root Block"); } subnodeBTree = new SubnodeBTree(file, rootSubnodeBlock); } return(new Subnode(file, entry.nid, dataTree, subnodeBTree)); }
public void UpdateSubnodeEntry(NodeID subnodeID, DataTree dataTree, SubnodeBTree subnodeBTree) { SubnodeLeafEntry entry = GetLeafEntry(subnodeID.Value); if (entry != null) { entry.bidData = new BlockID(0); if (dataTree != null && dataTree.RootBlock != null) { entry.bidData = dataTree.RootBlock.BlockID; } entry.bidSub = new BlockID(0); if (subnodeBTree != null && subnodeBTree.RootBlock != null) { entry.bidSub = subnodeBTree.RootBlock.BlockID; } // We have to store the new leaf block, and cascade the changes up to the root block SubnodeLeafBlock leafBlock = FindLeafBlock(entry.nid.Value); // leafBlock cannot be null int index = leafBlock.IndexOfLeafEntry(subnodeID.Value); leafBlock.rgentries[index] = entry; UpdateBlockAndReferences(leafBlock); } }
public void CreateSubnodeBTreeIfNotExist() { if (m_subnodeBTree == null) { m_subnodeBTree = new SubnodeBTree(m_file); } }
public static PSTNode GetPSTNode(PSTFile file, NodeID nodeID) { NodeBTreeEntry entry = file.FindNodeEntryByNodeID(nodeID.Value); if (entry != null) { DataTree dataTree = null; if (entry.bidData.Value != 0) { Block rootDataBlock = file.FindBlockByBlockID(entry.bidData); dataTree = new DataTree(file, rootDataBlock); } SubnodeBTree subnodeBTree = null; if (entry.bidSub.Value != 0) { Block rootSubnodeBlock = file.FindBlockByBlockID(entry.bidSub); subnodeBTree = new SubnodeBTree(file, rootSubnodeBlock); } return(new PSTNode(file, nodeID, dataTree, subnodeBTree)); } else { return(null); } }
/// <param name="subnodeBTree">Note: We use ref, this way we are able to create a new subnode BTree and update the subnodeBTree the caller provided</param> /// <param name="heapOrNodeID">Existing HeapOrNodeID</param> public static HeapOrNodeID StoreExternalProperty(PSTFile file, HeapOnNode heap, ref SubnodeBTree subnodeBTree, HeapOrNodeID heapOrNodeID, byte[] propertyBytes) { // We should avoid storing items with length of 0, because those are consideref freed, and could be repurposed if (propertyBytes.Length == 0) { RemoveExternalProperty(heap, subnodeBTree, heapOrNodeID); return(new HeapOrNodeID(HeapID.EmptyHeapID)); } if (heapOrNodeID.IsHeapID) // if HeapOrNodeID is empty then IsHeapID == true { if (propertyBytes.Length <= HeapOnNode.MaximumAllocationLength) { if (heapOrNodeID.IsEmpty) { return(new HeapOrNodeID(heap.AddItemToHeap(propertyBytes))); } else { return(new HeapOrNodeID(heap.ReplaceHeapItem(heapOrNodeID.HeapID, propertyBytes))); } } else // old data (if exist) is stored on heap, but new data needs a subnode { if (!heapOrNodeID.IsEmpty) { heap.RemoveItemFromHeap(heapOrNodeID.HeapID); } if (subnodeBTree == null) { subnodeBTree = new SubnodeBTree(file); } DataTree dataTree = new DataTree(file); dataTree.AppendData(propertyBytes); dataTree.SaveChanges(); NodeID subnodeID = file.Header.AllocateNextNodeID(NodeTypeName.NID_TYPE_LTP); subnodeBTree.InsertSubnodeEntry(subnodeID, dataTree, null); return(new HeapOrNodeID(subnodeID)); } } else // old data is stored in a subnode { Subnode subnode = subnodeBTree.GetSubnode(heapOrNodeID.NodeID); if (subnode.DataTree != null) { subnode.DataTree.Delete(); } subnode.DataTree = new DataTree(subnodeBTree.File); subnode.DataTree.AppendData(propertyBytes); subnode.SaveChanges(subnodeBTree); return(new HeapOrNodeID(heapOrNodeID.NodeID)); } }
public void CreateAttachmentTableIfNotExist() { CreateSubnodeBTreeIfNotExist(); Subnode subnode = SubnodeBTree.GetSubnode((uint)InternalNodeName.NID_ATTACHMENT_TABLE); if (subnode == null) { PSTNode template = this.File.GetNode(InternalNodeName.NID_ATTACHMENT_TABLE); NodeID nodeID = new NodeID((uint)InternalNodeName.NID_ATTACHMENT_TABLE); SubnodeBTree.InsertSubnodeEntry(nodeID, template.DataTree, null); File.BlockBTree.IncrementBlockEntryReferenceCount(template.DataTree.RootBlock.BlockID); } }
public static AttachmentObject CreateNewAttachmentObject(PSTFile file, SubnodeBTree subnodeBTree) { PropertyContext pc = PropertyContext.CreateNewPropertyContext(file); pc.SaveChanges(); NodeID pcNodeID = file.Header.AllocateNextNodeID(NodeTypeName.NID_TYPE_ATTACHMENT); subnodeBTree.InsertSubnodeEntry(pcNodeID, pc.DataTree, pc.SubnodeBTree); Subnode subnode = new Subnode(file, pcNodeID, pc.DataTree, pc.SubnodeBTree); return(new AttachmentObject(subnode)); }
private Subnode m_subnodeRows; // for buffering purposes public TableContext(HeapOnNode heap, SubnodeBTree subnodeBTree) { m_heap = heap; m_subnodeBTree = subnodeBTree; m_tcInfo = new TableContextInfo(m_heap.GetHeapItem(m_heap.HeapHeader.hidUserRoot)); BTreeOnHeap <TableContextRowID> bTreeOnHeap = new BTreeOnHeap <TableContextRowID>(m_heap, m_tcInfo.hidRowIndex); if (bTreeOnHeap.BTreeHeader.hidRoot.hidIndex > 0) // hidRoot is set to zero if the BTH is empty. { m_rowIndex = bTreeOnHeap.GetAll(); m_rowIndex.Sort(TableContextRowID.CompareByRowIndex); } m_rowsPerBlock = (int)Math.Floor((double)DataBlock.MaximumDataLength / RowLength); }
public static void RemoveExternalProperty(HeapOnNode heap, SubnodeBTree subnodeBTree, HeapOrNodeID heapOrNodeID) { if (!heapOrNodeID.IsEmpty) { if (heapOrNodeID.IsHeapID) { heap.RemoveItemFromHeap(heapOrNodeID.HeapID); } else { DataTree dataTree = subnodeBTree.GetSubnode(heapOrNodeID.NodeID).DataTree; dataTree.Delete(); subnodeBTree.DeleteSubnodeEntry(heapOrNodeID.NodeID); } } }
public void CreateRecipientsTableIfNotExist() { CreateSubnodeBTreeIfNotExist(); Subnode subnode = SubnodeBTree.GetSubnode((uint)InternalNodeName.NID_RECIPIENT_TABLE); if (subnode == null) { PSTNode template = this.File.GetNode(InternalNodeName.NID_RECIPIENT_TABLE); NodeID nodeID = new NodeID((uint)InternalNodeName.NID_RECIPIENT_TABLE); SubnodeBTree.InsertSubnodeEntry(nodeID, template.DataTree, null); File.BlockBTree.IncrementBlockEntryReferenceCount(template.DataTree.RootBlock.BlockID); this.RecipientsTable.AddPropertyColumnIfNotExist(PropertyID.PidTagRecipientDisplayName, PropertyTypeName.PtypString); this.RecipientsTable.AddPropertyColumnIfNotExist(PropertyID.PidTagRecipientEntryId, PropertyTypeName.PtypBinary); this.RecipientsTable.AddPropertyColumnIfNotExist(PropertyID.PidTagRecipientFlags, PropertyTypeName.PtypInteger32); this.RecipientsTable.AddPropertyColumnIfNotExist(PropertyID.PidTagRecipientTrackStatus, PropertyTypeName.PtypInteger32); } }
private void CreateSubnodeForRows() { if (m_subnodeBTree == null) { m_subnodeBTree = new SubnodeBTree(this.File); } // We don't have to use a unique node ID for a subnode, but we can. NodeID nodeID = File.Header.AllocateNextNodeID(NodeTypeName.NID_TYPE_LTP); // Data tree will be created when first row will be added m_subnodeRows = new Subnode(File, nodeID, null, null); m_subnodeBTree.InsertSubnodeEntry(nodeID, null, null); // update the Table Context Info structure to point to the new rows m_tcInfo.hnidRows = new HeapOrNodeID(m_subnodeRows.SubnodeID); UpdateTableContextInfo(); }
public void InsertSubnodeEntry(NodeID subnodeID, DataTree dataTree, SubnodeBTree subnodeBTree) { SubnodeLeafEntry entry = new SubnodeLeafEntry(); entry.nid = subnodeID; entry.bidData = new BlockID(0); if (dataTree != null && dataTree.RootBlock != null) { entry.bidData = dataTree.RootBlock.BlockID; } entry.bidSub = new BlockID(0); if (subnodeBTree != null && subnodeBTree.RootBlock != null) { entry.bidSub = subnodeBTree.RootBlock.BlockID; } InsertSubnodeEntry(entry); }
public virtual void Delete() { if (!m_file.IsSavingChanges) { throw new Exception("Implementer must call PSTFile.BeginSavingChanges() before saving changes"); } if (m_dataTree != null) { m_dataTree.Delete(); m_dataTree = null; } if (m_subnodeBTree != null) { m_subnodeBTree.Delete(); m_subnodeBTree = null; } }
/// <param name="subnodeBTree">Subnode BTree that will be associated with the new PC</param> public static PropertyContext CreateNewPropertyContext(PSTFile file, SubnodeBTree subnodeBTree) { HeapOnNode heap = HeapOnNode.CreateNewHeap(file); BTreeOnHeapHeader bTreeHeader = new BTreeOnHeapHeader(); bTreeHeader.cbKey = PropertyContextRecord.RecordKeyLength; bTreeHeader.cbEnt = PropertyContextRecord.RecordDataLength; HeapID newUserRoot = heap.AddItemToHeap(bTreeHeader.GetBytes()); // The heap header may have just been updated HeapOnNodeHeader header = heap.HeapHeader; header.bClientSig = OnHeapTypeName.bTypePC; header.hidUserRoot = newUserRoot; heap.UpdateHeapHeader(header); heap.FlushToDataTree(); return(new PropertyContext(heap, subnodeBTree)); }
public void InsertNodeEntry(NodeID nodeID, DataTree dataTree, SubnodeBTree subnodeBTree, NodeID parentNodeID) { NodeBTreeEntry entry = new NodeBTreeEntry(); entry.nid = nodeID; entry.bidData = new BlockID(0); if (dataTree != null && dataTree.RootBlock != null) { entry.bidData = dataTree.RootBlock.BlockID; } entry.bidSub = new BlockID(0); if (subnodeBTree != null && subnodeBTree.RootBlock != null) { entry.bidSub = subnodeBTree.RootBlock.BlockID; } entry.nidParent = parentNodeID; InsertNodeEntry(entry); }
public void UpdateNodeEntry(NodeID nodeID, DataTree dataTree, SubnodeBTree subnodeBTree) { NodeBTreeLeafPage leaf = (NodeBTreeLeafPage)FindLeafBTreePage(nodeID.Value); int index = leaf.GetIndexOfEntry(nodeID.Value); if (index >= 0) { leaf.NodeEntryList[index].bidData = new BlockID(0); if (dataTree != null && dataTree.RootBlock != null) { leaf.NodeEntryList[index].bidData = dataTree.RootBlock.BlockID; } leaf.NodeEntryList[index].bidSub = new BlockID(0); if (subnodeBTree != null && subnodeBTree.RootBlock != null) { leaf.NodeEntryList[index].bidSub = subnodeBTree.RootBlock.BlockID; } // now we have to store the new leaf page, and cascade the changes up to the root page UpdatePageAndReferences(leaf); } }
public RecipientsTable(HeapOnNode heap, SubnodeBTree subnodeBTree) : base(heap, subnodeBTree) { }
public NamedTableContext(HeapOnNode heap, SubnodeBTree subnodeBTree, PropertyNameToIDMap map) : base(heap, subnodeBTree) { m_map = map; }
public static HeapOrNodeID StoreExternalProperty(PSTFile file, HeapOnNode heap, ref SubnodeBTree subnodeBTree, byte[] propertyBytes) { return(StoreExternalProperty(file, heap, ref subnodeBTree, new HeapOrNodeID(HeapID.EmptyHeapID), propertyBytes)); }
/// <summary> /// The entry will be removed from the parent subnode-BTree /// </summary> public void Delete(SubnodeBTree parentSubnodeBTree) { Delete(); parentSubnodeBTree.DeleteSubnodeEntry(m_subnodeID); }
public void SaveChanges(SubnodeBTree parentSubnodeBTree) { SaveChanges(); parentSubnodeBTree.UpdateSubnodeEntry(m_subnodeID, this.DataTree, this.SubnodeBTree); }
public Subnode(PSTFile file, NodeID subnodeID, DataTree dataTree, SubnodeBTree subnodeBTree) : base(file, dataTree, subnodeBTree) { m_subnodeID = subnodeID; }
public HierarchyTable(HeapOnNode heap, SubnodeBTree subnodeBTree) : base(heap, subnodeBTree) { }
public PropertyContext(HeapOnNode heap, SubnodeBTree subnodeBTree) : base(heap) { m_subnodeBTree = subnodeBTree; }
public static ModifiedAppointmentInstance CreateNewModifiedInstance(PSTFile file, SubnodeBTree attachmentSubnodeBTree) { PropertyContext pc = PropertyContext.CreateNewPropertyContext(file); pc.SetStringProperty(PropertyID.PidTagMessageClass, RecurringAppointmentExceptionMessageClass); pc.SetDateTimeProperty(PropertyID.PidTagCreationTime, DateTime.UtcNow); pc.SetDateTimeProperty(PropertyID.PidTagLastModificationTime, DateTime.UtcNow); // PidTagSearchKey is apparently a GUID pc.SetBytesProperty(PropertyID.PidTagSearchKey, LittleEndianConverter.GetBytes(Guid.NewGuid())); pc.SaveChanges(); NodeID subnodeID = file.Header.AllocateNextNodeID(NodeTypeName.NID_TYPE_NORMAL_MESSAGE); attachmentSubnodeBTree.InsertSubnodeEntry(subnodeID, pc.DataTree, pc.SubnodeBTree); Subnode subnode = new Subnode(file, subnodeID, pc.DataTree, pc.SubnodeBTree); return(new ModifiedAppointmentInstance(subnode)); }
public static AttachmentObject CreateNewExceptionAttachmentObject(PSTFile file, SubnodeBTree subnodeBTree) { AttachmentObject attachment = CreateNewAttachmentObject(file, subnodeBTree); attachment.PC.SetStringProperty(PropertyID.PidTagDisplayName, "Untitled"); attachment.PC.SetStringProperty(PropertyID.PidTagAttachEncoding, String.Empty); //attachment.PC.SetBytesProperty(PropertyID.PidTagAttachRendering, AppointmentAttachRendering); attachment.PC.SetInt32Property(PropertyID.PidTagAttachMethod, (int)AttachMethod.EmbeddedMessage); attachment.PC.SetInt32Property(PropertyID.PidTagAttachFlags, 0); attachment.PC.SetInt32Property(PropertyID.PidTagAttachmentFlags, (int)AttachmentFlags.afException); attachment.PC.SetInt32Property(PropertyID.PidTagAttachmentLinkId, 0); attachment.PC.SetInt32Property(PropertyID.PidTagRenderingPosition, -1); attachment.PC.SetBooleanProperty(PropertyID.PidTagAttachmentHidden, true); attachment.PC.SetBooleanProperty(PropertyID.PidTagAttachmentContactPhoto, false); attachment.CreateSubnodeBTreeIfNotExist(); return(attachment); }
private NamedPropertyContext m_propertyContext; // The BTH leaves are cached, so we use a single reference public Node(PSTFile file, DataTree dataTree, SubnodeBTree subnodeBTree) { m_file = file; m_dataTree = dataTree; m_subnodeBTree = subnodeBTree; }
public AttachmentTable(HeapOnNode heap, SubnodeBTree subnodeBTree) : base(heap, subnodeBTree) { }