/// <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);
            }
        }
        public bool IsCellInUse(int rowIndex, PropertyID propertyID, PropertyTypeName propertyType)
        {
            int columnIndex = GetColumnIndexByPropertyTag(propertyID, propertyType);
            TableColumnDescriptor columnDescriptor = m_tcInfo.rgTCOLDESC[columnIndex];

            byte[] rowBytes = GetRowBytes(rowIndex);
            return(IsCellInUse(columnDescriptor, rowBytes));
        }
        public bool IsCellInUse(TableColumnDescriptor columnDescriptor, byte[] rowBytes)
        {
            int cebByteOffset = m_tcInfo.CellExistenceBlockStartOffset + columnDescriptor.iBit / 8;
            // from MSB to LSB (as suggested by MS-PST, page 68)
            int cebBitOffset = 7 - columnDescriptor.iBit % 8;

            return((rowBytes[cebByteOffset] & (0x01 << cebBitOffset)) > 0);
        }
        public void RemoveProperty(int rowIndex, PropertyID propertyID, PropertyTypeName propertyType)
        {
            int columnIndex = GetColumnIndexByPropertyTag(propertyID, propertyType);
            TableColumnDescriptor columnDescriptor = m_tcInfo.rgTCOLDESC[columnIndex];

            if (columnDescriptor.IsStoredExternally)
            {
                RemoveExternalProperty(rowIndex, columnIndex);
            }
            byte[] rowBytes = GetRowBytes(rowIndex);
            UpdateCellExistenceBlock(columnDescriptor, rowBytes, false);
            SetRowBytes(rowIndex, rowBytes);
        }
 public int FindColumnIndexByPropertyTag(PropertyID propertyID, PropertyTypeName propertyType)
 {
     for (int index = 0; index < m_tcInfo.rgTCOLDESC.Count; index++)
     {
         TableColumnDescriptor descriptor = m_tcInfo.rgTCOLDESC[index];
         if (descriptor.PropertyID == propertyID &&
             descriptor.PropertyType == propertyType)
         {
             return(index);
         }
     }
     return(-1);
 }
        private void UpdateCellExistenceBlock(TableColumnDescriptor columnDescriptor, byte[] rowBytes, bool isInUse)
        {
            int cebByteOffset = m_tcInfo.CellExistenceBlockStartOffset + columnDescriptor.iBit / 8;
            // from MSB to LSB (as suggested by MS-PST, page 68)
            int cebBitOffset = 7 - columnDescriptor.iBit % 8;

            if (isInUse)
            {
                rowBytes[cebByteOffset] |= (byte)(0x01 << cebBitOffset);
            }
            else
            {
                rowBytes[cebByteOffset] &= (byte)~(0x01 << cebBitOffset);
            }
        }
        public byte[] GetInternalCellBytes(int rowIndex, int columnIndex)
        {
            TableColumnDescriptor columnDescriptor = m_tcInfo.rgTCOLDESC[columnIndex];

            byte[] rowBytes = GetRowBytes(rowIndex);
            bool   inUse    = IsCellInUse(columnDescriptor, rowBytes);

            if (!inUse)
            {
                return(null);
            }
            else
            {
                int    cellLength = columnDescriptor.cbData;
                byte[] cellBytes  = new byte[cellLength];
                int    cellOffset = columnDescriptor.ibData;
                Array.Copy(rowBytes, cellOffset, cellBytes, 0, cellBytes.Length);
                return(cellBytes);
            }
        }
        private void SetInternalCellBytes(int rowIndex, int columnIndex, byte[] cellBytes)
        {
            TableColumnDescriptor columnDescriptor = m_tcInfo.rgTCOLDESC[columnIndex];
            int cellLength = columnDescriptor.cbData;

            if (cellBytes.Length == cellLength)
            {
                byte[] rowBytes   = GetRowBytes(rowIndex);
                int    cellOffset = columnDescriptor.ibData;
                Array.Copy(cellBytes, 0, rowBytes, cellOffset, cellBytes.Length);

                // update CEB:
                UpdateCellExistenceBlock(columnDescriptor, rowBytes, true);

                SetRowBytes(rowIndex, rowBytes);
            }
            else
            {
                throw new InvalidPropertyException("Invalid cell length");
            }
        }
        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);
                }
            }
        }
