public static unsafe string SFileGetFileHash(MpqFileSafeHandle hFile)
        {
            if (hFile.IsInvalid || hFile.IsClosed)
            {
                throw new InvalidOperationException();
            }

            IntPtr           handle = hFile.DangerousGetHandle();
            _TMPQFileHeader *header = (_TMPQFileHeader *)handle.ToPointer();

            byte *md5 = header->pFileEntry->md5;

            char[] chars = new char[32];

            fixed(char *c = chars)
            {
                int b;

                for (int i = 0; i < 16; i++)
                {
                    b            = md5[i] >> 4;
                    c[i * 2]     = (char)(55 + b + (((b - 10) >> 31) & -7));
                    b            = md5[i] & 0xF;
                    c[i * 2 + 1] = (char)(55 + b + (((b - 10) >> 31) & -7));
                }

                return(new string(c).Substring(0, 32));
            }
        }
        internal unsafe MpqFileStream(MpqFileSafeHandle handle, FileAccess accessType, MpqArchive owner)
        {
            _TMPQFileHeader *header = (_TMPQFileHeader *)handle.DangerousGetHandle().ToPointer();

            TFileEntry = *header->pFileEntry;

            FileName    = Marshal.PtrToStringAnsi(TFileEntry.szFileName);
            _handle     = handle;
            _accessType = accessType;
            _owner      = owner;
        }
        public static unsafe uint SFileGetFilePointer(MpqFileSafeHandle hFile)
        {
            if (hFile.IsInvalid || hFile.IsClosed)
            {
                throw new InvalidOperationException();
            }

            _TMPQFileHeader *header = (_TMPQFileHeader *)hFile.DangerousGetHandle().ToPointer();

            return(header->dwFilePos);
        }
        public static unsafe DateTime?SFileGetFileTime(MpqFileSafeHandle hFile)
        {
            if (hFile.IsInvalid || hFile.IsClosed)
            {
                throw new InvalidOperationException();
            }

            IntPtr           handle = hFile.DangerousGetHandle();
            _TMPQFileHeader *header = (_TMPQFileHeader *)handle.ToPointer();
            ulong            time   = header->pFileEntry->FileTime;

            return(time > 0 ? (DateTime?)DateTime.FromFileTimeUtc((long)time) : null);
        }