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); } }
/// <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); } }
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); } }
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); } }
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); } } }
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; } }
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(); } } }