using System;
using System.Runtime.InteropServices;

#pragma warning disable CA2101 // Specify marshaling for P/Invoke string arguments
#pragma warning disable IDE1006 // Naming Styles
#pragma warning disable SYSLIB1054 // Use 'LibraryImportAttribute' instead of 'DllImportAttribute' to generate P/Invoke marshalling code at compile time
namespace StormLibSharp.Native
{
    internal static class NativeMethods
    {
        private const string STORMLIB = "stormlib.dll";

        #region Functions for manipulation with StormLib global flags

        [DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
        public static extern uint SFileGetLocale();

        [DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
        public static extern uint SFileSetLocale(uint lcNewLocale);

        #endregion

        #region Functions for archive manipulation

        [DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
        public static extern bool SFileOpenArchive(
            [MarshalAs(UnmanagedType.LPTStr)] string szMpqName,
            uint dwPriority,
            SFileOpenArchiveFlags dwFlags,
            out MpqArchiveSafeHandle phMpq
            );

        [DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
        public static extern bool SFileCreateArchive(
            [MarshalAs(UnmanagedType.LPTStr)] string szMpqName,
            uint dwCreateFlags,
            uint dwMaxFileCount,
            out MpqArchiveSafeHandle phMpq
            );

        [DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
        public static extern bool SFileCreateArchive2(
            [MarshalAs(UnmanagedType.LPTStr)] string szMpqName,
            ref SFILE_CREATE_MPQ pCreateInfo,
            out MpqArchiveSafeHandle phMpq
            );

        [DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
        public static extern bool SFileSetDownloadCallback(
            MpqArchiveSafeHandle? hMpq,
            [MarshalAs(UnmanagedType.FunctionPtr)] SFILE_DOWNLOAD_CALLBACK pfnCallback,
            IntPtr pvUserData
            );

        [DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
        public static extern bool SFileFlushArchive(MpqArchiveSafeHandle? hMpq);

        [DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
        public static extern bool SFileCloseArchive(IntPtr hMpq);

        [DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
        public static extern bool SFileCloseArchive(MpqArchiveSafeHandle? hMpq);

        #endregion

        #region Adds another listfile into MPQ.

        [DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
        public static extern int SFileAddListFile(
            MpqArchiveSafeHandle? hMpq,
            [MarshalAs(UnmanagedType.LPStr)] string szListFile
            );

        #endregion

        #region Archive compacting

        [DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
        public static extern bool SFileSetCompactCallback(
            MpqArchiveSafeHandle? hMpq,
            SFILE_COMPACT_CALLBACK? compactCB,
            IntPtr pvUserData
            );

        [DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
        public static extern bool SFileCompactArchive(
            MpqArchiveSafeHandle? hMpq,
            [MarshalAs(UnmanagedType.LPStr)] string szListFile,
            bool bReserved
            );

        #endregion

        #region Maximum file count

        [DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
        public static extern uint SFileGetMaxFileCount(MpqArchiveSafeHandle? hMpq);

        [DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
        public static extern bool SFileSetMaxFileCount(MpqArchiveSafeHandle? hMpq, uint dwMaxFileCount);

        #endregion

        #region Changing (attributes) file

        [DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
        public static extern uint SFileGetAttributes(MpqArchiveSafeHandle? hMpq);

        [DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
        public static extern bool SFileSetAttributes(MpqArchiveSafeHandle? hMpq, uint dwFlags);

        [DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
        public static extern bool SFileUpdateFileAttributes(
            MpqArchiveSafeHandle? hMpq,
            [MarshalAs(UnmanagedType.LPStr)] string szFileName
            );

        #endregion

        #region Functions for manipulation with patch archives

        [DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
        public static extern bool SFileOpenPatchArchive(
            MpqArchiveSafeHandle? hMpq,
            [MarshalAs(UnmanagedType.LPTStr)] string szPatchMpqName,
            [MarshalAs(UnmanagedType.LPStr)] string? szPatchPathPrefix,
            uint dwFlags
            );

        [DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
        public static extern bool SFileIsPatchedArchive(MpqArchiveSafeHandle? hMpq);

        #endregion

        #region Functions for file manipulation

        [DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
        public static extern bool SFileHasFile(
            MpqArchiveSafeHandle? hMpq,
            [MarshalAs(UnmanagedType.LPStr)] string szFileName
            );

        [DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
        public static extern bool SFileOpenFileEx(
            MpqArchiveSafeHandle? hMpq,
            [MarshalAs(UnmanagedType.LPStr)] string szFileName,
            uint dwSearchScope,
            out MpqFileSafeHandle phFile
            );

        [DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
        public static extern uint SFileGetFileSize(MpqFileSafeHandle? hFile, ref uint pdwFileSizeHigh);

        public static unsafe uint SFileGetFilePointer(
            MpqFileSafeHandle? hFile
            )
        {
            if (hFile is null || hFile.IsInvalid || hFile.IsClosed)
                throw new InvalidOperationException();

            IntPtr handle = hFile.DangerousGetHandle();
            _TMPQFileHeader* header = (_TMPQFileHeader*)handle.ToPointer();
            return header->dwFilePos;
        }

        //public static unsafe uint SFileGetFileSize(
        //    MpqFileSafeHandle? hFile
        //    )
        //{
        //    if (hFile.IsInvalid || hFile.IsClosed)
        //        throw new InvalidOperationException();

        //    IntPtr handle = hFile.DangerousGetHandle();
        //    _TMPQFileHeader* header = (_TMPQFileHeader*)handle.ToPointer();
        //    return header->pFileEntry->dwFileSize;
        //}

        [DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
        public static extern uint SFileSetFilePointer(
            MpqFileSafeHandle? hFile,
            uint lFilePos,
            ref uint plFilePosHigh,
            uint dwMoveMethod
            );

        [DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
        public static extern bool SFileReadFile(
            MpqFileSafeHandle? hFile,
            IntPtr lpBuffer,
            uint dwToRead,
            out uint pdwRead,
            ref System.Threading.NativeOverlapped lpOverlapped
            );

        [DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
        public static extern bool SFileCloseFile(IntPtr hFile);

        [DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
        public static extern bool SFileCloseFile(MpqFileSafeHandle? hFile);

        #region Retrieving info about a file in the archive

        [DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
        public static extern bool SFileGetFileInfo(
            IntPtr hMpqOrFile,
            SFileInfoClass InfoClass,
            IntPtr pvFileInfo,
            uint cbFileInfoSize,
            out uint pcbLengthNeeded
            );

        [DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
        public static extern bool SFileGetFileInfo(
            MpqArchiveSafeHandle? hMpqOrFile,
            SFileInfoClass InfoClass,
            IntPtr pvFileInfo,
            uint cbFileInfoSize,
            out uint pcbLengthNeeded
            );

        [DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
        public static extern bool SFileGetFileInfo(
            MpqFileSafeHandle hMpqOrFile,
            SFileInfoClass InfoClass,
            IntPtr pvFileInfo,
            uint cbFileInfoSize,
            out uint pcbLengthNeeded
            );

        [DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
        public static extern bool SFileGetFileName(
            MpqFileSafeHandle? hFile,
            [MarshalAs(UnmanagedType.LPStr)] out string szFileName
            );

        [DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
        public static extern bool SFileFreeFileInfo(
            IntPtr pvFileInfo,
            SFileInfoClass infoClass
            );

        #endregion

        [DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
        public static extern bool SFileExtractFile(
            MpqArchiveSafeHandle? hMpq,
            [MarshalAs(UnmanagedType.LPStr)] string szToExtract,
            [MarshalAs(UnmanagedType.LPTStr)] string szExtracted,
            uint dwSearchScope
            );

        #endregion

        #region Functions for file and archive verification

        [DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
        public static extern bool SFileGetFileChecksums(
            MpqArchiveSafeHandle? hMpq,
            [MarshalAs(UnmanagedType.LPStr)] string szFileName,
            out uint pdwCrc32,
            IntPtr pMD5
            );

        [DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
        public static extern uint SFileVerifyFile(
            MpqArchiveSafeHandle? hMpq,
            [MarshalAs(UnmanagedType.LPStr)] string szFileName,
            uint dwFlags
            );

        [DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
        public static extern int SFileVerifyRawData(
            MpqArchiveSafeHandle? hMpq,
            uint dwWhatToVerify,
            [MarshalAs(UnmanagedType.LPStr)] string szFileName
            );

        [DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
        public static extern uint SFileVerifyArchive(MpqArchiveSafeHandle? hMpq);

        #endregion

        #region Functions for file searching

        [DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
        public static extern IntPtr SFileFindFirstFile(
            MpqArchiveSafeHandle? hMpq,
            [MarshalAs(UnmanagedType.LPStr)] string szMask,
            out _SFILE_FIND_DATA lpFindFileData,
            [MarshalAs(UnmanagedType.LPStr)] string szListFile
            );

        [DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
        public static extern bool SFileFindNextFile(
            IntPtr hFind,
            [In, Out] ref _SFILE_FIND_DATA lpFindFileData
            );

        [DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
        public static extern bool SFileFindClose(IntPtr hFind);

        [DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
        public static extern IntPtr SListFileFindFirstFile(
            MpqArchiveSafeHandle? hMpq,
            [MarshalAs(UnmanagedType.LPStr)] string szListFile,
            [MarshalAs(UnmanagedType.LPStr)] string szMask,
            [In, Out] ref _SFILE_FIND_DATA lpFindFileData
            );

        [DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
        public static extern bool SListFileFindNextFile(
            IntPtr hFind,
            [In, Out] ref _SFILE_FIND_DATA lpFindFileData
            );

        [DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
        public static extern bool SListFileFindClose(IntPtr hFind);

        #endregion

        #region Locale support

        [DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
        public static extern int SFileEnumLocales(
            MpqArchiveSafeHandle? hMpq,
            [MarshalAs(UnmanagedType.LPStr)] string szFileName,
            IntPtr plcLocales,
            ref uint pdwMaxLocales,
            uint dwSearchScope
            );

        #endregion

        #region Support for adding files to the MPQ

        [DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
        public static extern bool SFileCreateFile(
            MpqArchiveSafeHandle? hMpq,
            [MarshalAs(UnmanagedType.LPStr)] string szArchiveName,
            ulong fileTime,
            uint dwFileSize,
            uint lcLocale,
            uint dwFlags,
            out IntPtr phFile
            );

        [DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
        public static extern bool SFileWriteFile(
            MpqFileSafeHandle? hFile,
            IntPtr pvData,
            uint dwSize,
            uint dwCompression
            );

        [DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
        public static extern bool SFileFinishFile(MpqFileSafeHandle? hFile);

        [DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
        public static extern bool SFileAddFileEx(
            MpqArchiveSafeHandle? hMpq,
            [MarshalAs(UnmanagedType.LPTStr)] string szFileName,
            [MarshalAs(UnmanagedType.LPStr)] string szArchivedName,
            uint dwFlags,
            uint dwCompression,
            uint dwCompressionNext
            );

        [DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
        public static extern bool SFileAddFile(
            MpqArchiveSafeHandle? hMpq,
            [MarshalAs(UnmanagedType.LPTStr)] string szFileName,
            [MarshalAs(UnmanagedType.LPStr)] string szArchivedName,
            uint dwFlags
            );

        [DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
        public static extern bool SFileAddWave(
            MpqArchiveSafeHandle? hMpq,
            [MarshalAs(UnmanagedType.LPTStr)] string szFileName,
            [MarshalAs(UnmanagedType.LPStr)] string szArchivedName,
            uint dwFlags,
            uint dwQuality
            );

        [DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
        public static extern bool SFileRemoveFile(
            MpqArchiveSafeHandle? hMpq,
            [MarshalAs(UnmanagedType.LPStr)] string szFileName,
            uint dwSearchScope
            );

        [DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
        public static extern bool SFileRenameFile(
            MpqArchiveSafeHandle? hMpq,
            [MarshalAs(UnmanagedType.LPStr)] string szOldFileName,
            [MarshalAs(UnmanagedType.LPStr)] string szNewFileName
            );

        [DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
        public static extern bool SFileSetFileLocale(
            MpqFileSafeHandle? hFile,
            uint lcNewLocale
            );

        [DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
        public static extern bool SFileSetDataCompression(uint DataCompression);

        [DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
        public static extern bool SFileSetAddFileCallback(
            MpqArchiveSafeHandle? hMpq,
            SFILE_ADDFILE_CALLBACK AddFileCB,
            IntPtr pvUserData
            );

        #endregion

        #region Compression and decompression

        [DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
        public static extern int SCompImplode(
            IntPtr pvOutBuffer,
            ref int pcbOutBuffer,
            IntPtr pvInBuffer,
            int cbInBuffer
            );

        [DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
        public static extern int SCompExplode(
            IntPtr pvOutBuffer,
            ref int pcbOutBuffer,
            IntPtr pvInBuffer,
            int cbInBuffer
            );

        [DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
        public static extern int SCompCompress(
            IntPtr pvOutBuffer,
            ref int pcbOutBuffer,
            IntPtr pvInBuffer,
            int cbInBuffer,
            uint uCompressionMask,
            int nCmpType,
            int nCmpLevel
            );

        [DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
        public static extern int SCompDecompress(
            IntPtr pvOutBuffer,
            ref int pcbOutBuffer,
            IntPtr pvInBuffer,
            int cbInBuffer
            );

        [DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
        public static extern int SCompDecompress2(
            IntPtr pvOutBuffer,
            ref int pcbOutBuffer,
            IntPtr pvInBuffer,
            int cbInBuffer
            );

        #endregion
    }

#pragma warning disable CS0649

#pragma warning disable CS0169
#pragma warning disable IDE0044
#pragma warning disable IDE0051
    internal struct SFILE_CREATE_MPQ
    {
        public uint cbSize;
        public uint dwMpqVersion;
        private IntPtr pvUserData;
        private uint cbUserData;
        public uint dwStreamFlags;
        public uint dwFileFlags1;
        public uint dwFileFlags2;
        public uint dwAttrFlags;
        public uint dwSectorSize;
        public uint dwRawChunkSize;
        public uint dwMaxFileCount;
    }
#pragma warning restore CS0169
#pragma warning restore IDE0044
#pragma warning restore IDE0051

    internal unsafe struct _SFILE_FIND_DATA
    {
        public fixed char cFileName[260];                  // Full name of the found file

        public IntPtr szPlainName;                         // Plain name of the found file
        public uint dwHashIndex;                          // Hash table index for the file
        public uint dwBlockIndex;                          // Block table index for the file
        public uint dwFileSize;                            // File size in bytes
        public uint dwFileFlags;                           // MPQ file flags
        public uint dwCompSize;                            // Compressed file size
        public uint dwFileTimeLo;                          // Low 32-bits of the file time (0 if not present)
        public uint dwFileTimeHi;                          // High 32-bits of the file time (0 if not present)
        public uint lcLocale;                              // Locale version
    }

    internal unsafe struct _TFileEntry
    {
        public ulong FileNameHash;
        public ulong ByteOffset;
        public ulong FileTime;
        public uint dwHashIndex;
        public uint dwFileSize;
        public uint dwCmpSize;
        public uint dwFlags;
        public ushort lcLocale;
        public ushort wPlatform;
        public uint dwCrc32;
        public fixed byte md5[16];
        public IntPtr szFileName;
    }

    // Provides enough of _TMPQFile to get to the file size and current position.
    internal unsafe struct _TMPQFileHeader
    {
        public IntPtr pStream;
        public IntPtr ha;
        public _TFileEntry* pFileEntry;
        public uint dwFileKey;
        public uint dwFilePos;
    }
#pragma warning restore CS0649
}
