Esempio n. 1
0
        /// <summary>
        /// http://social.msdn.microsoft.com/Forums/en-US/os_binaryfile/thread/a5f9c653-40f5-4638-85d3-00c54607d984/
        /// Outlook 2003 MUST have a valid rgbFillLevel for write operations
        /// </summary>
        private void UpdateFillLevelMap()
        {
            int blocksToProcess     = Math.Min(m_dataTree.DataBlockCount, 8);
            HeapOnNodeHeader header = this.HeapHeader;

            for (int blockIndex = 0; blockIndex < blocksToProcess; blockIndex++)
            {
                if (m_blocksToUpdate.Contains(blockIndex))
                {
                    HeapOnNodeBlockData blockData = GetBlockData(blockIndex);
                    byte fillLevel = HeapOnNodeHelper.GetBlockFillLevel(blockData);
                    header.rgbFillLevel[blockIndex] = fillLevel;
                }
            }
            UpdateHeapHeader(header);

            for (int blockIndex = 8; blockIndex < m_dataTree.DataBlockCount; blockIndex += 128)
            {
                int blocksLeft = m_dataTree.DataBlockCount - blockIndex;
                blocksToProcess = Math.Min(blocksLeft, 128);
                HeapOnNodeBitmapHeader bitmapHeader = GetBitmapHeader(blockIndex);
                for (int blockOffset = 0; blockOffset < blocksToProcess; blockOffset++)
                {
                    if (m_blocksToUpdate.Contains(blockIndex + blockOffset))
                    {
                        HeapOnNodeBlockData blockData = GetBlockData(blockIndex + blockOffset);
                        byte fillLevel = HeapOnNodeHelper.GetBlockFillLevel(blockData);
                        bitmapHeader.rgbFillLevel[blockOffset] = fillLevel;
                    }
                }
                UpdateBitmapHeader(blockIndex, bitmapHeader);

                blocksLeft -= blocksToProcess;
            }
        }
Esempio n. 2
0
 private void UpdateBuffer(int blockIndex, HeapOnNodeBlockData blockData)
 {
     m_buffer[blockIndex] = blockData;
     if (!m_blocksToUpdate.Contains(blockIndex))
     {
         m_blocksToUpdate.Add(blockIndex);
     }
 }
Esempio n. 3
0
        public void FlushToDataTree()
        {
            UpdateFillLevelMap();

            foreach (int blockIndex in m_blocksToUpdate)
            {
                HeapOnNodeBlockData blockData = m_buffer[blockIndex];
                m_dataTree.UpdateDataBlock(blockIndex, blockData.GetBytes());
            }

            m_blocksToUpdate.Clear();
        }
Esempio n. 4
0
 private HeapOnNodeBlockData GetBlockData(int blockIndex)
 {
     if (!m_buffer.ContainsKey(blockIndex))
     {
         HeapOnNodeBlockData blockData = GetBlockDataUnbuffered(blockIndex);
         m_buffer.Add(blockIndex, blockData);
         return(blockData);
     }
     else
     {
         return(m_buffer[blockIndex]);
     }
 }
Esempio n. 5
0
 /// <summary>
 /// We trim freed items (items at the end of the block that can be removed without corrupting HeapIDs)
 /// (so that new items could be added in their place)
 /// </summary>
 /// <param name="blockData"></param>
 private void CompactBlockData(HeapOnNodeBlockData blockData)
 {
     for (int itemIndex = blockData.HeapItems.Count - 1; itemIndex >= 0; itemIndex--)
     {
         if (blockData.HeapItems[itemIndex].Length == 0)
         {
             blockData.HeapItems.RemoveAt(itemIndex);
         }
         else
         {
             break;
         }
     }
 }
Esempio n. 6
0
        public void RemoveItemFromHeap(HeapID heapID)
        {
            int blockIndex = heapID.hidBlockIndex;
            HeapOnNodeBlockData blockData = GetBlockData(blockIndex);

            // We can't remove the HeapItem, because then the HeapID of the subsequent items will be incorrect
            // So instead we put an empty item instead of the item we wish to remove.
            // (We must not forget to update the HNPAGEMAP's cFree, otherwise outlook will report that the pst is corrupt)

            // hidIndex is one-based
            blockData.HeapItems[heapID.hidIndex - 1] = new byte[0];
            CompactBlockData(blockData);
            UpdateBuffer(blockIndex, blockData);
        }