示例#10
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;
            }
        }
示例#11
0
        /// <summary>
        /// For discovery purposes
        /// </summary>
        public List <string> ListTable()
        {
            List <string> result = new List <string>();

            result.Add("Number of Columns: " + this.ColumnCount);
            for (int index = 0; index < m_tcInfo.rgTCOLDESC.Count; index++)
            {
                TableColumnDescriptor descriptor = m_tcInfo.rgTCOLDESC[index];
                result.Add(String.Format("Column {0}, Property Type: {1}, PropertyName: {2}, Data Length: {3}, Offset: {4}, iBit: {5}", index, descriptor.PropertyType, GetPropertyIDString((ushort)descriptor.PropertyID), descriptor.cbData, descriptor.ibData, descriptor.iBit));
            }

            result.Add("Number of Rows: " + m_rowIndex.Count);
            result.Add("4-byte entries length: " + (m_tcInfo.rgib[TableContextInfo.TCI_4b]));
            result.Add("2-byte entries length: " + (m_tcInfo.rgib[TableContextInfo.TCI_2b] - m_tcInfo.rgib[TableContextInfo.TCI_4b]));
            result.Add("1-byte entries length: " + (m_tcInfo.rgib[TableContextInfo.TCI_1b] - m_tcInfo.rgib[TableContextInfo.TCI_2b]));
            result.Add("Row length (net): " + m_tcInfo.rgib[TableContextInfo.TCI_1b]);
            result.Add("Row length: " + this.RowLength);
            for (int rowIndex = 0; rowIndex < m_rowIndex.Count; rowIndex++)
            {
                result.Add("--------------------------------------------------------------------------------");
                result.Add("Row ID: " + m_rowIndex[rowIndex].dwRowID);
                result.Add("Data Length: " + m_rowIndex[rowIndex].DataLength);
                result.Add("Row Index: " + m_rowIndex[rowIndex].dwRowIndex);
                for (int columnIndex = 0; columnIndex < m_tcInfo.rgTCOLDESC.Count; columnIndex++)
                {
                    TableColumnDescriptor descriptor   = m_tcInfo.rgTCOLDESC[columnIndex];
                    PropertyTypeName      propertyType = descriptor.PropertyType;
                    PropertyID            propertyID   = descriptor.PropertyID;
                    string value;
                    if (IsCellInUse(rowIndex, propertyID, propertyType))
                    {
                        if (propertyType == PropertyTypeName.PtypBoolean)
                        {
                            bool boolValue = GetBooleanProperty(rowIndex, propertyID).Value;
                            value = boolValue.ToString();
                        }
                        else if (propertyType == PropertyTypeName.PtypInteger16)
                        {
                            value = GetInt16Property(rowIndex, propertyID).ToString() + " (Int16)";
                        }
                        else if (propertyType == PropertyTypeName.PtypInteger32)
                        {
                            value = GetInt32Property(rowIndex, propertyID).ToString();
                        }
                        else if (propertyType == PropertyTypeName.PtypInteger64)
                        {
                            value = GetInt64Property(rowIndex, propertyID).ToString() + " (Int64)";
                        }
                        else if (propertyType == PropertyTypeName.PtypTime)
                        {
                            value = GetDateTimeProperty(rowIndex, propertyID).ToString();
                        }
                        else if (propertyType == PropertyTypeName.PtypString)
                        {
                            value = GetStringProperty(rowIndex, propertyID);
                        }
                        else if (propertyType == PropertyTypeName.PtypBinary)
                        {
                            value = StringHelper.GetByteArrayString(GetBytesProperty(rowIndex, propertyID));
                        }
                        else
                        {
                            value = "-" + propertyType.ToString();
                        }
                    }
                    else
                    {
                        value = "(Unused)";
                    }

                    result.Add(GetPropertyIDString((ushort)propertyID) + ": " + value);
                }
            }

            return(result);
        }
