public void SetExternalProperty(PropertyID propertyID, PropertyTypeName propertyType, byte[] propertyBytes)
        {
            PropertyContextRecord record = GetRecordByPropertyID(propertyID);

            if (record != null)
            {
                if (record.wPropType != propertyType)
                {
                    throw new InvalidPropertyException("Property type mismatch");
                }

                if (record.IsExternal)
                {
                    HeapOrNodeID newHeapOrNodeID = NodeStorageHelper.StoreExternalProperty(this.File, this.Heap, ref m_subnodeBTree, record.HeapOrNodeID, propertyBytes);
                    if (record.HeapOrNodeID.Value != newHeapOrNodeID.Value)
                    {
                        record.HeapOrNodeID = newHeapOrNodeID;
                        UpdateRecord(record);
                    }
                }
                else
                {
                    // old record is not external but new record is, this should never happen.
                    throw new InvalidPropertyException("Old record should be external but is not");
                }
            }
            else // old record does not exist
            {
                record = new PropertyContextRecord();
                record.HeapOrNodeID = NodeStorageHelper.StoreExternalProperty(this.File, this.Heap, ref m_subnodeBTree, propertyBytes);
                record.wPropId      = propertyID;
                record.wPropType    = propertyType;
                AddRecord(record);
            }
        }
Esempio n. 2
0
        /// <param name="cellBytes">If property is external, byte[0] means empty data item</param>
        public void SetPropertyValue(int rowIndex, int columnIndex, byte[] propertyBytes)
        {
            TableColumnDescriptor columnDescriptor = m_tcInfo.rgTCOLDESC[columnIndex];

            if (columnDescriptor.IsStoredExternally)
            {
                byte[]       cellBytes = GetInternalCellBytes(rowIndex, columnIndex);
                HeapOrNodeID heapOrNodeID;
                if (cellBytes != null)
                {
                    heapOrNodeID = new HeapOrNodeID(cellBytes);
                }
                else
                {
                    heapOrNodeID = new HeapOrNodeID(HeapID.EmptyHeapID);
                }

                HeapOrNodeID newHeapOrNodeID = NodeStorageHelper.StoreExternalProperty(this.File, m_heap, ref m_subnodeBTree, heapOrNodeID, propertyBytes);
                // we call SetInternalCellBytes even when oldHeapID.Value == newHeapID.Value,
                // this will make sure the CEB will be updated
                SetInternalCellBytes(rowIndex, columnIndex, LittleEndianConverter.GetBytes(newHeapOrNodeID.Value));
            }
            else
            {
                SetInternalCellBytes(rowIndex, columnIndex, propertyBytes);
            }
        }
Esempio n. 3
0
 private void RemoveExternalProperty(int rowIndex, int columnIndex)
 {
     byte[] cellBytes = GetInternalCellBytes(rowIndex, columnIndex);
     if (cellBytes != null)
     {
         HeapOrNodeID heapOrNodeID = new HeapOrNodeID(cellBytes);
         NodeStorageHelper.RemoveExternalProperty(m_heap, m_subnodeBTree, heapOrNodeID);
     }
 }
Esempio n. 4
0
 public PropertyContextRecord(byte[] buffer, int offset)
 {
     wPropId     = (PropertyID)LittleEndianConverter.ToUInt16(buffer, offset + 0);
     wPropType   = (PropertyTypeName)LittleEndianConverter.ToUInt16(buffer, offset + 2);
     dwValueHnid = LittleEndianConverter.ToUInt32(buffer, offset + 4);
     if (!IsPropertyStoredInternally(wPropType))
     {
         HeapOrNodeID = new HeapOrNodeID(buffer, offset + 4);
     }
 }
Esempio n. 5
0
        public byte[] GetPropertyValue(int rowIndex, int columnIndex)
        {
            TableColumnDescriptor columnDescriptor = m_tcInfo.rgTCOLDESC[columnIndex];

            byte[] cellBytes = GetInternalCellBytes(rowIndex, columnIndex);
            if (cellBytes == null)
            {
                return(null);
            }
            else
            {
                if (columnDescriptor.IsStoredExternally)
                {
                    HeapOrNodeID heapOrNodeID = new HeapOrNodeID(cellBytes);
                    return(NodeStorageHelper.GetExternalPropertyBytes(m_heap, m_subnodeBTree, heapOrNodeID));
                }
                else
                {
                    return(cellBytes);
                }
            }
        }
Esempio n. 6
0
        public TableContextInfo(byte[] buffer)
        {
            bType = (OnHeapTypeName)ByteReader.ReadByte(buffer, 0);
            byte cCols    = ByteReader.ReadByte(buffer, 1);
            int  position = 2;

            for (int index = 0; index < 4; index++)
            {
                rgib[index] = LittleEndianConverter.ToUInt16(buffer, position);
                position   += 2;
            }
            hidRowIndex = new HeapID(buffer, 10);
            hnidRows    = new HeapOrNodeID(buffer, 14);
            // hidIndex - deprecated
            position = 22;
            for (int index = 0; index < cCols; index++)
            {
                TableColumnDescriptor descriptor = new TableColumnDescriptor(buffer, position);
                rgTCOLDESC.Add(descriptor);
                position += TableColumnDescriptor.Length;
            }
        }
Esempio n. 7
0
 public TableContextInfo()
 {
     bType       = OnHeapTypeName.bTypeTC;
     hidRowIndex = HeapID.EmptyHeapID;
     hnidRows    = new HeapOrNodeID(HeapID.EmptyHeapID);
 }
        /// <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 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 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();
         }
     }
 }