Esempio n. 7
0
        public HeapID AddItemToHeap(byte[] itemBytes)
        {
            if (itemBytes.Length > MaximumAllocationLength)
            {
                throw new ArgumentException("Maximum size of a heap allocation is 3580 bytes");
            }

            if (itemBytes.Length == 0)
            {
                return(HeapID.EmptyHeapID);
            }

            // We can use the Header / BitmapHeader to locate available space,
            // but the final authority is HNPAGEMAP located at the end of each block
            // Note: we are only required to maintain HNPAGEMAP
            for (int blockIndex = 0; blockIndex < m_dataTree.DataBlockCount; blockIndex++)
            {
                HeapOnNodeBlockData blockData = GetBlockData(blockIndex);
                // We need space for the item itself and for a place for it in the page map (2 bytes)
                // We also have to make sure we do not allocate more items then can be represented by hidIndex
                if (blockData.AvailableSpace > itemBytes.Length + 2 && blockData.HeapItems.Count < HeapID.MaximumHidIndex)
                {
                    blockData.HeapItems.Add(itemBytes);
                    UpdateBuffer(blockIndex, blockData);

                    // hidIndex is one-based
                    ushort hidIndex = (ushort)(blockData.HeapItems.Count);
                    return(new HeapID((ushort)blockIndex, hidIndex));
                }
            }

            // no space found in existing blocks, we need to allocate new data block
            int newBlockIndex = m_dataTree.DataBlockCount;
            HeapOnNodeBlockData newBlockData;

            if (newBlockIndex % 128 == 8)
            {
                newBlockData = new HeapOnNodeBitmapBlockData();
            }
            else
            {
                newBlockData = new HeapOnNodePageBlockData();
            }
            newBlockData.HeapItems.Add(itemBytes);
            this.DataTree.AddDataBlock(newBlockData.GetBytes());
            // hidIndex is one-based
            return(new HeapID((ushort)newBlockIndex, 1));
        }
Esempio n. 8
0
        public byte[] GetHeapItem(HeapID hid)
        {
            HeapOnNodeBlockData blockData = GetBlockData(hid.hidBlockIndex);

            // hidIndex is one-based
            if (hid.hidIndex == 0)
            {
                throw new ArgumentOutOfRangeException("hidIndex", "PST is corrupted, hidIndex cannot be 0");
            }
            else if (hid.hidIndex - 1 < blockData.HeapItems.Count)
            {
                return(blockData.HeapItems[hid.hidIndex - 1]);
            }
            else
            {
                throw new ArgumentOutOfRangeException("hidIndex", "PST is corrupted, hidIndex is out of range");
            }
        }
Esempio n. 9
0
        /// <summary>
        /// Replace item in-place, to avoid issues, item should not be larger than the old item
        /// </summary>
        /// <returns>true if success</returns>
        private bool TryReplacingHeapItemInPlace(HeapID heapID, byte[] itemBytes)
        {
            int blockIndex = heapID.hidBlockIndex;
            HeapOnNodeBlockData blockData = GetBlockData(blockIndex);
            // hidIndex is one-based
            int oldSize = blockData.HeapItems[heapID.hidIndex - 1].Length;
            int newSize = itemBytes.Length;

            if (newSize - oldSize <= blockData.AvailableSpace)
            {
                blockData.HeapItems[heapID.hidIndex - 1] = itemBytes;
                UpdateBuffer(blockIndex, blockData);
                return(true);
            }
            else
            {
                return(false);
            }
        }
Esempio n. 10
0
        public static byte GetBlockFillLevel(HeapOnNodeBlockData blockData)
        {
            int availableSpace = blockData.AvailableSpace;

            if (availableSpace >= 3584)
            {
                return(0x00);
            }
            else if (availableSpace >= 2560)
            {
                return(0x01);
            }
            else if (availableSpace >= 2048)
            {
                return(0x02);
            }
            else if (availableSpace >= 1792)
            {
                return(0x03);
            }
            else if (availableSpace >= 1536)
            {
                return(0x04);
            }
            else if (availableSpace >= 1280)
            {
                return(0x05);
            }
            else if (availableSpace >= 1024)
            {
                return(0x06);
            }
            else if (availableSpace >= 768)
            {
                return(0x07);
            }
            else if (availableSpace >= 512)
            {
                return(0x08);
            }
            else if (availableSpace >= 256)
            {
                return(0x09);
            }
            else if (availableSpace >= 128)
            {
                return(0x0A);
            }
            else if (availableSpace >= 64)
            {
                return(0x0B);
            }
            else if (availableSpace >= 32)
            {
                return(0x0C);
            }
            else if (availableSpace >= 16)
            {
                return(0x0D);
            }
            else if (availableSpace >= 8)
            {
                return(0x0E);
            }
            else
            {
                return(0x0F);
            }
        }
Esempio n. 11
0
        /// <summary>
        /// For discovery purposes
        /// </summary>
        public int GetBlockibHnpm(int blockIndex)
        {
            HeapOnNodeBlockData blockData = GetBlockData(blockIndex);

            return(blockData.ibHnpm);
        }
Esempio n. 12
0
        public int GetItemCount(int blockIndex)
        {
            HeapOnNodeBlockData blockData = GetBlockData(blockIndex);

            return(blockData.HeapItems.Count);
        }