示例#12
0
        /// <summary>
        /// Add column to an empty table context.
        /// If this is a Contents Table, the caller should call UpdateMessage() afterwards.
        /// Similarly, for attachment table, the caller should call UpdateAttachment().
        /// </summary>
        public void AddPropertyColumn(PropertyID propertyID, PropertyTypeName propertyType)
        {
            TableColumnDescriptor newColumnDescriptor = new TableColumnDescriptor();

            newColumnDescriptor.PropertyID   = propertyID;
            newColumnDescriptor.PropertyType = propertyType;
            newColumnDescriptor.iBit         = (byte)m_tcInfo.ColumnCount;
            newColumnDescriptor.cbData       = (byte)GetPropertyDataLength(propertyType);

            // Set the ibData:
            // http://social.msdn.microsoft.com/Forums/en-US/os_binaryfile/thread/a5f9c653-40f5-4638-85d3-00c54607d984/
            // PidTagLtpRowId and PidTagLtpRowVer must not be relocated
            if (newColumnDescriptor.DataLengthGroup == TableContextInfo.TCI_4b)
            {
                newColumnDescriptor.ibData = m_tcInfo.rgib[TableContextInfo.TCI_4b];
            }
            else if (newColumnDescriptor.DataLengthGroup == TableContextInfo.TCI_2b)
            {
                newColumnDescriptor.ibData = m_tcInfo.rgib[TableContextInfo.TCI_2b];
            }
            else
            {
                newColumnDescriptor.ibData = m_tcInfo.rgib[TableContextInfo.TCI_1b];
            }

            // We call GetRedistributedRows() before adding the new column:
            List <byte[]> rows = GetRedistributedRows(newColumnDescriptor.ibData, newColumnDescriptor.cbData);

            // add the new column
            m_tcInfo.rgTCOLDESC.Add(newColumnDescriptor);

            // redistribute column descriptions
            ushort offset = (ushort)(newColumnDescriptor.ibData + newColumnDescriptor.cbData);

            for (int groupIndex = newColumnDescriptor.DataLengthGroup + 1; groupIndex < 3; groupIndex++)
            {
                for (int index = 0; index < m_tcInfo.rgTCOLDESC.Count; index++)
                {
                    TableColumnDescriptor descriptor = m_tcInfo.rgTCOLDESC[index];

                    if (groupIndex == descriptor.DataLengthGroup)
                    {
                        // changes to descriptor will be saved when calling UpdateTableContextInfo()
                        descriptor.ibData = offset;
                        offset           += descriptor.cbData;
                    }
                }
            }

            // update the group ending offset
            m_tcInfo.UpdateDataLayout();
            m_rowsPerBlock = (int)Math.Floor((double)DataBlock.MaximumDataLength / RowLength);

            // Update the rows data
            if (!m_tcInfo.hnidRows.IsEmpty)
            {
                if (m_tcInfo.hnidRows.IsHeapID)
                {
                    m_heap.RemoveItemFromHeap(m_tcInfo.hnidRows.HeapID);
                    CreateSubnodeForRows();
                }
                else
                {
                    if (m_subnodeRows == null)
                    {
                        m_subnodeRows = m_subnodeBTree.GetSubnode(m_tcInfo.hnidRows.NodeID);
                    }
                    m_subnodeRows.Delete(); // this will set the subnode data-tree to null
                    // New data tree will be created when the first row will be added
                    m_subnodeBTree.UpdateSubnodeEntry(m_tcInfo.hnidRows.NodeID, null, null);
                }

                for (int index = 0; index < rows.Count; index++)
                {
                    AddRowToSubnode(index, rows[index]);
                }
            }

            UpdateTableContextInfo();
        }
示例#13
0
 public static int Compare(TableColumnDescriptor a, TableColumnDescriptor b)
 {
     return(a.Tag.CompareTo(b.Tag));
 }