using System; using System.Runtime.InteropServices; namespace Trinet.Core.IO.Ntfs { internal sealed class StreamName : IDisposable { #region Private Data private static readonly SafeHGlobalHandle _invalidBlock = SafeHGlobalHandle.Invalid(); private SafeHGlobalHandle _memoryBlock = _invalidBlock; #endregion #region Constructor /// /// Initializes a new instance of the class. /// public StreamName() { } #endregion #region Properties /// /// Returns the handle to the block of memory. /// /// /// The representing the block of memory. /// public SafeHGlobalHandle MemoryBlock { get { return _memoryBlock; } } #endregion #region Methods /// /// Performs application-defined tasks associated with freeing, /// releasing, or resetting unmanaged resources. /// public void Dispose() { if (!_memoryBlock.IsInvalid) { _memoryBlock.Dispose(); _memoryBlock = _invalidBlock; } } /// /// Ensures that there is sufficient memory allocated. /// /// /// The required capacity of the block, in bytes. /// /// /// There is insufficient memory to satisfy the request. /// public void EnsureCapacity(int capacity) { int currentSize = _memoryBlock.IsInvalid ? 0 : _memoryBlock.Size; if (capacity > currentSize) { if (0 != currentSize) currentSize <<= 1; if (capacity > currentSize) currentSize = capacity; if (!_memoryBlock.IsInvalid) _memoryBlock.Dispose(); _memoryBlock = SafeHGlobalHandle.Allocate(currentSize); } } /// /// Reads the Unicode string from the memory block. /// /// /// The length of the string to read, in characters. /// /// /// The string read from the memory block. /// public string ReadString(int length) { if (0 >= length || _memoryBlock.IsInvalid) return null; if (length > _memoryBlock.Size) length = _memoryBlock.Size; return Marshal.PtrToStringUni(_memoryBlock.DangerousGetHandle(), length); } /// /// Reads the string, and extracts the stream name. /// /// /// The length of the string to read, in characters. /// /// /// The stream name. /// public string ReadStreamName(int length) { string name = this.ReadString(length); if (!string.IsNullOrEmpty(name)) { // Name is of the format ":NAME:$DATA\0" int separatorIndex = name.IndexOf(SafeNativeMethods.StreamSeparator, 1); if (-1 != separatorIndex) { name = name.Substring(1, separatorIndex - 1); } else { // Should never happen! separatorIndex = name.IndexOf('\0'); if (1 < separatorIndex) { name = name.Substring(1, separatorIndex - 1); } else { name = null; } } } return name; } #endregion } }