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);
 }
示例#3
0
        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);
            }
        }
示例#5
0
 public void CreateSubnodeBTreeIfNotExist()
 {
     if (m_subnodeBTree == null)
     {
         m_subnodeBTree = new SubnodeBTree(m_file);
     }
 }
示例#6
0
        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);
            }
        }
示例#9
0
        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));
        }
示例#10
0
        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);
         }
     }
 }
示例#12
0
        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);
            }
        }
示例#13
0
        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();
        }
示例#14
0
        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);
        }
示例#15
0
        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));
        }
示例#17
0
        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);
        }
示例#18
0
        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)
 {
 }
示例#20
0
 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));
 }
示例#22
0
 /// <summary>
 /// The entry will be removed from the parent subnode-BTree
 /// </summary>
 public void Delete(SubnodeBTree parentSubnodeBTree)
 {
     Delete();
     parentSubnodeBTree.DeleteSubnodeEntry(m_subnodeID);
 }
示例#23
0
 public void SaveChanges(SubnodeBTree parentSubnodeBTree)
 {
     SaveChanges();
     parentSubnodeBTree.UpdateSubnodeEntry(m_subnodeID, this.DataTree, this.SubnodeBTree);
 }
示例#24
0
 public Subnode(PSTFile file, NodeID subnodeID, DataTree dataTree, SubnodeBTree subnodeBTree)
     : base(file, dataTree, subnodeBTree)
 {
     m_subnodeID = subnodeID;
 }
示例#25
0
 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));
        }
示例#28
0
        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);
        }
示例#29
0
        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)
 {
 }