Current News
Archived News
Search News
Discussion Forum


Old Forum
Install Programs More Downloads...
Troubleshooting
Source Code
Format Specs.
Misc. Information
Non-SF Stuff
Links




ShadowFlare [Fri, 4 Jul 2008 04:17:10 +0000 (22:17 -0600)]
22 files changed:
SComp.h [new file with mode: 0644]
SFmpq in multi-threaded applications.txt [new file with mode: 0644]
SFmpq_static.cpp [new file with mode: 0644]
SFmpq_static.h [new file with mode: 0644]
SFmpqapi.bas [new file with mode: 0644]
SFmpqapi.cpp [new file with mode: 0644]
SFmpqapi.def [new file with mode: 0644]
SFmpqapi.dsp [new file with mode: 0644]
SFmpqapi.dsw [new file with mode: 0644]
SFmpqapi.h [new file with mode: 0644]
SFmpqapi.odl [new file with mode: 0644]
SFmpqapi.rc [new file with mode: 0644]
SFmpqapiVB.rtf [new file with mode: 0644]
SFmpqapi_no-lib.cpp [new file with mode: 0644]
SFmpqapi_no-lib.h [new file with mode: 0644]
SFmpqlib.dsp [new file with mode: 0644]
WinError.bas [new file with mode: 0644]
about [new file with mode: 0644]
license.txt [new file with mode: 0644]
linux/windows.cpp [new file with mode: 0644]
linux/windows.h [new file with mode: 0644]
resource.h [new file with mode: 0644]

diff --git a/SComp.h b/SComp.h
new file mode 100644 (file)
index 0000000..37a8e93
--- /dev/null
+++ b/SComp.h
@@ -0,0 +1,25 @@
+// SComp.h - Header for main compression/decompression routines
+// License information for this code is in license.txt
+
+#ifndef S_COMP_INCLUDED
+#define S_COMP_INCLUDED
+
+#if (defined(_WIN32) || defined(WIN32)) && !defined(NO_WINDOWS_H)
+#include <windows.h>
+#else
+#include "wintypes.h"
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+BOOL WINAPI SCompCompress(LPVOID lpvDestinationMem, LPDWORD lpdwCompressedSize, LPVOID lpvSourceMem, DWORD dwDecompressedSize, DWORD dwCompressionType, DWORD dwCompressionSubType, DWORD dwCompressLevel);
+BOOL WINAPI SCompDecompress(LPVOID lpvDestinationMem, LPDWORD lpdwDecompressedSize, LPVOID lpvSourceMem, DWORD dwCompressedSize);
+
+#ifdef __cplusplus
+};  // extern "C" 
+#endif
+
+#endif
+
diff --git a/SFmpq in multi-threaded applications.txt b/SFmpq in multi-threaded applications.txt
new file mode 100644 (file)
index 0000000..ef09148
--- /dev/null
@@ -0,0 +1,73 @@
+====================================
+SFmpq in multi-threaded applications
+====================================
+
+A note about archive and file handles:  In most cases, archive and file handles should not be shared between threads.  Instead, open a new handle for each thread that will be reading from or writing to the archive or file.  However, if no threads have direct access to the handle and only one is able to use the archive or file at a time, sharing handles can be done.  Also, archive handles may be shared between threads when you are only reading files from the archive.
+
+-------------------------------
+Always nonthread-safe functions
+-------------------------------
+SFileOpenFileAsArchive
+SFileOpenArchive
+SFileCloseArchive
+SFileOpenFile
+SFileOpenFileEx
+SFileCloseFile
+SFileSetLocale (same value is used for all threads, so changing it for one changes it for all)
+SFileSetBasePath (should not be called at same time as itself or SFileGetBasePath, same value is used for all threads)
+SFileSetArchivePriority
+MpqOpenArchiveForUpdate
+MpqCloseUpdatedArchive
+MpqAddFileToArchiveEx
+MpqAddFileToArchive
+MpqAddWaveToArchive
+MpqAddFileFromBufferEx
+MpqAddFileFromBuffer
+MpqAddWaveFromBuffer
+MpqRenameFile
+MpqRenameAndSetFileLocale
+MpqDeleteFile
+MpqDeleteFileWithLocale
+MpqCompactArchive
+MpqSetFileLocale
+
+-----------------------------------
+Conditionally thread-safe functions
+-----------------------------------
+
+Note:  All file reading functions are thread-safe if separate handles are used for each thread and no functions are being used that would change the archive or files in any way.  If an archive is opened with write access, no other thread should be able to open another handle to it.
+
+Should not be called while opening or closing archives or files
+---------------------------------------------------------------
+SFileGetArchiveName
+SFileGetFileName
+SFileGetFileInfo
+
+Should not be called if the archive or file handle being used will be closed
+----------------------------------------------------------------------------
+SFileGetFileSize
+SFileGetFileArchive
+SFileSetFilePointer
+SFileReadFile
+SFileListFiles
+SFileFindMpqHeader
+
+Other conditions
+----------------
+SFileGetBasePath (should not be called at same time as SFileSetBasePath)
+
+----------------------------
+Always thread-safe functions
+----------------------------
+SFileDestroy
+StormDestroy
+SFMpqDestroy
+MpqInitialize
+MpqGetVersionString
+MpqGetVersion
+SFMpqGetVersionString
+SFMpqGetVersionString2
+SFMpqGetVersion
+AboutSFMpq
+SFMpqCompareVersion
+
diff --git a/SFmpq_static.cpp b/SFmpq_static.cpp
new file mode 100644 (file)
index 0000000..e554f4d
--- /dev/null
@@ -0,0 +1,12 @@
+/* License information for this code is in license.txt */
+
+#include "..\\SFmpqapi\\SFmpq_static.h"
+
+void LoadSFMpq()
+{
+}
+
+void FreeSFMpq()
+{
+}
+
diff --git a/SFmpq_static.h b/SFmpq_static.h
new file mode 100644 (file)
index 0000000..f127873
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+
+  ShadowFlare MPQ Static Library. (c) ShadowFlare Software 2002-2003
+  License information for this code is in license.txt
+
+*/
+
+#ifndef SHADOWFLARE_MPQ_LIB_INCLUDED
+#define SHADOWFLARE_MPQ_LIB_INCLUDED
+
+#ifndef SFMPQ_STATIC
+#define SFMPQ_STATIC
+#endif
+
+#include "SFmpqapi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// These no longer need to be called.  They are only provided for
+// compatibility with older versions of this static library
+void LoadSFMpq();
+void FreeSFMpq();
+
+#ifdef __cplusplus
+};  // extern "C" 
+#endif
+
+#endif
+
diff --git a/SFmpqapi.bas b/SFmpqapi.bas
new file mode 100644 (file)
index 0000000..9389864
--- /dev/null
@@ -0,0 +1,312 @@
+Attribute VB_Name = "SFmpqapi"
+Option Explicit
+
+'  ShadowFlare MPQ API Library. (c) ShadowFlare Software 2002-2008
+'  License information for this code is in license.txt
+
+'  All functions below are actual functions that are part of this
+'  library and do not need any additional dll files.  It does not
+'  even require Storm to be able to decompress or compress files.
+
+'  This library emulates the interface of Lmpqapi and Storm MPQ
+'  functions, so it may be used as a replacement for them in
+'  MPQ extractors/archivers without even needing to recompile
+'  the program that uses Lmpqapi or Storm.  It has a few features
+'  not included in Lmpqapi and Storm, such as extra flags for some
+'  functions, setting the locale ID of existing files, and adding
+'  files without having to write them somewhere else first.  Also,
+'  MPQ handles used by functions prefixed with "SFile" and "Mpq"
+'  can be used interchangably; all functions use the same type
+'  of MPQ handles.  You cannot, however, use handles from this
+'  library with storm or lmpqapi or vice-versa.  Doing so will
+'  most likely result in a crash.
+
+'  Revision History:
+'  06/12/2002 1.07 (ShadowFlare)
+'  - No longer requires Storm.dll to compress or decompress
+'    Warcraft III files
+'  - Added SFileListFiles for getting names and information
+'    about all of the files in an archive
+'  - Fixed a bug with renaming and deleting files
+'  - Fixed a bug with adding wave compressed files with
+'    low compression setting
+'  - Added a check in MpqOpenArchiveForUpdate for proper
+'    dwMaximumFilesInArchive values (should be a number that
+'    is a power of 2).  If it is not a proper value, it will
+'    be rounded up to the next higher power of 2
+
+'  05/09/2002 1.06 (ShadowFlare)
+'  - Compresses files without Storm.dll!
+'  - If Warcraft III is installed, this library will be able to
+'    find Storm.dll on its own. (Storm.dll is needed to
+'    decompress Warcraft III files)
+'  - Fixed a bug where an embedded archive and the file that
+'    contains it would be corrupted if the archive was modified
+'  - Able to open all .w3m maps now
+
+'  29/06/2002 1.05 (ShadowFlare)
+'  - Supports decompressing files from Warcraft III MPQ archives
+'    if using Storm.dll from Warcraft III
+'  - Added MpqAddFileToArchiveEx and MpqAddFileFromBufferEx for
+'    using extra compression types
+
+'  29/05/2002 1.04 (ShadowFlare)
+'  - Files can be compressed now!
+'  - Fixed a bug in SFileReadFile when reading data not aligned
+'    to the block size
+'  - Optimized some of SFileReadFile's code.  It can read files
+'    faster now
+'  - SFile functions may now be used to access files not in mpq
+'    archives as you can with the real storm functions
+'  - MpqCompactArchive will no longer corrupt files with the
+'    MODCRYPTKEY flag as long as the file is either compressed,
+'    listed in "(listfile)", is "(listfile)", or is located in
+'    the same place in the compacted archive; so it is safe
+'    enough to use it on almost any archive
+'  - Added MpqAddWaveFromBuffer
+'  - Better handling of archives with no files
+'  - Fixed compression with COMPRESS2 flag
+
+'  15/05/2002 1.03 (ShadowFlare)
+'  - Supports adding files with the compression attribute (does
+'    not actually compress files).  Now archives created with
+'    this dll can have files added to them through lmpqapi
+'    without causing staredit to crash
+'  - SFileGetBasePath and SFileSetBasePath work more like their
+'    Storm equivalents now
+'  - Implemented MpqCompactArchive, but it is not finished yet.
+'    In its current state, I would recommend against using it
+'    on archives that contain files with the MODCRYPTKEY flag,
+'    since it will corrupt any files with that flag
+'  - Added SFMpqGetVersionString2 which may be used in Visual
+'    Basic to get the version string
+
+'  07/05/2002 1.02 (ShadowFlare)
+'  - SFileReadFile no longer passes the lpOverlapped parameter it
+'    receives to ReadFile.  This is what was causing the function
+'    to fail when used in Visual Basic
+'  - Added support for more Storm MPQ functions
+'  - GetLastError may now be used to get information about why a
+'    function failed
+
+'  01/05/2002 1.01 (ShadowFlare)
+'  - Added ordinals for Storm MPQ functions
+'  - Fixed MPQ searching functionality of SFileOpenFileEx
+'  - Added a check for whether a valid handle is given when
+'    SFileCloseArchive is called
+'  - Fixed functionality of SFileSetArchivePriority when multiple
+'    files are open
+'  - File renaming works for all filenames now
+'  - SFileReadFile no longer reallocates the buffer for each block
+'    that is decompressed.  This should make SFileReadFile at least
+'    a little faster
+
+'  30/04/2002 1.00 (ShadowFlare)
+'  - First version.
+'  - Compression not yet supported
+'  - Does not use SetLastError yet, so GetLastError will not return any
+'    errors that have to do with this library
+'  - MpqCompactArchive not implemented
+
+'  Any comments or suggestions are accepted at blakflare@hotmail.com (ShadowFlare)
+
+Type SFMPQVERSION
+    Major As Integer
+    Minor As Integer
+    Revision As Integer
+    Subrevision As Integer
+End Type
+
+' MpqInitialize does nothing.  It is only provided for
+' compatibility with MPQ archivers that use lmpqapi.
+Declare Function MpqInitialize Lib "SFmpq.dll" () As Boolean
+
+Declare Function MpqGetVersionString Lib "SFmpq.dll" () As String
+Declare Function MpqGetVersion Lib "SFmpq.dll" () As Single
+
+Declare Sub SFMpqDestroy Lib "SFmpq.dll" () ' This no longer needs to be called.  It is only provided for compatibility with older versions
+
+' SFMpqGetVersionString2's return value is the required length of the buffer plus
+' the terminating null, so use SFMpqGetVersionString2(ByVal 0&, 0) to get the length.
+Declare Function SFMpqGetVersionString Lib "SFmpq.dll" () As String
+Declare Function SFMpqGetVersionString2 Lib "SFmpq.dll" (ByVal lpBuffer As String, ByVal dwBufferLength As Long) As Long
+Declare Function SFMpqGetVersion Lib "SFmpq.dll" () As SFMPQVERSION
+
+' General error codes
+Public Const MPQ_ERROR_MPQ_INVALID As Long = &H85200065
+Public Const MPQ_ERROR_FILE_NOT_FOUND As Long = &H85200066
+Public Const MPQ_ERROR_DISK_FULL As Long = &H85200068 'Physical write file to MPQ failed. Not sure of exact meaning
+Public Const MPQ_ERROR_HASH_TABLE_FULL As Long = &H85200069
+Public Const MPQ_ERROR_ALREADY_EXISTS As Long = &H8520006A
+Public Const MPQ_ERROR_BAD_OPEN_MODE As Long = &H8520006C 'When MOAU_READ_ONLY is used without MOAU_OPEN_EXISTING
+
+Public Const MPQ_ERROR_COMPACT_ERROR As Long = &H85300001
+
+' MpqOpenArchiveForUpdate flags
+Public Const MOAU_CREATE_NEW As Long = &H0
+Public Const MOAU_CREATE_ALWAYS As Long = &H8 'Was wrongly named MOAU_CREATE_NEW
+Public Const MOAU_OPEN_EXISTING As Long = &H4
+Public Const MOAU_OPEN_ALWAYS As Long = &H20
+Public Const MOAU_READ_ONLY As Long = &H10 'Must be used with MOAU_OPEN_EXISTING
+Public Const MOAU_MAINTAIN_LISTFILE As Long = &H1
+
+' MpqAddFileToArchive flags
+Public Const MAFA_EXISTS As Long = &H80000000 'Will be added if not present
+Public Const MAFA_UNKNOWN40000000 As Long = &H40000000
+Public Const MAFA_MODCRYPTKEY As Long = &H20000
+Public Const MAFA_ENCRYPT As Long = &H10000
+Public Const MAFA_COMPRESS As Long = &H200
+Public Const MAFA_COMPRESS2 As Long = &H100
+Public Const MAFA_REPLACE_EXISTING As Long = &H1
+
+' MpqAddFileToArchiveEx compression flags
+Public Const MAFA_COMPRESS_STANDARD As Long = &H8 'Standard PKWare DCL compression
+Public Const MAFA_COMPRESS_DEFLATE  As Long = &H2 'ZLib's deflate compression
+Public Const MAFA_COMPRESS_WAVE    As Long = &H81 'Standard wave compression
+Public Const MAFA_COMPRESS_WAVE2   As Long = &H41 'Unused wave compression
+
+' Flags for individual compression types used for wave compression
+Public Const MAFA_COMPRESS_WAVECOMP1 As Long = &H80 'Main compressor for standard wave compression
+Public Const MAFA_COMPRESS_WAVECOMP2 As Long = &H40 'Main compressor for unused wave compression
+Public Const MAFA_COMPRESS_WAVECOMP3  As Long = &H1 'Secondary compressor for wave compression
+
+' ZLib deflate compression level constants (used with MpqAddFileToArchiveEx and MpqAddFileFromBufferEx)
+Public Const Z_NO_COMPRESSION         As Long = 0
+Public Const Z_BEST_SPEED             As Long = 1
+Public Const Z_BEST_COMPRESSION       As Long = 9
+Public Const Z_DEFAULT_COMPRESSION  As Long = (-1)
+
+' MpqAddWAVToArchive quality flags
+Public Const MAWA_QUALITY_HIGH As Long = 1
+Public Const MAWA_QUALITY_MEDIUM As Long = 0
+Public Const MAWA_QUALITY_LOW As Long = 2
+
+' SFileGetFileInfo flags
+Public Const SFILE_INFO_BLOCK_SIZE As Long = &H1 'Block size in MPQ
+Public Const SFILE_INFO_HASH_TABLE_SIZE As Long = &H2 'Hash table size in MPQ
+Public Const SFILE_INFO_NUM_FILES As Long = &H3 'Number of files in MPQ
+Public Const SFILE_INFO_TYPE As Long = &H4 'Is Long a file or an MPQ?
+Public Const SFILE_INFO_SIZE As Long = &H5 'Size of MPQ or uncompressed file
+Public Const SFILE_INFO_COMPRESSED_SIZE As Long = &H6 'Size of compressed file
+Public Const SFILE_INFO_FLAGS As Long = &H7 'File flags (compressed, etc.), file attributes if a file not in an archive
+Public Const SFILE_INFO_PARENT As Long = &H8 'Handle of MPQ that file is in
+Public Const SFILE_INFO_POSITION As Long = &H9 'Position of file pointer in files
+Public Const SFILE_INFO_LOCALEID As Long = &HA 'Locale ID of file in MPQ
+Public Const SFILE_INFO_PRIORITY As Long = &HB 'Priority of open MPQ
+Public Const SFILE_INFO_HASH_INDEX As Long = &HC 'Hash index of file in MPQ
+
+' SFileListFiles flags
+Public Const SFILE_LIST_MEMORY_LIST  As Long = &H1 ' Specifies that lpFilelists is a file list from memory, rather than being a list of file lists
+Public Const SFILE_LIST_ONLY_KNOWN   As Long = &H2 ' Only list files that the function finds a name for
+Public Const SFILE_LIST_ONLY_UNKNOWN As Long = &H4 ' Only list files that the function does not find a name for
+
+Public Const SFILE_TYPE_MPQ As Long = &H1
+Public Const SFILE_TYPE_FILE As Long = &H2
+
+Public Const INVALID_HANDLE_VALUE As Long = -1
+
+Public Const FILE_BEGIN   As Long = 0
+Public Const FILE_CURRENT As Long = 1
+Public Const FILE_END     As Long = 2
+
+Public Const SFILE_OPEN_HARD_DISK_FILE As Long = &H0 'Open archive without regard to the drive type it resides on
+Public Const SFILE_OPEN_CD_ROM_FILE As Long = &H1 'Open the archive only if it is on a CD-ROM
+Public Const SFILE_OPEN_ALLOW_WRITE As Long = &H8000 'Open file with write access
+
+Public Const SFILE_SEARCH_CURRENT_ONLY As Long = &H0 'Used with SFileOpenFileEx; only the archive with the handle specified will be searched for the file
+Public Const SFILE_SEARCH_ALL_OPEN As Long = &H1 'SFileOpenFileEx will look through all open archives for the file
+
+Type FILELISTENTRY
+    dwFileExists As Long ' Nonzero if this entry is used
+    lcLocale As Long ' Locale ID of file
+    dwCompressedSize As Long ' Compressed size of file
+    dwFullSize As Long ' Uncompressed size of file
+    dwFlags As Long ' Flags for file
+    szFileName(259) As Byte
+End Type
+
+' Storm functions implemented by this library
+Declare Function SFileOpenArchive Lib "SFmpq.dll" (ByVal lpFileName As String, ByVal dwPriority As Long, ByVal dwFlags As Long, ByRef hMPQ As Long) As Boolean
+Declare Function SFileCloseArchive Lib "SFmpq.dll" (ByVal hMPQ As Long) As Boolean
+Declare Function SFileGetArchiveName Lib "SFmpq.dll" (ByVal hMPQ As Long, ByVal lpBuffer As String, ByVal dwBufferLength As Long) As Boolean
+Declare Function SFileOpenFile Lib "SFmpq.dll" (ByVal lpFileName As String, ByRef hFile As Long) As Boolean
+Declare Function SFileOpenFileEx Lib "SFmpq.dll" (ByVal hMPQ As Long, ByVal lpFileName As String, ByVal dwSearchScope As Long, ByRef hFile As Long) As Boolean
+Declare Function SFileCloseFile Lib "SFmpq.dll" (ByVal hFile As Long) As Boolean
+Declare Function SFileGetFileSize Lib "SFmpq.dll" (ByVal hFile As Long, lpFileSizeHigh As Long) As Long
+Declare Function SFileGetFileArchive Lib "SFmpq.dll" (ByVal hFile As Long, ByRef hMPQ As Long) As Boolean
+Declare Function SFileGetFileName Lib "SFmpq.dll" (ByVal hMPQ As Long, ByVal lpBuffer As String, ByVal dwBufferLength As Long) As Boolean
+Declare Function SFileSetFilePointer Lib "SFmpq.dll" (ByVal hFile As Long, ByVal lDistanceToMove As Long, lplDistanceToMoveHigh As Long, ByVal dwMoveMethod As Long) As Long
+Declare Function SFileReadFile Lib "SFmpq.dll" (ByVal hFile As Long, lpBuffer As Any, ByVal nNumberOfBytesToRead As Long, lpNumberOfBytesRead As Long, lpOverlapped As Any) As Boolean
+Declare Function SFileSetLocale Lib "SFmpq.dll" (ByVal nNewLocale As Long) As Long
+Declare Function SFileGetBasePath Lib "SFmpq.dll" (ByVal lpBuffer As String, ByVal dwBufferLength As Long) As Boolean
+Declare Function SFileSetBasePath Lib "SFmpq.dll" (ByVal lpNewBasePath As String) As Boolean
+
+' Extra storm-related functions
+Declare Function SFileGetFileInfo Lib "SFmpq.dll" (ByVal hFile As Long, ByVal dwInfoType As Long) As Long
+Declare Function SFileSetArchivePriority Lib "SFmpq.dll" (ByVal hMPQ As Long, ByVal dwPriority As Long) As Boolean
+Declare Function SFileFindMpqHeader Lib "SFmpq.dll" (ByVal hFile As Long) As Long
+Declare Function SFileListFiles Lib "SFmpq.dll" (ByVal hMPQ As Long, ByVal lpFileLists As String, ByRef lpListBuffer As FILELISTENTRY, ByVal dwFlags As Long) As Boolean
+
+' Archive editing functions implemented by this library
+Declare Function MpqOpenArchiveForUpdate Lib "SFmpq.dll" (ByVal lpFileName As String, ByVal dwFlags As Long, ByVal dwMaximumFilesInArchive As Long) As Long
+Declare Function MpqCloseUpdatedArchive Lib "SFmpq.dll" (ByVal hMPQ As Long, ByVal dwUnknown2 As Long) As Long
+Declare Function MpqAddFileToArchive Lib "SFmpq.dll" (ByVal hMPQ As Long, ByVal lpSourceFileName As String, ByVal lpDestFileName As String, ByVal dwFlags As Long) As Boolean
+Declare Function MpqAddWaveToArchive Lib "SFmpq.dll" (ByVal hMPQ As Long, ByVal lpSourceFileName As String, ByVal lpDestFileName As String, ByVal dwFlags As Long, ByVal dwQuality As Long) As Boolean
+Declare Function MpqRenameFile Lib "SFmpq.dll" (ByVal hMPQ As Long, ByVal lpcOldFileName As String, ByVal lpcNewFileName As String) As Boolean
+Declare Function MpqDeleteFile Lib "SFmpq.dll" (ByVal hMPQ As Long, ByVal lpFileName As String) As Boolean
+Declare Function MpqCompactArchive Lib "SFmpq.dll" (ByVal hMPQ As Long) As Boolean
+
+' Extra archive editing functions
+Declare Function MpqAddFileToArchiveEx Lib "SFmpq.dll" (ByVal hMPQ As Long, ByVal lpSourceFileName As String, ByVal lpDestFileName As String, ByVal dwFlags As Long, ByVal dwCompressionType As Long, ByVal dwCompressLevel As Long) As Boolean
+Declare Function MpqAddFileFromBufferEx Lib "SFmpq.dll" (ByVal hMPQ As Long, lpBuffer As Any, ByVal dwLength As Long, ByVal lpFileName As String, ByVal dwFlags As Long, ByVal dwCompressionType As Long, ByVal dwCompressLevel As Long) As Boolean
+Declare Function MpqAddFileFromBuffer Lib "SFmpq.dll" (ByVal hMPQ As Long, lpBuffer As Any, ByVal dwLength As Long, ByVal lpFileName As String, ByVal dwFlags As Long) As Boolean
+Declare Function MpqAddWaveFromBuffer Lib "SFmpq.dll" (ByVal hMPQ As Long, lpBuffer As Any, ByVal dwLength As Long, ByVal lpFileName As String, ByVal dwFlags As Long, ByVal dwQuality As Long) As Boolean
+Declare Function MpqSetFileLocale Lib "SFmpq.dll" (ByVal hMPQ As Long, ByVal lpFileName As String, ByVal nOldLocale As Long, ByVal nNewLocale As Long) As Boolean
+
+' These functions do nothing.  They are only provided for
+' compatibility with MPQ extractors that use storm.
+Declare Function SFileDestroy Lib "SFmpq.dll" () As Boolean
+Declare Sub StormDestroy Lib "SFmpq.dll" ()
+
+' Returns 0 if the dll version is equal to the version your program was compiled
+' with, 1 if the dll is newer, -1 if the dll is older.
+Function SFMpqCompareVersion() As Long
+    Dim ExeVersion As SFMPQVERSION, DllVersion As SFMPQVERSION
+    With ExeVersion
+        .Major = 1
+        .Minor = 0
+        .Revision = 7
+        .Subrevision = 4
+    End With
+    DllVersion = SFMpqGetVersion()
+    If DllVersion.Major > ExeVersion.Major Then
+        SFMpqCompareVersion = 1
+        Exit Function
+    ElseIf DllVersion.Major < ExeVersion.Major Then
+        SFMpqCompareVersion = -1
+        Exit Function
+    End If
+    If DllVersion.Minor > ExeVersion.Minor Then
+        SFMpqCompareVersion = 1
+        Exit Function
+    ElseIf DllVersion.Minor < ExeVersion.Minor Then
+        SFMpqCompareVersion = -1
+        Exit Function
+    End If
+    If DllVersion.Revision > ExeVersion.Revision Then
+        SFMpqCompareVersion = 1
+        Exit Function
+    ElseIf DllVersion.Revision < ExeVersion.Revision Then
+        SFMpqCompareVersion = -1
+        Exit Function
+    End If
+    If DllVersion.Subrevision > ExeVersion.Subrevision Then
+        SFMpqCompareVersion = 1
+        Exit Function
+    ElseIf DllVersion.Subrevision < ExeVersion.Subrevision Then
+        SFMpqCompareVersion = -1
+        Exit Function
+    End If
+    SFMpqCompareVersion = 0
+End Function
+
diff --git a/SFmpqapi.cpp b/SFmpqapi.cpp
new file mode 100644 (file)
index 0000000..a42fa43
--- /dev/null
@@ -0,0 +1,3849 @@
+/* License information for this code is in license.txt */
+
+#define WIN32_LEAN_AND_MEAN
+
+// Includes
+#include <windows.h>
+#include <malloc.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#ifdef _USRDLL
+#include <shellapi.h>
+#endif
+
+#include "SComp.h"
+
+#include "SFmpqapi.h"
+
+struct SFMPQAPIMODULE {
+       SFMPQAPIMODULE();
+       ~SFMPQAPIMODULE();
+} SFMpqApi;
+
+#ifndef _WIN32
+#define SFMPQ_STATIC
+#endif
+
+#if defined(SFMPQ_STATIC) || !defined(SFMPQAPI_EXPORTS)
+#define DllMain SFMpqMain
+
+struct SFMPQLIBMODULE {
+       SFMPQLIBMODULE();
+       ~SFMPQLIBMODULE();
+} SFMpqLib;
+
+BOOL APIENTRY DllMain(HINSTANCE hInstDLL, DWORD  ul_reason_for_call, LPVOID lpReserved);
+
+SFMPQLIBMODULE::SFMPQLIBMODULE()
+{
+       SFMpqMain(0,DLL_PROCESS_ATTACH,0);
+}
+
+SFMPQLIBMODULE::~SFMPQLIBMODULE()
+{
+       SFMpqDestroy();
+       SFMpqMain(0,DLL_PROCESS_DETACH,0);
+}
+
+#endif
+
+LCID LocaleID = 0;
+BOOL SFMpqInit = FALSE;
+HINSTANCE hStorm = 0;
+#ifdef _USRDLL
+HINSTANCE hSFMpqInstance = 0;
+#endif
+
+#define SFMPQ_CURRENT_VERSION {1,0,8,1}
+
+SFMPQVERSION SFMpqVersion = SFMPQ_CURRENT_VERSION;
+LPCSTR SFMpqVersionString = "ShadowFlare MPQ API Library v1.08";
+float MpqVersion = 2.00;
+
+// Class to simulate _alloca for cross-compiler compatibility
+class TempAlloc {
+public:
+       TempAlloc();
+       ~TempAlloc();
+       TempAlloc(unsigned long int AllocSize);
+       void * Alloc(unsigned long int AllocSize);
+       void *lpAllocAddress;
+};
+
+LPCSTR ID_MPQ = "MPQ\x1A";
+LPCSTR ID_BN3 = "BN3\x1A";
+LPCSTR ID_RIFF = "RIFF";
+LPCSTR ID_WAVE = "WAVEfmt ";
+LPCSTR INTERNAL_LISTFILE = "(listfile)";
+LPCSTR INTERNAL_FILES = "(attributes)\n(listfile)\n(signature)";
+LPCSTR Storm_dll = "Storm.dll";
+LPCSTR UNKNOWN_OUT = "~unknowns\\unknown_%08x";
+LPCSTR UNKNOWN_IN = "~unknowns\\unknown_%x";
+LPCSTR UNKNOWN_CMP = "~unknowns\\unknown_";
+#define UNKNOWN_LEN 18
+
+LCID availLocales[7] = {0x0000,0x0407,0x0409,0x040A,0x040C,0x0410,0x0416};
+#define nLocales 7
+
+#define MAX_MPQ_PATH 260;
+
+#define HASH_POSITION 0
+#define HASH_NAME_A 1
+#define HASH_NAME_B 2
+#define HASH_KEY 3
+
+BOOL bCryptTableInit = FALSE;
+DWORD dwCryptTable[0x500];
+DWORD dwHashTableKey;
+DWORD dwBlockTableKey;
+MPQARCHIVE **lpOpenMpq = 0;
+DWORD dwOpenMpqCount = 0;
+MPQARCHIVE * FirstLastMpq[2] = {0,0};
+MPQFILE **lpOpenFile = 0;
+DWORD dwOpenFileCount = 0;
+MPQFILE * FirstLastFile[2] = {0,0};
+
+char StormBasePath[MAX_PATH+1];
+
+#define UNSUPPORTED_COMPRESSION   (0xFF ^ (0x40 | 0x80 | 0x01 | 0x02 | 0x08))
+#define UNSUPPORTED_DECOMPRESSION (0xFF ^ (0x40 | 0x80 | 0x01 | 0x02 | 0x08))
+
+typedef BOOL (WINAPI* funcSCompCompress)(LPVOID lpvDestinationMem, LPDWORD lpdwCompressedSize, LPVOID lpvSourceMem, DWORD dwDecompressedSize, DWORD dwCompressionType, DWORD dwCompressionSubType, DWORD dwWAVQuality);
+typedef BOOL (WINAPI* funcSCompDecompress)(LPVOID lpvDestinationMem, LPDWORD lpdwDecompressedSize, LPVOID lpvSourceMem, DWORD dwCompressedSize);
+funcSCompCompress stormSCompCompress = 0;
+funcSCompDecompress stormSCompDecompress = 0;
+
+void LoadStorm();
+void FreeStorm();
+
+LPVOID WINAPI SFAlloc(DWORD dwSize);
+void WINAPI SFFree(LPVOID lpvMemory);
+void WINAPI SFMemZero(LPVOID lpvDestination, DWORD dwLength);
+BOOL WINAPI MpqOpenArchiveEx(LPCSTR lpFileName, DWORD dwPriority, DWORD dwFlags, MPQHANDLE *hMPQ, DWORD dwFlags2, DWORD dwMaximumFilesInArchive, DWORD dwBlockSize);
+DWORD WINAPI FindMpqHeaderAtLocation(HANDLE hFile, DWORD dwStart, DWORD dwLength);
+DWORD GetFullPath(LPCSTR lpFileName, char *lpBuffer, DWORD dwBufferLength);
+MPQHANDLE GetHashTableEntry(MPQHANDLE hMPQ, LPCSTR lpFileName, LCID FileLocale);
+MPQHANDLE GetHashTableEntryOfHash(MPQHANDLE hMPQ, DWORD dwTablePos, DWORD dwNameHashA, DWORD dwNameHashB, LCID FileLocale);
+MPQHANDLE GetFreeHashTableEntry(MPQHANDLE hMPQ, LPCSTR lpFileName, LCID FileLocale, BOOL ReturnExisting);
+BOOL SearchOpenArchives(LPCSTR lpFileName, MPQHANDLE *hMPQ, MPQHANDLE *hFile);
+void SortOpenArchivesByPriority();
+DWORD GetHandleType(MPQHANDLE hFile);
+BOOL AddToInternalListing(MPQHANDLE hMPQ, LPCSTR lpFileName);
+BOOL RemoveFromInternalListing(MPQHANDLE hMPQ, LPCSTR lpFileName);
+size_t strlnlen(const char *strline);
+char *nextline(const char *strline);
+BOOL InitCryptTable();
+DWORD HashString(LPCSTR lpszString, DWORD dwHashType);
+BOOL EncryptData(LPBYTE lpbyBuffer, DWORD dwLength, DWORD dwKey);
+BOOL DecryptData(LPBYTE lpbyBuffer, DWORD dwLength, DWORD dwKey);
+static DWORD DetectFileSeed(DWORD * block, DWORD decrypted, DWORD blocksize);
+DWORD DetectFileSeedEx(MPQARCHIVE * mpqOpenArc, HASHTABLEENTRY * lpHashEntry, LPCSTR * lplpFileName);
+
+BOOL APIENTRY DllMain( HINSTANCE hInstDLL, 
+                       DWORD  ul_reason_for_call, 
+                       LPVOID lpReserved
+                                        )
+{
+#ifdef _WIN32
+       char *lpExeName,*buffer;DWORD slen;
+#endif
+       DWORD dwLastCount;
+
+#ifdef _USRDLL
+       hSFMpqInstance = hInstDLL;
+#endif
+
+    switch (ul_reason_for_call)
+       {
+               case DLL_PROCESS_ATTACH:
+                       InitCryptTable();
+                       dwHashTableKey = HashString("(hash table)",HASH_KEY);
+                       dwBlockTableKey = HashString("(block table)",HASH_KEY);
+#ifdef _WIN32
+                       lpExeName = (char *)SFAlloc(MAX_PATH+1);
+                       if (lpExeName) {
+                               slen = GetModuleFileName(0,lpExeName,MAX_PATH);
+                               lpExeName[slen] = 0;
+                               buffer = lpExeName+strlen(lpExeName);
+                               while (*buffer!='\\') {*buffer = 0;buffer--;}
+                               SFileSetBasePath(lpExeName);
+                               SFFree(lpExeName);
+                       }
+#else
+                       SFileSetBasePath("./");
+#endif
+                       break;
+               case DLL_THREAD_ATTACH:
+                       break;
+               case DLL_THREAD_DETACH:
+                       break;
+               case DLL_PROCESS_DETACH:
+                       if (lpOpenFile) {
+                               while (dwOpenFileCount>0) {
+                                       dwLastCount = dwOpenFileCount;
+                                       SFileCloseFile((MPQHANDLE)lpOpenFile[dwOpenFileCount-1]);
+                                       if (dwLastCount==dwOpenFileCount) dwOpenFileCount--;
+                               }
+
+                               SFFree(lpOpenFile);
+                       }
+
+                       if (lpOpenMpq) {
+                               while (dwOpenMpqCount>0) {
+                                       dwLastCount = dwOpenMpqCount;
+                                       SFileCloseArchive((MPQHANDLE)lpOpenMpq[dwOpenMpqCount-1]);
+                                       if (dwLastCount==dwOpenMpqCount) dwOpenMpqCount--;
+                               }
+
+                               SFFree(lpOpenMpq);
+                       }
+                       break;
+    }
+
+    return TRUE;
+}
+
+LPVOID WINAPI SFAlloc(DWORD dwSize)
+{
+       LPVOID lpMemory = malloc(dwSize);
+       if (lpMemory) SFMemZero(lpMemory,dwSize);
+       return lpMemory;
+}
+
+void WINAPI SFFree(LPVOID lpvMemory)
+{
+       if (lpvMemory) free(lpvMemory);
+}
+
+void WINAPI SFMemZero(LPVOID lpvDestination, DWORD dwLength)
+{
+       DWORD dwPrevLen = dwLength;
+       LPDWORD lpdwDestination = (LPDWORD)lpvDestination;
+       LPBYTE lpbyDestination;
+
+       dwLength >>= 2;
+
+       while (dwLength--)
+               *lpdwDestination++ = 0;
+
+       lpbyDestination = (LPBYTE)lpdwDestination;
+
+       dwLength = dwPrevLen;
+       dwLength &= 3;
+
+       while (dwLength--)
+               *lpbyDestination++ = 0;
+}
+
+TempAlloc::TempAlloc()
+{
+       lpAllocAddress = 0;
+}
+
+TempAlloc::TempAlloc(unsigned long int AllocSize)
+{
+       lpAllocAddress = SFAlloc(AllocSize);
+}
+
+TempAlloc::~TempAlloc()
+{
+       if (lpAllocAddress) {
+               SFFree(lpAllocAddress);
+               lpAllocAddress = 0;
+       }
+}
+
+void * TempAlloc::Alloc(unsigned long int AllocSize)
+{
+       lpAllocAddress = SFAlloc(AllocSize);
+       return lpAllocAddress;
+}
+
+SFMPQAPIMODULE::SFMPQAPIMODULE()
+{
+       //LoadStorm();
+}
+
+SFMPQAPIMODULE::~SFMPQAPIMODULE()
+{
+       FreeStorm();
+}
+
+BOOL SFMPQAPI WINAPI SFileDestroy() {
+       return TRUE;
+}
+
+void SFMPQAPI WINAPI StormDestroy() {
+}
+
+void SFMPQAPI WINAPI SFMpqDestroy() {
+       //FreeStorm();
+}
+
+BOOL SFMPQAPI WINAPI MpqInitialize()
+{
+       return (SFMpqInit=TRUE);
+}
+
+LPCSTR SFMPQAPI WINAPI MpqGetVersionString()
+{
+       return SFMpqVersionString;
+}
+
+float SFMPQAPI WINAPI MpqGetVersion()
+{
+       return MpqVersion;
+}
+
+LPCSTR SFMPQAPI WINAPI SFMpqGetVersionString()
+{
+       return SFMpqVersionString;
+}
+
+DWORD  SFMPQAPI WINAPI SFMpqGetVersionString2(LPCSTR lpBuffer, DWORD dwBufferLength)
+{
+       if (!lpBuffer) {
+               SetLastError(ERROR_INVALID_PARAMETER);
+               return strlen(SFMpqVersionString)+1;
+       }
+
+       DWORD slen = strlen(SFMpqVersionString)+1;
+
+       if (dwBufferLength>=slen) memcpy((void *)lpBuffer,SFMpqVersionString,slen);
+       else memcpy((void *)lpBuffer,SFMpqVersionString,dwBufferLength);
+
+       return slen;
+}
+
+SFMPQVERSION SFMPQAPI WINAPI SFMpqGetVersion()
+{
+       return SFMpqVersion;
+}
+
+void SFMPQAPI WINAPI AboutSFMpq()
+{
+#ifdef _USRDLL
+       if (hSFMpqInstance) {
+               char szAboutPage[MAX_PATH+13];
+               strcpy(szAboutPage,"res://");
+               GetModuleFileName(hSFMpqInstance,szAboutPage+6,MAX_PATH);
+               strcat(szAboutPage,"/about");
+               ShellExecute(0,0,szAboutPage,0,0,SW_SHOWNORMAL);
+       }
+#endif
+}
+
+BOOL WINAPI MpqOpenArchiveEx(LPCSTR lpFileName, DWORD dwPriority, DWORD dwFlags, MPQHANDLE *hMPQ, DWORD dwFlags2, DWORD dwMaximumFilesInArchive, DWORD dwBlockSize)
+{
+       DWORD flen,tsz;
+
+       if (!lpFileName || !hMPQ) {
+               SetLastError(ERROR_INVALID_PARAMETER);
+               if (hMPQ) *hMPQ = 0;
+               return FALSE;
+       }
+       if (!*lpFileName) {
+               SetLastError(ERROR_INVALID_PARAMETER);
+               *hMPQ = 0;
+               return FALSE;
+       }
+
+       DWORD dwFlags1 = 0;
+
+#ifdef _WIN32
+       char RootPath[4];
+       memset(RootPath,0,4);
+       if (memcmp(lpFileName+1,":\\",2)==0) memcpy(RootPath,lpFileName,3);
+       else {
+               char CurDir[MAX_PATH];
+               GetCurrentDirectory(MAX_PATH,CurDir);
+               memcpy(RootPath,CurDir,3);
+       }
+       if (GetDriveType(RootPath)==DRIVE_CDROM)
+               dwFlags1 |= 2;
+       else if (dwFlags&2)
+               dwFlags1 |= 1;
+       if (dwFlags & SFILE_OPEN_CD_ROM_FILE)
+               if (!(dwFlags1&2)) {*hMPQ = 0;return FALSE;}
+#endif
+
+       DWORD dwCreateFlags,dwAccessFlags,dwShareFlags;
+       if (dwFlags2 & MOAU_OPEN_ALWAYS) dwCreateFlags = OPEN_ALWAYS;
+       else if (dwFlags2 & MOAU_CREATE_ALWAYS) dwCreateFlags = CREATE_ALWAYS;
+       else if (dwFlags2 & MOAU_OPEN_EXISTING) dwCreateFlags = OPEN_EXISTING;
+       else dwCreateFlags = CREATE_NEW;
+       if (dwFlags2 & MOAU_READ_ONLY) {
+               if (!(dwFlags2 & MOAU_OPEN_EXISTING)) {
+                       SetLastError(MPQ_ERROR_BAD_OPEN_MODE);
+                       *hMPQ = 0;
+                       return FALSE;
+               }
+               dwAccessFlags = GENERIC_READ;
+               if (dwFlags2 & SFILE_OPEN_ALLOW_WRITE) dwFlags2 = dwFlags2^SFILE_OPEN_ALLOW_WRITE;
+       }
+       else {
+               dwAccessFlags = GENERIC_READ|GENERIC_WRITE;
+               dwFlags2 = dwFlags2|SFILE_OPEN_ALLOW_WRITE;
+       }
+       if (dwAccessFlags & GENERIC_WRITE)
+               dwShareFlags = 0;
+       else
+               dwShareFlags = FILE_SHARE_READ;
+       HANDLE hFile;
+       hFile = CreateFile(lpFileName,dwAccessFlags,dwShareFlags,0,dwCreateFlags,0,0);
+       TempAlloc NewAlloc;
+       if (hFile==INVALID_HANDLE_VALUE) {
+               DWORD namelen = GetFullPath(lpFileName,0,0);
+               char *namebuffer = (char *)NewAlloc.Alloc(namelen);
+               GetFullPath(lpFileName,namebuffer,namelen);
+               lpFileName = namebuffer;
+               hFile = CreateFile(lpFileName,dwAccessFlags,dwShareFlags,0,dwCreateFlags,0,0);
+       }
+       if (hFile!=INVALID_HANDLE_VALUE)
+       {
+               MPQARCHIVE **lpnOpenMpq = (MPQARCHIVE **)SFAlloc(sizeof(MPQARCHIVE *) * (dwOpenMpqCount+1));
+               if (lpnOpenMpq==0) {
+                       CloseHandle(hFile);
+                       *hMPQ = 0;
+                       return FALSE;
+               }
+               DWORD dwMpqStart;
+               MPQARCHIVE *mpqOpenArc;
+               if (GetFileSize(hFile,0)==0 && !(dwFlags2 & MOAU_READ_ONLY))
+               {
+                       dwMpqStart = 0;
+                       mpqOpenArc = (MPQARCHIVE *)SFAlloc(sizeof(MPQARCHIVE));
+                       if (!mpqOpenArc) {
+                               SFFree(lpnOpenMpq);
+                               CloseHandle(hFile);
+                               *hMPQ = 0;
+                               return FALSE;
+                       }
+                       memcpy(&mpqOpenArc->MpqHeader.dwMPQID,ID_MPQ,4);
+                       mpqOpenArc->MpqHeader.dwHeaderSize = sizeof(MPQHEADER);
+                       mpqOpenArc->MpqHeader.wUnused0C = 0;
+                       if (dwBlockSize & 0xFFFF0000)
+                               mpqOpenArc->MpqHeader.wBlockSize = DEFAULT_BLOCK_SIZE;
+                       else
+                               mpqOpenArc->MpqHeader.wBlockSize = (WORD)dwBlockSize;
+                       DWORD i;
+                       for (i=1;i<dwMaximumFilesInArchive;i*=2) {}
+                       dwMaximumFilesInArchive = i;
+                       mpqOpenArc->MpqHeader.dwHashTableSize = dwMaximumFilesInArchive;
+                       mpqOpenArc->MpqHeader.dwBlockTableSize = 0;
+                       mpqOpenArc->MpqHeader.dwHashTableOffset = mpqOpenArc->MpqHeader.dwHeaderSize;
+                       mpqOpenArc->MpqHeader.dwBlockTableOffset = mpqOpenArc->MpqHeader.dwHeaderSize + mpqOpenArc->MpqHeader.dwHashTableSize * sizeof(HASHTABLEENTRY);
+                       mpqOpenArc->MpqHeader.dwMPQSize = mpqOpenArc->MpqHeader.dwHeaderSize + mpqOpenArc->MpqHeader.dwHashTableSize * sizeof(HASHTABLEENTRY);
+                       if(WriteFile(hFile,&mpqOpenArc->MpqHeader,mpqOpenArc->MpqHeader.dwHeaderSize,&tsz,0)==0) {
+                               SFFree(lpnOpenMpq);
+                               SFFree(mpqOpenArc);
+                               CloseHandle(hFile);
+                               *hMPQ = 0;
+                               return FALSE;
+                       }
+                       flen = mpqOpenArc->MpqHeader.dwMPQSize;
+                       mpqOpenArc->lpHashTable = (HASHTABLEENTRY *)SFAlloc(sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize);
+                       if(!mpqOpenArc->lpHashTable) {
+                               SFFree(lpnOpenMpq);
+                               SFFree(mpqOpenArc);
+                               CloseHandle(hFile);
+                               *hMPQ = 0;
+                               return FALSE;
+                       }
+                       memset(mpqOpenArc->lpHashTable,0xFF,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize);
+                       EncryptData((LPBYTE)mpqOpenArc->lpHashTable,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,dwHashTableKey);
+                       if(WriteFile(hFile,mpqOpenArc->lpHashTable,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,&tsz,0)==0) {
+                               SFFree(mpqOpenArc->lpHashTable);
+                               SFFree(lpnOpenMpq);
+                               SFFree(mpqOpenArc);
+                               CloseHandle(hFile);
+                               *hMPQ = 0;
+                               return FALSE;
+                       }
+               }
+               else
+               {
+                       dwMpqStart = SFileFindMpqHeader(hFile);
+                       if (dwMpqStart==0xFFFFFFFF) {
+                               SFFree(lpnOpenMpq);
+                               CloseHandle(hFile);
+                               SetLastError(MPQ_ERROR_MPQ_INVALID);
+                               *hMPQ = 0;
+                               return FALSE;
+                       }
+                       flen = GetFileSize(hFile,0);
+                       mpqOpenArc = (MPQARCHIVE *)SFAlloc(sizeof(MPQARCHIVE));
+                       if (!mpqOpenArc) {
+                               SFFree(lpnOpenMpq);
+                               CloseHandle(hFile);
+                               *hMPQ = 0;
+                               return FALSE;
+                       }
+                       SetFilePointer(hFile,dwMpqStart,0,FILE_BEGIN);
+                       if(ReadFile(hFile,&mpqOpenArc->MpqHeader,sizeof(MPQHEADER),&tsz,0)==0) {
+                               SFFree(lpnOpenMpq);
+                               SFFree(mpqOpenArc);
+                               CloseHandle(hFile);
+                               *hMPQ = 0;
+                               return FALSE;
+                       }
+                       mpqOpenArc->lpHashTable = (HASHTABLEENTRY *)SFAlloc(sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize);
+                       if(!mpqOpenArc->lpHashTable) {
+                               SFFree(lpnOpenMpq);
+                               SFFree(mpqOpenArc);
+                               CloseHandle(hFile);
+                               *hMPQ = 0;
+                               return FALSE;
+                       }
+                       if (mpqOpenArc->MpqHeader.dwBlockTableSize!=0) {
+                               mpqOpenArc->lpBlockTable = (BLOCKTABLEENTRY *)SFAlloc(sizeof(BLOCKTABLEENTRY) * mpqOpenArc->MpqHeader.dwBlockTableSize);
+                               if(!mpqOpenArc->lpBlockTable) {
+                                       SFFree(mpqOpenArc->lpHashTable);
+                                       SFFree(lpnOpenMpq);
+                                       SFFree(mpqOpenArc);
+                                       CloseHandle(hFile);
+                                       *hMPQ = 0;
+                                       return FALSE;
+                               }
+                       }
+                       SetFilePointer(hFile,dwMpqStart+mpqOpenArc->MpqHeader.dwHashTableOffset,0,FILE_BEGIN);
+                       if(ReadFile(hFile,mpqOpenArc->lpHashTable,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,&tsz,0)==0) {
+                               if(mpqOpenArc->lpBlockTable) SFFree(mpqOpenArc->lpBlockTable);
+                               SFFree(mpqOpenArc->lpHashTable);
+                               SFFree(lpnOpenMpq);
+                               SFFree(mpqOpenArc);
+                               CloseHandle(hFile);
+                               *hMPQ = 0;
+                               return FALSE;
+                       }
+                       if (mpqOpenArc->MpqHeader.dwBlockTableSize!=0) {
+                               SetFilePointer(hFile,dwMpqStart+mpqOpenArc->MpqHeader.dwBlockTableOffset,0,FILE_BEGIN);
+                               if(ReadFile(hFile,mpqOpenArc->lpBlockTable,sizeof(BLOCKTABLEENTRY) * mpqOpenArc->MpqHeader.dwBlockTableSize,&tsz,0)==0) {
+                                       SFFree(mpqOpenArc->lpBlockTable);
+                                       SFFree(mpqOpenArc->lpHashTable);
+                                       SFFree(lpnOpenMpq);
+                                       SFFree(mpqOpenArc);
+                                       CloseHandle(hFile);
+                                       *hMPQ = 0;
+                                       return FALSE;
+                               }
+                       }
+               }
+               /*mpqOpenArc->lpFileName = (char *)SFAlloc(strlen(lpFileName)+1);
+               if(!mpqOpenArc->lpFileName) {
+                       if(mpqOpenArc->lpBlockTable) SFFree(mpqOpenArc->lpBlockTable);
+                       SFFree(mpqOpenArc->lpHashTable);
+                       SFFree(lpnOpenMpq);
+                       SFFree(mpqOpenArc);
+                       CloseHandle(hFile);
+                       *hMPQ = 0;
+                       return FALSE;
+               }*/
+               DecryptData((LPBYTE)mpqOpenArc->lpHashTable,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,dwHashTableKey);
+               if (mpqOpenArc->lpBlockTable) DecryptData((LPBYTE)mpqOpenArc->lpBlockTable,sizeof(BLOCKTABLEENTRY) * mpqOpenArc->MpqHeader.dwBlockTableSize,dwBlockTableKey);
+               mpqOpenArc->lpFileName = mpqOpenArc->szFileName;
+               strncpy(mpqOpenArc->lpFileName,lpFileName,259);
+               if (FirstLastMpq[1]) FirstLastMpq[1]->lpNextArc = mpqOpenArc;
+               mpqOpenArc->lpNextArc = (MPQARCHIVE *)FirstLastMpq;
+               mpqOpenArc->lpPrevArc = (MPQARCHIVE *)FirstLastMpq[1];
+               if (!FirstLastMpq[0]) {
+                       mpqOpenArc->lpPrevArc = (MPQARCHIVE *)0xEAFC5E23;
+                       FirstLastMpq[0] = mpqOpenArc;
+               }
+               FirstLastMpq[1] = mpqOpenArc;
+               mpqOpenArc->hFile = hFile;
+               mpqOpenArc->dwFlags1 = dwFlags1;
+               mpqOpenArc->dwPriority = dwPriority;
+               mpqOpenArc->lpLastReadFile = 0;
+               mpqOpenArc->dwUnk = 0;
+               mpqOpenArc->dwBlockSize = 512 << mpqOpenArc->MpqHeader.wBlockSize;
+               mpqOpenArc->lpLastReadBlock = 0;
+               mpqOpenArc->dwBufferSize = 0;
+               mpqOpenArc->dwMPQStart = dwMpqStart;
+               mpqOpenArc->lpMPQHeader = &mpqOpenArc->MpqHeader;
+               mpqOpenArc->dwReadOffset = flen;
+               mpqOpenArc->dwRefCount = 1;
+               mpqOpenArc->dwFlags = dwFlags2;
+               mpqOpenArc->dwExtraFlags = 0;
+               memcpy(lpnOpenMpq,lpOpenMpq,sizeof(MPQARCHIVE *) * dwOpenMpqCount);
+               lpnOpenMpq[dwOpenMpqCount] = mpqOpenArc;
+               if (lpOpenMpq) SFFree(lpOpenMpq);
+               lpOpenMpq = lpnOpenMpq;
+               dwOpenMpqCount++;
+               if (dwOpenMpqCount>1) SortOpenArchivesByPriority();
+               *hMPQ = (MPQHANDLE)mpqOpenArc;
+               return TRUE;
+       }
+       else {
+               if (dwFlags2&MOAU_OPEN_EXISTING) SetLastError(ERROR_FILE_NOT_FOUND);
+               else if (dwFlags2&MOAU_CREATE_NEW) SetLastError(ERROR_ALREADY_EXISTS);
+               *hMPQ = (MPQHANDLE)INVALID_HANDLE_VALUE;
+               return FALSE;
+       }
+}
+
+BOOL SFMPQAPI WINAPI SFileOpenFileAsArchive(MPQHANDLE hSourceMPQ, LPCSTR lpFileName, DWORD dwPriority, DWORD dwFlags, MPQHANDLE *hMPQ)
+{
+       DWORD flen,tsz;
+
+       if (!lpFileName || !hMPQ) {
+               SetLastError(ERROR_INVALID_PARAMETER);
+               if (hMPQ) *hMPQ = 0;
+               return FALSE;
+       }
+       if (!*lpFileName) {
+               SetLastError(ERROR_INVALID_PARAMETER);
+               *hMPQ = 0;
+               return FALSE;
+       }
+
+       HANDLE hFile;
+       if (SFileOpenFileEx(hSourceMPQ,lpFileName,1,&hFile))
+       {
+               MPQFILE mpqArcFile;
+               mpqArcFile = *(MPQFILE *)hFile;
+               SFileCloseFile(hFile);
+               if (mpqArcFile.hFile != INVALID_HANDLE_VALUE)
+                       return SFileOpenArchive(lpFileName,dwPriority,dwFlags,hMPQ);
+               hFile = mpqArcFile.lpParentArc->hFile;
+               MPQARCHIVE **lpnOpenMpq = (MPQARCHIVE **)SFAlloc(sizeof(MPQARCHIVE *) * (dwOpenMpqCount+1));
+               if (!lpnOpenMpq) {
+                       *hMPQ = 0;
+                       return FALSE;
+               }
+               DWORD dwMpqStart;
+               MPQARCHIVE *mpqOpenArc;
+               dwMpqStart = mpqArcFile.lpBlockEntry->dwFileOffset;
+               flen = mpqArcFile.lpBlockEntry->dwFullSize;
+               dwMpqStart = FindMpqHeaderAtLocation(hFile,dwMpqStart,flen);
+               if (dwMpqStart==0xFFFFFFFF) {
+                       SFFree(lpnOpenMpq);
+                       SetLastError(MPQ_ERROR_MPQ_INVALID);
+                       *hMPQ = 0;
+                       return FALSE;
+               }
+               mpqOpenArc = (MPQARCHIVE *)SFAlloc(sizeof(MPQARCHIVE));
+               if (!mpqOpenArc) {
+                       SFFree(lpnOpenMpq);
+                       *hMPQ = 0;
+                       return FALSE;
+               }
+               SetFilePointer(hFile,dwMpqStart,0,FILE_BEGIN);
+               if(ReadFile(hFile,&mpqOpenArc->MpqHeader,sizeof(MPQHEADER),&tsz,0)==0) {
+                       SFFree(lpnOpenMpq);
+                       SFFree(mpqOpenArc);
+                       *hMPQ = 0;
+                       return FALSE;
+               }
+               mpqOpenArc->lpHashTable = (HASHTABLEENTRY *)SFAlloc(sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize);
+               if(!mpqOpenArc->lpHashTable) {
+                       SFFree(lpnOpenMpq);
+                       SFFree(mpqOpenArc);
+                       *hMPQ = 0;
+                       return FALSE;
+               }
+               if (mpqOpenArc->MpqHeader.dwBlockTableSize!=0) {
+                       mpqOpenArc->lpBlockTable = (BLOCKTABLEENTRY *)SFAlloc(sizeof(BLOCKTABLEENTRY) * mpqOpenArc->MpqHeader.dwBlockTableSize);
+                       if(!mpqOpenArc->lpBlockTable) {
+                               SFFree(mpqOpenArc->lpHashTable);
+                               SFFree(lpnOpenMpq);
+                               SFFree(mpqOpenArc);
+                               *hMPQ = 0;
+                               return FALSE;
+                       }
+               }
+               SetFilePointer(hFile,dwMpqStart+mpqOpenArc->MpqHeader.dwHashTableOffset,0,FILE_BEGIN);
+               if(ReadFile(hFile,mpqOpenArc->lpHashTable,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,&tsz,0)==0) {
+                       if(mpqOpenArc->lpBlockTable) SFFree(mpqOpenArc->lpBlockTable);
+                       SFFree(mpqOpenArc->lpHashTable);
+                       SFFree(lpnOpenMpq);
+                       SFFree(mpqOpenArc);
+                       *hMPQ = 0;
+                       return FALSE;
+               }
+               if (mpqOpenArc->MpqHeader.dwBlockTableSize!=0) {
+                       SetFilePointer(hFile,dwMpqStart+mpqOpenArc->MpqHeader.dwBlockTableOffset,0,FILE_BEGIN);
+                       if(ReadFile(hFile,mpqOpenArc->lpBlockTable,sizeof(BLOCKTABLEENTRY) * mpqOpenArc->MpqHeader.dwBlockTableSize,&tsz,0)==0) {
+                               SFFree(mpqOpenArc->lpBlockTable);
+                               SFFree(mpqOpenArc->lpHashTable);
+                               SFFree(lpnOpenMpq);
+                               SFFree(mpqOpenArc);
+                               *hMPQ = 0;
+                               return FALSE;
+                       }
+               }
+               /*mpqOpenArc->lpFileName = (char *)SFAlloc(strlen(lpFileName)+1);
+               if(!mpqOpenArc->lpFileName) {
+                       if(mpqOpenArc->lpBlockTable) SFFree(mpqOpenArc->lpBlockTable);
+                       SFFree(mpqOpenArc->lpHashTable);
+                       SFFree(lpnOpenMpq);
+                       SFFree(mpqOpenArc);
+                       *hMPQ = 0;
+                       return FALSE;
+               }*/
+               DecryptData((LPBYTE)mpqOpenArc->lpHashTable,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,dwHashTableKey);
+               if (mpqOpenArc->lpBlockTable) DecryptData((LPBYTE)mpqOpenArc->lpBlockTable,sizeof(BLOCKTABLEENTRY) * mpqOpenArc->MpqHeader.dwBlockTableSize,dwBlockTableKey);
+               mpqOpenArc->lpFileName = mpqOpenArc->szFileName;
+               strncpy(mpqOpenArc->lpFileName,lpFileName,259);
+               if (FirstLastMpq[1]) FirstLastMpq[1]->lpNextArc = mpqOpenArc;
+               mpqOpenArc->lpNextArc = (MPQARCHIVE *)FirstLastMpq;
+               mpqOpenArc->lpPrevArc = (MPQARCHIVE *)FirstLastMpq[1];
+               if (!FirstLastMpq[0]) {
+                       mpqOpenArc->lpPrevArc = (MPQARCHIVE *)0xEAFC5E23;
+                       FirstLastMpq[0] = mpqOpenArc;
+               }
+               FirstLastMpq[1] = mpqOpenArc;
+               mpqOpenArc->hFile = hFile;
+               mpqOpenArc->dwFlags1 = 0;
+               mpqOpenArc->dwPriority = dwPriority;
+               mpqOpenArc->lpLastReadFile = 0;
+               mpqOpenArc->dwUnk = 0;
+               mpqOpenArc->dwBlockSize = 512 << mpqOpenArc->MpqHeader.wBlockSize;
+               mpqOpenArc->lpLastReadBlock = 0;
+               mpqOpenArc->dwBufferSize = 0;
+               mpqOpenArc->dwMPQStart = dwMpqStart;
+               mpqOpenArc->lpMPQHeader = &mpqOpenArc->MpqHeader;
+               mpqOpenArc->dwReadOffset = flen;
+               mpqOpenArc->dwRefCount = 1;
+               mpqOpenArc->dwFlags = dwFlags;
+               mpqOpenArc->dwExtraFlags = 1;
+               memcpy(lpnOpenMpq,lpOpenMpq,sizeof(MPQARCHIVE *) * dwOpenMpqCount);
+               lpnOpenMpq[dwOpenMpqCount] = mpqOpenArc;
+               if (lpOpenMpq) SFFree(lpOpenMpq);
+               lpOpenMpq = lpnOpenMpq;
+               dwOpenMpqCount++;
+               if (dwOpenMpqCount>1) SortOpenArchivesByPriority();
+               *hMPQ = (MPQHANDLE)mpqOpenArc;
+               return TRUE;
+       }
+       else {
+               *hMPQ = (MPQHANDLE)INVALID_HANDLE_VALUE;
+               return FALSE;
+       }
+}
+
+BOOL SFMPQAPI WINAPI SFileOpenArchive(LPCSTR lpFileName, DWORD dwPriority, DWORD dwFlags, MPQHANDLE *hMPQ)
+{
+       if (dwFlags & SFILE_OPEN_ALLOW_WRITE) {
+               return MpqOpenArchiveEx(lpFileName,dwPriority,dwFlags ^ SFILE_OPEN_ALLOW_WRITE,hMPQ,MOAU_OPEN_EXISTING,0,USE_DEFAULT_BLOCK_SIZE);
+       }
+       else {
+               return MpqOpenArchiveEx(lpFileName,dwPriority,dwFlags,hMPQ,MOAU_OPEN_EXISTING|MOAU_READ_ONLY,0,USE_DEFAULT_BLOCK_SIZE);
+       }
+}
+
+BOOL SFMPQAPI WINAPI SFileCloseArchive(MPQHANDLE hMPQ)
+{
+       if (hMPQ==0) {
+               SetLastError(ERROR_INVALID_PARAMETER);
+               return FALSE;
+       }
+
+       MPQARCHIVE *mpqOpenArc = (MPQARCHIVE *)hMPQ;
+       if (dwOpenMpqCount==0) return FALSE;
+       if (memcmp(&mpqOpenArc->MpqHeader.dwMPQID,ID_MPQ,4)!=0 && memcmp(&mpqOpenArc->MpqHeader.dwMPQID,ID_BN3,4)!=0) return FALSE;
+       if (!(mpqOpenArc->dwExtraFlags & 1)) CloseHandle(mpqOpenArc->hFile);
+       //SFFree(mpqOpenArc->lpFileName);
+       SFFree(mpqOpenArc->lpHashTable);
+       if(mpqOpenArc->lpBlockTable) SFFree(mpqOpenArc->lpBlockTable);
+       if ((DWORD)mpqOpenArc->lpNextArc!=(DWORD)FirstLastMpq)
+               mpqOpenArc->lpNextArc->lpPrevArc = mpqOpenArc->lpPrevArc;
+       if ((DWORD)mpqOpenArc->lpPrevArc!=0xEAFC5E23)
+               mpqOpenArc->lpPrevArc->lpNextArc = mpqOpenArc->lpNextArc;
+       if (mpqOpenArc==FirstLastMpq[0])
+               FirstLastMpq[0] = mpqOpenArc->lpNextArc;
+       if ((DWORD)FirstLastMpq[0]==(DWORD)FirstLastMpq)
+               FirstLastMpq[0] = 0;
+       if (mpqOpenArc==FirstLastMpq[1])
+               FirstLastMpq[1] = mpqOpenArc->lpPrevArc;
+       if ((DWORD)FirstLastMpq[1]==0xEAFC5E23)
+               FirstLastMpq[1] = 0;
+       SFFree(mpqOpenArc);
+       if (!lpOpenMpq) return TRUE;
+       if (dwOpenMpqCount-1==0) {
+               SFFree(lpOpenMpq);
+               lpOpenMpq = 0;
+               dwOpenMpqCount--;
+               return TRUE;
+       }
+       else if (dwOpenMpqCount==0) return FALSE;
+       MPQARCHIVE **lpnOpenMpq = (MPQARCHIVE **)SFAlloc(sizeof(MPQARCHIVE *) * (dwOpenMpqCount-1));
+       if (lpnOpenMpq) {
+               for (DWORD i=0,j=0;i<dwOpenMpqCount;i++) {
+                       if ((MPQHANDLE)lpOpenMpq[i]!=hMPQ) {
+                               memcpy(&lpnOpenMpq[j],&lpOpenMpq[i],sizeof(MPQARCHIVE *));
+                               j++;
+                       }
+               }
+               SFFree(lpOpenMpq);
+               lpOpenMpq = lpnOpenMpq;
+               dwOpenMpqCount--;
+       }
+       else {
+               for (DWORD i=0,j=0;i<dwOpenMpqCount;i++) {
+                       if ((MPQHANDLE)lpOpenMpq[i]==hMPQ) {
+                               lpOpenMpq[i] = (MPQARCHIVE *)0;
+                       }
+                       else {
+                               if (i!=j) memcpy(&lpOpenMpq[j],&lpOpenMpq[i],sizeof(MPQARCHIVE *));
+                               j++;
+                       }
+               }
+               dwOpenMpqCount--;
+       }
+       return TRUE;
+}
+
+BOOL SFMPQAPI WINAPI SFileGetArchiveName(MPQHANDLE hMPQ, LPCSTR lpBuffer, DWORD dwBufferLength)
+{
+       if (hMPQ==0 || lpBuffer==0) {
+               SetLastError(ERROR_INVALID_PARAMETER);
+               return FALSE;
+       }
+
+       DWORD dwhType = GetHandleType(hMPQ);
+       char *lpFileName;
+       if (dwhType==SFILE_TYPE_MPQ) lpFileName = ((MPQARCHIVE *)hMPQ)->lpFileName;
+       else if (dwhType==SFILE_TYPE_FILE) lpFileName = ((MPQFILE *)hMPQ)->lpFileName;
+       else return FALSE;
+       DWORD slen = strlen(lpFileName)+1;
+       if (dwBufferLength>=slen) memcpy((void *)lpBuffer,lpFileName,slen);
+       else memcpy((void *)lpBuffer,lpFileName,dwBufferLength);
+       return TRUE;
+}
+
+BOOL SFMPQAPI WINAPI SFileOpenFile(LPCSTR lpFileName, MPQHANDLE *hFile)
+{
+       return SFileOpenFileEx(0,lpFileName,SFILE_SEARCH_CURRENT_ONLY,hFile);
+}
+
+BOOL WINAPI IsHexDigit(char nChar)
+{
+       switch (nChar) {
+               case '0':
+               case '1':
+               case '2':
+               case '3':
+               case '4':
+               case '5':
+               case '6':
+               case '7':
+               case '8':
+               case '9':
+               case 'A':
+               case 'a':
+               case 'B':
+               case 'b':
+               case 'C':
+               case 'c':
+               case 'D':
+               case 'd':
+               case 'E':
+               case 'e':
+               case 'F':
+               case 'f':
+                       return TRUE;
+               default:
+                       return FALSE;
+       }
+       return FALSE;
+}
+
+BOOL SFMPQAPI WINAPI SFileOpenFileEx(MPQHANDLE hMPQ, LPCSTR lpFileName, DWORD dwSearchScope, MPQHANDLE *hFile)
+{
+       if (!lpFileName || !hFile) {
+               SetLastError(ERROR_INVALID_PARAMETER);
+               return FALSE;
+       }
+       if (!*lpFileName) {
+               SetLastError(ERROR_INVALID_PARAMETER);
+               return FALSE;
+       }
+
+       /*char szFileName[260];
+       if (hMPQ!=0) {
+               if ((DWORD)lpFileName<((MPQARCHIVE *)hMPQ)->MpqHeader.dwHashTableSize) {
+                       sprintf(szFileName,UNKNOWN_OUT,(DWORD)lpFileName);
+                       lpFileName = szFileName;
+                       dwSearchScope = SFILE_SEARCH_CURRENT_ONLY;
+               }
+       }
+       else {
+               for (DWORD i=0;i<dwOpenMpqCount;i++) {
+                       if ((DWORD)lpFileName<lpOpenMpq[i]->MpqHeader.dwHashTableSize) {
+                               SetLastError(ERROR_INVALID_PARAMETER);
+                               return FALSE;
+                       }
+               }
+       }*/
+
+       MPQFILE **lpnOpenFile = (MPQFILE **)SFAlloc(sizeof(MPQFILE *) * (dwOpenFileCount+1));
+       if (!lpnOpenFile) return FALSE;
+
+       MPQFILE *mpqOpenFile = (MPQFILE *)SFAlloc(sizeof(MPQFILE));
+       if (!mpqOpenFile) {
+               SFFree(lpnOpenFile);
+               return FALSE;
+       }
+       BOOL bFileOnDisk=FALSE;
+       MPQHANDLE hnMPQ,hnFile;
+       TempAlloc NewAlloc;
+       if (dwSearchScope==SFILE_SEARCH_CURRENT_ONLY) {
+               if (hMPQ) {
+                       if (memicmp(lpFileName,UNKNOWN_CMP,UNKNOWN_LEN)==0 && IsHexDigit(lpFileName[UNKNOWN_LEN])) {
+                               DWORD dwHashIndex;
+                               sscanf(lpFileName,UNKNOWN_IN,&dwHashIndex);
+                               hnFile = (HANDLE)&((MPQARCHIVE *)hMPQ)->lpHashTable[dwHashIndex];
+                               if ((((HASHTABLEENTRY *)hnFile)->dwBlockTableIndex&0xFFFFFFFE)==0xFFFFFFFE)
+                               {
+                                       SFFree(mpqOpenFile);
+                                       SFFree(lpnOpenFile);
+                                       SetLastError(ERROR_FILE_NOT_FOUND);
+                                       return FALSE;
+                               }
+                       }
+                       else hnFile = GetHashTableEntry(hMPQ,lpFileName,LocaleID);
+                       hnMPQ = hMPQ;
+               }
+               else {
+                       SearchOpenArchives(lpFileName,&hnMPQ,&hnFile);
+               }
+       }
+       else {
+               SearchOpenArchives(lpFileName,&hnMPQ,&hnFile);
+               if (!hnFile) {
+                       hnMPQ = 0;
+                       DWORD namelen = GetFullPath(lpFileName,0,0);
+                       char *namebuffer = (char *)NewAlloc.Alloc(namelen);
+                       GetFullPath(lpFileName,namebuffer,namelen);
+                       lpFileName = namebuffer;
+                       hnFile = CreateFile(lpFileName,GENERIC_READ,FILE_SHARE_READ,0,OPEN_EXISTING,0,0);
+                       if (hnFile==INVALID_HANDLE_VALUE) hnFile=0;
+                       else bFileOnDisk = TRUE;
+               }
+       }
+       if (hnMPQ) {
+               if(!((MPQARCHIVE *)hnMPQ)->lpBlockTable) {
+                       SFFree(mpqOpenFile);
+                       SFFree(lpnOpenFile);
+                       SetLastError(ERROR_FILE_NOT_FOUND);
+                       return FALSE;
+               }
+       }
+       if (!hnFile) {
+               SFFree(mpqOpenFile);
+               SFFree(lpnOpenFile);
+               SetLastError(ERROR_FILE_NOT_FOUND);
+               return FALSE;
+       }
+       mpqOpenFile->lpFileName = (char *)SFAlloc(strlen(lpFileName)+1);
+       if (!mpqOpenFile->lpFileName) {
+               SFFree(mpqOpenFile);
+               SFFree(lpnOpenFile);
+               return FALSE;
+       }
+       if (hnMPQ) {
+               if (!(((MPQARCHIVE *)hnMPQ)->lpBlockTable[((HASHTABLEENTRY *)hnFile)->dwBlockTableIndex].dwFlags & MAFA_EXISTS)) {
+                       SFFree(mpqOpenFile->lpFileName);
+                       SFFree(mpqOpenFile);
+                       SFFree(lpnOpenFile);
+                       SetLastError(ERROR_FILE_INVALID);
+                       return FALSE;
+               }
+       }
+       strcpy(mpqOpenFile->lpFileName,lpFileName);
+       if (!bFileOnDisk) {
+               mpqOpenFile->lpParentArc = (MPQARCHIVE *)hnMPQ;
+               mpqOpenFile->hFile = INVALID_HANDLE_VALUE;
+               mpqOpenFile->lpHashEntry = (HASHTABLEENTRY *)hnFile;
+               mpqOpenFile->lpBlockEntry = &((MPQARCHIVE *)hnMPQ)->lpBlockTable[mpqOpenFile->lpHashEntry->dwBlockTableIndex];
+               mpqOpenFile->lpParentArc->dwRefCount++;
+               if (mpqOpenFile->lpBlockEntry->dwFlags&MAFA_ENCRYPT) {
+                       LPSTR lpOldNameBuffer = mpqOpenFile->lpFileName;
+                       if (memicmp(mpqOpenFile->lpFileName,UNKNOWN_CMP,UNKNOWN_LEN)==0 && IsHexDigit(mpqOpenFile->lpFileName[UNKNOWN_LEN]))
+                               mpqOpenFile->lpFileName = 0;
+                       mpqOpenFile->dwCryptKey = DetectFileSeedEx(mpqOpenFile->lpParentArc,mpqOpenFile->lpHashEntry,(LPCSTR *)&mpqOpenFile->lpFileName);
+                       if (memicmp(lpFileName,UNKNOWN_CMP,UNKNOWN_LEN)==0 && IsHexDigit(lpFileName[UNKNOWN_LEN])) {
+                               if (!mpqOpenFile->lpFileName)
+                                       mpqOpenFile->lpFileName = lpOldNameBuffer;
+                               else
+                                       SFFree(lpOldNameBuffer);
+                       }
+                       if (mpqOpenFile->dwCryptKey==0) {
+                               SFFree(mpqOpenFile->lpFileName);
+                               SFFree(mpqOpenFile);
+                               SFFree(lpnOpenFile);
+                               SetLastError(ERROR_FILE_INVALID);
+                               return FALSE;
+                       }
+               }
+       }
+       else {
+               mpqOpenFile->hFile = hnFile;
+       }
+       strncpy(mpqOpenFile->szFileName,mpqOpenFile->lpFileName,259);
+       *hFile = (MPQHANDLE)mpqOpenFile;
+       memcpy(lpnOpenFile,lpOpenFile,sizeof(MPQFILE *) * dwOpenFileCount);
+       lpnOpenFile[dwOpenFileCount] = mpqOpenFile;
+       if (lpOpenFile) SFFree(lpOpenFile);
+       lpOpenFile = lpnOpenFile;
+       dwOpenFileCount++;
+       return TRUE;
+}
+
+BOOL SFMPQAPI WINAPI SFileCloseFile(MPQHANDLE hFile)
+{
+       if (!hFile) {
+               SetLastError(ERROR_INVALID_PARAMETER);
+               return FALSE;
+       }
+
+       MPQFILE *mpqOpenFile = (MPQFILE *)hFile;
+
+       if (dwOpenFileCount==0) return FALSE;
+       SFFree(mpqOpenFile->lpFileName);
+       if (mpqOpenFile->lpdwBlockOffsets) SFFree(mpqOpenFile->lpdwBlockOffsets);
+       if (mpqOpenFile->hFile == INVALID_HANDLE_VALUE) mpqOpenFile->lpParentArc->dwRefCount--;
+
+       SFFree(mpqOpenFile);
+       if (lpOpenFile==0) return TRUE;
+       if (dwOpenFileCount-1==0) {
+               SFFree(lpOpenFile);
+               lpOpenFile = (MPQFILE **)0;
+               dwOpenFileCount--;
+               return TRUE;
+       }
+       else if (dwOpenFileCount==0) return FALSE;
+       MPQFILE **lpnOpenFile = (MPQFILE **)SFAlloc(sizeof(MPQFILE *) * (dwOpenFileCount-1));
+       if (lpnOpenFile) {
+               for (DWORD i=0,j=0;i<dwOpenFileCount;i++) {
+                       if ((MPQHANDLE)lpOpenFile[i]!=hFile) {
+                               memcpy(&lpnOpenFile[j],&lpOpenFile[i],sizeof(MPQFILE *));
+                               j++;
+                       }
+               }
+               SFFree(lpOpenFile);
+               lpOpenFile = lpnOpenFile;
+               dwOpenFileCount--;
+       }
+       else {
+               for (DWORD i=0,j=0;i<dwOpenFileCount;i++) {
+                       if ((MPQHANDLE)lpOpenFile[i]==hFile) {
+                               lpOpenFile[i] = (MPQFILE *)0;
+                       }
+                       else {
+                               if (i!=j) memcpy(&lpOpenFile[j],&lpOpenFile[i],sizeof(MPQFILE *));
+                               j++;
+                       }
+               }
+               dwOpenFileCount--;
+       }
+       return TRUE;
+}
+
+DWORD SFMPQAPI WINAPI SFileGetFileSize(MPQHANDLE hFile, LPDWORD lpFileSizeHigh)
+{
+       if (!hFile) {
+               SetLastError(ERROR_INVALID_PARAMETER);
+               return (DWORD)-1;
+       }
+
+       MPQFILE *mpqOpenFile = (MPQFILE *)hFile;
+       if (mpqOpenFile->hFile == INVALID_HANDLE_VALUE) {
+               if (lpFileSizeHigh) *lpFileSizeHigh = 0;
+               return mpqOpenFile->lpBlockEntry->dwFullSize;
+       }
+       else return GetFileSize(mpqOpenFile->hFile,lpFileSizeHigh);
+}
+
+BOOL SFMPQAPI WINAPI SFileGetFileArchive(MPQHANDLE hFile, MPQHANDLE *hMPQ)
+{
+       if (!hFile || !hMPQ) {
+               SetLastError(ERROR_INVALID_PARAMETER);
+               return FALSE;
+       }
+
+       if (((MPQFILE *)hFile)->hFile == INVALID_HANDLE_VALUE) {
+               *hMPQ = (MPQHANDLE)((MPQFILE *)hFile)->lpParentArc;
+               return TRUE;
+       }
+       else {
+               SetLastError(ERROR_INVALID_PARAMETER);
+               return FALSE;
+       }
+}
+
+BOOL SFMPQAPI WINAPI SFileGetFileName(MPQHANDLE hFile, LPCSTR lpBuffer, DWORD dwBufferLength)
+{
+       return SFileGetArchiveName(hFile,lpBuffer,dwBufferLength);
+}
+
+DWORD SFMPQAPI WINAPI SFileGetFileInfo(MPQHANDLE hFile, DWORD dwInfoType)
+{
+       if (!hFile) {
+               SetLastError(ERROR_INVALID_PARAMETER);
+               return (DWORD)-1;
+       }
+       if (dwInfoType==0) {
+               SetLastError(ERROR_UNKNOWN_PROPERTY);
+               return (DWORD)-1;
+       }
+
+       DWORD dwhType = GetHandleType(hFile);
+       if (dwhType==SFILE_TYPE_FILE)
+       {
+               MPQFILE *mpqOpenFile = (MPQFILE *)hFile;
+               if (mpqOpenFile->hFile == INVALID_HANDLE_VALUE) {
+                       MPQARCHIVE *mpqOpenArc = mpqOpenFile->lpParentArc;
+                       switch (dwInfoType) {
+                       case SFILE_INFO_BLOCK_SIZE:
+                               return mpqOpenArc->MpqHeader.wBlockSize;
+                       case SFILE_INFO_HASH_TABLE_SIZE:
+                               return mpqOpenArc->MpqHeader.dwHashTableSize;
+                       case SFILE_INFO_NUM_FILES:
+                               return mpqOpenArc->MpqHeader.dwBlockTableSize;
+                       case SFILE_INFO_TYPE:
+                               return SFILE_TYPE_FILE;
+                       case SFILE_INFO_SIZE:
+                               return mpqOpenFile->lpBlockEntry->dwFullSize;
+                       case SFILE_INFO_COMPRESSED_SIZE:
+                               return mpqOpenFile->lpBlockEntry->dwCompressedSize;
+                       case SFILE_INFO_FLAGS:
+                               return mpqOpenFile->lpBlockEntry->dwFlags;
+                       case SFILE_INFO_PARENT:
+                               return (DWORD)mpqOpenFile->lpParentArc;
+                       case SFILE_INFO_POSITION:
+                               return mpqOpenFile->dwFilePointer;
+                       case SFILE_INFO_LOCALEID:
+                               return mpqOpenFile->lpHashEntry->lcLocale;
+                       case SFILE_INFO_PRIORITY:
+                               return mpqOpenArc->dwPriority;
+                       case SFILE_INFO_HASH_INDEX:
+                               return ((DWORD)mpqOpenFile->lpHashEntry-(DWORD)mpqOpenArc->lpHashTable)/sizeof(HASHTABLEENTRY);
+                       case SFILE_INFO_BLOCK_INDEX:
+                               return mpqOpenFile->lpHashEntry->dwBlockTableIndex;
+                       default:
+                               SetLastError(ERROR_UNKNOWN_PROPERTY);
+                               return (DWORD)-1;
+                       }
+               }
+               else {
+                       switch (dwInfoType) {
+                       case SFILE_INFO_TYPE:
+                               return SFILE_TYPE_FILE;
+                       case SFILE_INFO_SIZE:
+                               return GetFileSize(mpqOpenFile->hFile,0);
+                       case SFILE_INFO_COMPRESSED_SIZE:
+                               return GetFileSize(mpqOpenFile->hFile,0);
+#ifdef _WIN32
+                       case SFILE_INFO_FLAGS:
+                               return GetFileAttributes(mpqOpenFile->lpFileName);
+#endif
+                       case SFILE_INFO_POSITION:
+                               return SetFilePointer(mpqOpenFile->hFile,0,0,FILE_CURRENT);
+                       default:
+                               SetLastError(ERROR_UNKNOWN_PROPERTY);
+                               return (DWORD)-1;
+
+                       }
+               }
+       }
+       else if (dwhType==SFILE_TYPE_MPQ)
+       {
+               MPQARCHIVE *mpqOpenArc = (MPQARCHIVE *)hFile;
+               switch (dwInfoType) {
+               case SFILE_INFO_BLOCK_SIZE:
+                       return mpqOpenArc->MpqHeader.wBlockSize;
+               case SFILE_INFO_HASH_TABLE_SIZE:
+                       return mpqOpenArc->MpqHeader.dwHashTableSize;
+               case SFILE_INFO_NUM_FILES:
+                       return mpqOpenArc->MpqHeader.dwBlockTableSize;
+               case SFILE_INFO_TYPE:
+                       return SFILE_TYPE_MPQ;
+               case SFILE_INFO_SIZE:
+                       return mpqOpenArc->MpqHeader.dwMPQSize;
+               case SFILE_INFO_PRIORITY:
+                       return mpqOpenArc->dwPriority;
+               default:
+                       SetLastError(ERROR_UNKNOWN_PROPERTY);
+                       return (DWORD)-1;
+               }
+       }
+       SetLastError(ERROR_INVALID_PARAMETER);
+       return (DWORD)-1;
+}
+
+DWORD SFMPQAPI WINAPI SFileSetFilePointer(MPQHANDLE hFile, long lDistanceToMove, PLONG lplDistanceToMoveHigh, DWORD dwMoveMethod)
+{
+       if (!hFile) {
+               SetLastError(ERROR_INVALID_PARAMETER);
+               return (DWORD)-1;
+       }
+
+       MPQFILE *mpqOpenFile = (MPQFILE *)hFile;
+       if (mpqOpenFile->hFile == INVALID_HANDLE_VALUE) {
+               long fsz = mpqOpenFile->lpBlockEntry->dwFullSize;
+               long cpos = mpqOpenFile->dwFilePointer;
+               switch (dwMoveMethod) {
+               case FILE_BEGIN:
+                       if (lDistanceToMove<0 || lDistanceToMove>fsz) return (DWORD)-1;
+                       mpqOpenFile->dwFilePointer = lDistanceToMove;
+                       break;
+               case FILE_CURRENT:
+                       if (lDistanceToMove<cpos || cpos+lDistanceToMove>fsz) return (DWORD)-1;
+                       mpqOpenFile->dwFilePointer += lDistanceToMove;
+                       break;
+
+               case FILE_END:
+                       if (lDistanceToMove<fsz || lDistanceToMove>0) return (DWORD)-1;
+                       mpqOpenFile->dwFilePointer = fsz+lDistanceToMove;
+                       break;
+               default:
+                       if (lDistanceToMove<0 || lDistanceToMove>fsz) return (DWORD)-1;
+                       mpqOpenFile->dwFilePointer = lDistanceToMove;
+               }
+               if (lplDistanceToMoveHigh!=0) *lplDistanceToMoveHigh = 0;
+               return mpqOpenFile->dwFilePointer;
+       }
+       else return SetFilePointer(mpqOpenFile->hFile,lDistanceToMove,lplDistanceToMoveHigh,dwMoveMethod);
+
+}
+
+BOOL SFMPQAPI WINAPI SFileReadFile(MPQHANDLE hFile,LPVOID lpBuffer,DWORD nNumberOfBytesToRead,LPDWORD lpNumberOfBytesRead,LPOVERLAPPED lpOverlapped)
+{
+       if (!hFile || !lpBuffer) {
+               SetLastError(ERROR_INVALID_PARAMETER);
+               return FALSE;
+       }
+
+       MPQFILE *mpqOpenFile = (MPQFILE *)hFile;
+       if (mpqOpenFile->hFile != INVALID_HANDLE_VALUE) {
+               DWORD tsz=0;
+               BOOL RetVal = ReadFile(mpqOpenFile->hFile,lpBuffer,nNumberOfBytesToRead,&tsz,lpOverlapped);
+               if (lpNumberOfBytesRead) *lpNumberOfBytesRead = tsz;
+               return RetVal;
+       }
+       if (lpOverlapped)
+               if (lpOverlapped->Internal || lpOverlapped->InternalHigh || lpOverlapped->Offset || lpOverlapped->OffsetHigh || lpOverlapped->hEvent)
+                       SFileSetFilePointer(hFile,lpOverlapped->Offset,(long *)&lpOverlapped->OffsetHigh,FILE_BEGIN);
+       if (nNumberOfBytesToRead==0) {
+               if (lpNumberOfBytesRead) *lpNumberOfBytesRead = 0;
+               if (lpOverlapped) lpOverlapped->InternalHigh = 0;
+               return TRUE;
+       }
+       MPQARCHIVE *mpqOpenArc = mpqOpenFile->lpParentArc;
+
+       if (mpqOpenFile->dwFilePointer>mpqOpenFile->lpBlockEntry->dwFullSize) return FALSE;
+       if (mpqOpenFile->dwFilePointer==mpqOpenFile->lpBlockEntry->dwFullSize)
+       {
+               if (lpNumberOfBytesRead) *lpNumberOfBytesRead = 0;
+               if (lpOverlapped) lpOverlapped->InternalHigh = 0;
+               return TRUE;
+       }
+       DWORD nBytesRead,TotalBytesRead=0;
+       DWORD BlockIndex = mpqOpenFile->lpHashEntry->dwBlockTableIndex;
+       if (mpqOpenFile->dwFilePointer+nNumberOfBytesToRead>mpqOpenArc->lpBlockTable[BlockIndex].dwFullSize) nNumberOfBytesToRead = mpqOpenArc->lpBlockTable[BlockIndex].dwFullSize-mpqOpenFile->dwFilePointer;
+       DWORD blockSize = 512 << mpqOpenArc->MpqHeader.wBlockSize;
+       DWORD dwBlockStart = mpqOpenFile->dwFilePointer - (mpqOpenFile->dwFilePointer % blockSize);
+    DWORD blockNum = dwBlockStart / blockSize;
+    DWORD nBlocks  = (mpqOpenFile->dwFilePointer+nNumberOfBytesToRead) / blockSize;
+    if((mpqOpenFile->dwFilePointer+nNumberOfBytesToRead) % blockSize)
+               nBlocks++;
+       DWORD TotalBlocks = mpqOpenArc->lpBlockTable[BlockIndex].dwFullSize / blockSize;
+       if(mpqOpenArc->lpBlockTable[BlockIndex].dwFullSize % blockSize)
+               TotalBlocks++;
+       DWORD dwBlockPos = mpqOpenFile->dwFilePointer % blockSize;
+       DWORD dwBlockPosEnd = (mpqOpenFile->dwFilePointer+nNumberOfBytesToRead) % blockSize;
+       if (dwBlockPosEnd==0) dwBlockPosEnd = blockSize;
+       void *blkBuffer = SFAlloc(blockSize);
+       if (!blkBuffer) {
+               if (lpNumberOfBytesRead) *lpNumberOfBytesRead = 0;
+               if (lpOverlapped) lpOverlapped->InternalHigh = 0;
+               return FALSE;
+       }
+       void *blk16Buffer = SFAlloc(blockSize * 16);
+       if (!blk16Buffer) {
+               SFFree(blkBuffer);
+               if (lpNumberOfBytesRead) *lpNumberOfBytesRead = 0;
+               if (lpOverlapped) lpOverlapped->InternalHigh = 0;
+               return FALSE;
+       }
+       DWORD dwCryptKey = mpqOpenFile->dwCryptKey;
+       //if (mpqOpenArc->lpBlockTable[BlockIndex].dwFlags & MAFA_ENCRYPT) dwCryptKey = HashString(mpqOpenFile->lpFileName,HASH_KEY);
+       //if (mpqOpenArc->lpBlockTable[BlockIndex].dwFlags & MAFA_MODCRYPTKEY) dwCryptKey = (dwCryptKey + mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset) ^ mpqOpenArc->lpBlockTable[BlockIndex].dwFullSize;
+       DWORD HeaderLength=0;
+       if (memcmp(&mpqOpenArc->MpqHeader.dwMPQID,ID_BN3,4)==0)
+       {
+               SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset,0,FILE_BEGIN);
+               ReadFile(mpqOpenArc->hFile,&HeaderLength,4,&nBytesRead,0);
+       }
+       DWORD i;
+       if (!mpqOpenFile->lpdwBlockOffsets)
+       {
+               DWORD *dwBlockPtrTable = (DWORD *)SFAlloc((TotalBlocks+1)*4);
+               if (!dwBlockPtrTable) {
+
+                       SFFree(blk16Buffer);
+                       SFFree(blkBuffer);
+                       if (lpNumberOfBytesRead) *lpNumberOfBytesRead = 0;
+                       if (lpOverlapped) lpOverlapped->InternalHigh = 0;
+                       return FALSE;
+               }
+               if ((mpqOpenArc->lpBlockTable[BlockIndex].dwFlags & MAFA_COMPRESS) || (mpqOpenArc->lpBlockTable[BlockIndex].dwFlags & MAFA_COMPRESS2))
+               {
+                       SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset+HeaderLength,0,FILE_BEGIN);
+                       ReadFile(mpqOpenArc->hFile,dwBlockPtrTable,(TotalBlocks+1)*4,&nBytesRead,0);
+                       if (mpqOpenArc->lpBlockTable[BlockIndex].dwFlags & MAFA_ENCRYPT) {
+                               DecryptData((LPBYTE)dwBlockPtrTable,(TotalBlocks+1)*4,dwCryptKey-1);
+                       }
+               }
+               else
+               {
+                       for (i=0;i<TotalBlocks+1;i++) {
+                               if (i<TotalBlocks) dwBlockPtrTable[i] = i * blockSize;
+                               else dwBlockPtrTable[i] = mpqOpenArc->lpBlockTable[BlockIndex].dwFullSize;
+                       }
+               }
+               mpqOpenFile->lpdwBlockOffsets = dwBlockPtrTable;
+       }
+       BYTE *compbuffer = (BYTE *)SFAlloc(blockSize+3);
+       if (!compbuffer) {
+               SFFree(blk16Buffer);
+               SFFree(blkBuffer);
+               if (lpNumberOfBytesRead) *lpNumberOfBytesRead = 0;
+               if (lpOverlapped) lpOverlapped->InternalHigh = 0;
+               return FALSE;
+       }
+       DWORD blk=0,blki=0;
+       for (i=blockNum;i<nBlocks;i++) {
+               if (blk==0) {
+                       SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset+HeaderLength+mpqOpenFile->lpdwBlockOffsets[i],0,FILE_BEGIN);
+                       blki=i;
+                       if (i+16>nBlocks) {
+                               if (ReadFile(mpqOpenArc->hFile,blk16Buffer,mpqOpenFile->lpdwBlockOffsets[nBlocks]-mpqOpenFile->lpdwBlockOffsets[i],&nBytesRead,0)==0) {
+                                       SFFree(compbuffer);
+                                       SFFree(blk16Buffer);
+                                       SFFree(blkBuffer);
+                                       if (lpNumberOfBytesRead) *lpNumberOfBytesRead = TotalBytesRead;
+                                       if (lpOverlapped) lpOverlapped->InternalHigh = TotalBytesRead;
+                                       return FALSE;
+                               }
+
+                       }
+                       else {
+                               if (ReadFile(mpqOpenArc->hFile,blk16Buffer,mpqOpenFile->lpdwBlockOffsets[i+16]-mpqOpenFile->lpdwBlockOffsets[i],&nBytesRead,0)==0) {
+                                       SFFree(compbuffer);
+                                       SFFree(blk16Buffer);
+                                       SFFree(blkBuffer);
+                                       if (lpNumberOfBytesRead) *lpNumberOfBytesRead = TotalBytesRead;
+                                       if (lpOverlapped) lpOverlapped->InternalHigh = TotalBytesRead;
+                                       return FALSE;
+                               }
+                       }
+               }
+               memcpy(blkBuffer,((char *)blk16Buffer)+(mpqOpenFile->lpdwBlockOffsets[blki+blk]-mpqOpenFile->lpdwBlockOffsets[blki]),mpqOpenFile->lpdwBlockOffsets[i+1]-mpqOpenFile->lpdwBlockOffsets[i]);
+               if (mpqOpenArc->lpBlockTable[BlockIndex].dwFlags & MAFA_ENCRYPT)
+               {
+                       DecryptData((LPBYTE)blkBuffer,mpqOpenFile->lpdwBlockOffsets[i+1]-mpqOpenFile->lpdwBlockOffsets[i],dwCryptKey+i);
+               }
+               if (i==TotalBlocks-1 && (mpqOpenArc->lpBlockTable[BlockIndex].dwFullSize % blockSize)!=0) blockSize=mpqOpenArc->lpBlockTable[BlockIndex].dwFullSize % blockSize;
+               DWORD outLength=blockSize;
+               if ((mpqOpenFile->lpdwBlockOffsets[i+1]-mpqOpenFile->lpdwBlockOffsets[i])!=blockSize)
+               {
+                       if (mpqOpenArc->lpBlockTable[BlockIndex].dwFlags & MAFA_COMPRESS)
+                       {
+                               BYTE *compdata = compbuffer;
+                               memcpy(compdata,(char *)blkBuffer,mpqOpenFile->lpdwBlockOffsets[i+1]-mpqOpenFile->lpdwBlockOffsets[i]);
+                               if (compdata[0]&UNSUPPORTED_DECOMPRESSION) {
+                                       LoadStorm();
+                                       if (stormSCompDecompress)
+                                               stormSCompDecompress(blkBuffer, &outLength, compdata, mpqOpenFile->lpdwBlockOffsets[i+1]-mpqOpenFile->lpdwBlockOffsets[i]);
+                               }
+                               else {
+                                       SCompDecompress(blkBuffer, &outLength, compdata, mpqOpenFile->lpdwBlockOffsets[i+1]-mpqOpenFile->lpdwBlockOffsets[i]);
+                               }
+                       }
+                       else if (mpqOpenArc->lpBlockTable[BlockIndex].dwFlags & MAFA_COMPRESS2)
+                       {
+                               BYTE *compdata = compbuffer;
+                               compdata[0] = 0x08;
+                               memcpy(compdata+1,(char *)blkBuffer,mpqOpenFile->lpdwBlockOffsets[i+1]-mpqOpenFile->lpdwBlockOffsets[i]);
+                               SCompDecompress(blkBuffer, &outLength, compdata, mpqOpenFile->lpdwBlockOffsets[i+1]-mpqOpenFile->lpdwBlockOffsets[i]+1);
+                       }
+               }
+               if (i==blockNum) {
+                       if (nNumberOfBytesToRead > blockSize-dwBlockPos) {
+                               memcpy(lpBuffer,(char *)blkBuffer+dwBlockPos,blockSize-dwBlockPos);
+                               TotalBytesRead+=blockSize-dwBlockPos;
+                               mpqOpenFile->dwFilePointer += blockSize-dwBlockPos;
+                               nNumberOfBytesToRead-=blockSize-dwBlockPos;
+                       }
+                       else {
+                               memcpy(lpBuffer,(char *)blkBuffer+dwBlockPos,nNumberOfBytesToRead);
+                               TotalBytesRead+=nNumberOfBytesToRead;
+                               mpqOpenFile->dwFilePointer += nNumberOfBytesToRead;
+                               nNumberOfBytesToRead-=nNumberOfBytesToRead;
+                       }
+               }
+               else if (i==nBlocks-1) {
+                       if (nNumberOfBytesToRead > dwBlockPosEnd) {
+                               memcpy((char *)lpBuffer+TotalBytesRead,blkBuffer,dwBlockPosEnd);
+                               TotalBytesRead+=dwBlockPosEnd;
+                               mpqOpenFile->dwFilePointer += dwBlockPosEnd;
+                               nNumberOfBytesToRead-=dwBlockPosEnd;
+                       }
+                       else {
+                               memcpy((char *)lpBuffer+TotalBytesRead,blkBuffer,nNumberOfBytesToRead);
+                               TotalBytesRead+=nNumberOfBytesToRead;
+                               mpqOpenFile->dwFilePointer += nNumberOfBytesToRead;
+                               nNumberOfBytesToRead-=nNumberOfBytesToRead;
+                       }
+               }
+               else {
+                       if (nNumberOfBytesToRead > blockSize) {
+                               memcpy((char *)lpBuffer+TotalBytesRead,blkBuffer,blockSize);
+                               TotalBytesRead+=blockSize;
+                               mpqOpenFile->dwFilePointer += blockSize;
+                               nNumberOfBytesToRead-=blockSize;
+                       }
+                       else {
+                               memcpy((char *)lpBuffer+TotalBytesRead,blkBuffer,nNumberOfBytesToRead);
+                               TotalBytesRead+=nNumberOfBytesToRead;
+                               mpqOpenFile->dwFilePointer += nNumberOfBytesToRead;
+                               nNumberOfBytesToRead-=nNumberOfBytesToRead;
+                       }
+               }
+               blk = (blk+1) % 16;
+       }
+       SFFree(compbuffer);
+       SFFree(blk16Buffer);
+       SFFree(blkBuffer);
+       if (lpNumberOfBytesRead) *lpNumberOfBytesRead = TotalBytesRead;
+       if (lpOverlapped) lpOverlapped->InternalHigh = TotalBytesRead;
+       return TRUE;
+}
+
+LCID SFMPQAPI WINAPI SFileSetLocale(LCID nNewLocale)
+{
+       return (LocaleID = nNewLocale);
+}
+
+BOOL SFMPQAPI WINAPI SFileGetBasePath(LPCSTR lpBuffer, DWORD dwBufferLength)
+{
+       if (lpBuffer==0) {
+               SetLastError(ERROR_INVALID_PARAMETER);
+               return FALSE;
+       }
+
+       DWORD slen = strlen(StormBasePath)+1;
+       if (dwBufferLength>=slen) memcpy((void *)lpBuffer,StormBasePath,slen);
+       else memcpy((void *)lpBuffer,StormBasePath,dwBufferLength);
+       return TRUE;
+}
+
+BOOL SFMPQAPI WINAPI SFileSetBasePath(LPCSTR lpNewBasePath)
+{
+       if (!lpNewBasePath) {
+               SetLastError(ERROR_INVALID_PARAMETER);
+               return FALSE;
+       }
+       if (!*lpNewBasePath) {
+               SetLastError(ERROR_INVALID_PARAMETER);
+               return FALSE;
+       }
+
+       DWORD slen = strlen(lpNewBasePath)+1;
+       if (slen>MAX_PATH+1) return FALSE;
+       else if (slen==MAX_PATH+1)
+               if (lpNewBasePath[MAX_PATH-1]!='\\' && lpNewBasePath[MAX_PATH-1]!='/') return FALSE;
+       TempAlloc NewAlloc;
+       char *buffer = (char *)NewAlloc.Alloc(slen+1);
+       memcpy(buffer,lpNewBasePath,slen);
+       char *npath;
+#ifdef _WIN32
+       for (npath=buffer;npath[0]!=0;npath++)
+               if (npath[0]=='/') npath[0]='\\';
+       if (npath[-1]!='\\') {
+               npath[0]='\\';
+               npath[1]=0;
+               slen+=1;
+       }
+#else
+       for (npath=buffer;npath[0]!=0;npath++)
+               if (npath[0]=='\\') npath[0]='/';
+       if (npath[-1]!='/') {
+               npath[0]='/';
+               npath[1]=0;
+               slen+=1;
+       }
+#endif
+#ifdef _WIN32
+       DWORD attrib = GetFileAttributes(buffer);
+       if ((attrib&FILE_ATTRIBUTE_DIRECTORY)==0 || attrib==0xFFFFFFFF) return FALSE;
+#endif
+
+       memcpy(StormBasePath,buffer,slen);
+       return TRUE;
+}
+
+BOOL SFMPQAPI WINAPI SFileSetArchivePriority(MPQHANDLE hMPQ, DWORD dwPriority)
+{
+       if (!hMPQ) {
+               SetLastError(ERROR_INVALID_PARAMETER);
+               return FALSE;
+       }
+
+       MPQARCHIVE *mpqOpenArc = (MPQARCHIVE *)hMPQ;
+       mpqOpenArc->dwPriority = dwPriority;
+       if (dwOpenMpqCount>1) SortOpenArchivesByPriority();
+       return TRUE;
+}
+
+int StringICompare(const void *arg1,const void *arg2)
+{
+       return stricmp(*(char **)arg1,*(char **)arg2);
+}
+
+BOOL SFMPQAPI WINAPI SFileListFiles(MPQHANDLE hMPQ, LPCSTR lpFileLists, FILELISTENTRY *lpListBuffer, DWORD dwFlags)
+{
+       if (!hMPQ || !lpListBuffer) {
+               SetLastError(ERROR_INVALID_PARAMETER);
+               return FALSE;
+       }
+
+       MPQARCHIVE *mpqOpenArc = (MPQARCHIVE *)hMPQ;
+       DWORD i,tsz;
+
+       if (memcmp(&mpqOpenArc->MpqHeader.dwMPQID,ID_BN3,4)==0)
+       {
+               for (i=0;i<mpqOpenArc->MpqHeader.dwHashTableSize;i++) {
+                       lpListBuffer[i].dwFileExists = 0;
+                       lpListBuffer[i].szFileName[0] = 0;
+                       if ((mpqOpenArc->lpHashTable[i].dwBlockTableIndex&0xFFFFFFFE)!=0xFFFFFFFE) {
+                               lpListBuffer[i].lcLocale = mpqOpenArc->lpHashTable[i].lcLocale;
+                               DWORD dwBlockIndex = mpqOpenArc->lpHashTable[i].dwBlockTableIndex;
+                               lpListBuffer[i].dwCompressedSize = mpqOpenArc->lpBlockTable[dwBlockIndex].dwCompressedSize;
+                               lpListBuffer[i].dwFullSize = mpqOpenArc->lpBlockTable[dwBlockIndex].dwFullSize;
+                               lpListBuffer[i].dwFlags = mpqOpenArc->lpBlockTable[dwBlockIndex].dwFlags;
+                               lpListBuffer[i].dwFileExists=0xFFFFFFFF;
+                               SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->lpBlockTable[dwBlockIndex].dwFileOffset+0x40,0,FILE_BEGIN);
+                               ReadFile(mpqOpenArc->hFile,lpListBuffer[i].szFileName,260,&tsz,0);
+
+                               if (mpqOpenArc->lpHashTable[i].dwNameHashA==HashString(lpListBuffer[i].szFileName,HASH_NAME_A) && mpqOpenArc->lpHashTable[i].dwNameHashB==HashString(lpListBuffer[i].szFileName,HASH_NAME_B)) {
+                                       if (dwFlags&SFILE_LIST_ONLY_UNKNOWN && !(dwFlags&SFILE_LIST_ONLY_KNOWN)) {
+                                               lpListBuffer[i].dwFileExists = 0;
+                                       }
+                               }
+                               else {
+                                       sprintf(lpListBuffer[i].szFileName,UNKNOWN_OUT,i);
+                                       if (dwFlags&SFILE_LIST_ONLY_KNOWN) {
+                                               lpListBuffer[i].dwFileExists = 0;
+                                       }
+                               }
+                       }
+               }
+
+               return TRUE;
+       }
+
+       char **lpNameBuffers=0;
+
+       char **lpNames=0,szNull[1]={0},*lpFLCopy;
+       DWORD *lpdwNameHashA=0,*lpdwNameHashB=0;
+       DWORD dwListNameHashA,dwListNameHashB;
+       DWORD j;
+       lpFLCopy = (char *)lpFileLists;
+       DWORD dwExtLists=0,dwIntLists=0;
+       if (!lpFLCopy) lpFLCopy=szNull;
+       char *lpLines;
+       for (lpLines=lpFLCopy;lpLines;lpLines=nextline(lpLines)) {
+               if (!*lpLines) break;
+               dwExtLists++;
+       }
+       dwListNameHashA = HashString(INTERNAL_LISTFILE,HASH_NAME_A);
+       dwListNameHashB = HashString(INTERNAL_LISTFILE,HASH_NAME_B);
+       for (i=0;i<mpqOpenArc->MpqHeader.dwHashTableSize;i++) {
+               if (mpqOpenArc->lpHashTable[i].dwNameHashA==dwListNameHashA && mpqOpenArc->lpHashTable[i].dwNameHashB==dwListNameHashB && (mpqOpenArc->lpHashTable[i].dwBlockTableIndex&0xFFFFFFFE)!=0xFFFFFFFE) {
+                       dwIntLists++;
+               }
+       }
+       lpNameBuffers = (char **)SFAlloc((1+dwExtLists+dwIntLists)*sizeof(char *));
+       if (dwExtLists) {
+               lpFLCopy = strdup(lpFLCopy);
+               i=0;
+               for (lpLines=lpFLCopy;lpLines;lpLines=nextline(lpLines)) {
+                       if (!*lpLines) break;
+                       lpNameBuffers[i+1] = lpLines;
+                       i++;
+               }
+               for (i=0;i<dwExtLists;i++) {
+                       lpNameBuffers[i+1][strlnlen(lpNameBuffers[i+1])]=0;
+               }
+               qsort(lpNameBuffers+1,dwExtLists,sizeof(char *),StringICompare);
+               for (i=0;i<dwExtLists-1;i++) {
+                       if (stricmp(lpNameBuffers[i+1],lpNameBuffers[i+2])==0) {
+                               memmove(&lpNameBuffers[i+1],&lpNameBuffers[i+2],(dwExtLists-(i+1))*sizeof(char *));
+                               dwExtLists--;
+                       }
+               }
+       }
+       if (dwIntLists) {
+               dwIntLists = 0;
+               for (i=0;i<mpqOpenArc->MpqHeader.dwHashTableSize;i++) {
+                       if (mpqOpenArc->lpHashTable[i].dwNameHashA==dwListNameHashA && mpqOpenArc->lpHashTable[i].dwNameHashB==dwListNameHashB && (mpqOpenArc->lpHashTable[i].dwBlockTableIndex&0xFFFFFFFE)!=0xFFFFFFFE) {
+                               lpNameBuffers[1+dwExtLists+dwIntLists] = (char *)i;
+                               dwIntLists++;
+                       }
+               }
+       }
+       DWORD dwLines=0,dwOldLines=0,dwTotalLines=0;
+       DWORD fsz;
+       HANDLE hFile;
+       DWORD dwListCryptKey = HashString(INTERNAL_LISTFILE,HASH_KEY);
+       for (i=0;i<1+dwExtLists+dwIntLists;i++) {
+               if (i==0) {
+                       fsz = strlen(INTERNAL_FILES);
+                       lpNameBuffers[i] = (char *)SFAlloc(fsz+1);
+                       memcpy(lpNameBuffers[i],INTERNAL_FILES,fsz);
+                       lpNameBuffers[i][fsz]=0;
+               }
+               else if (i<1+dwExtLists) {
+                       if (!(dwFlags&SFILE_LIST_MEMORY_LIST)) {
+                               hFile = CreateFile(lpNameBuffers[i],GENERIC_READ,FILE_SHARE_READ,0,OPEN_EXISTING,0,0);
+                               if (hFile!=INVALID_HANDLE_VALUE) {
+                                       fsz = GetFileSize(hFile,0);
+                                       SetFilePointer(hFile,0,0,FILE_BEGIN);
+                                       lpNameBuffers[i] = (char *)SFAlloc(fsz+1);
+                                       ReadFile(hFile,lpNameBuffers[i],fsz,&tsz,0);
+                                       CloseHandle(hFile);
+                                       lpNameBuffers[i][fsz]=0;
+                               }
+                               else lpNameBuffers[i]=0;
+                       }
+                       else {
+                               dwTotalLines++;
+                               continue;
+                       }
+               }
+               else {
+                       MPQFILE thisFile;
+                       memset(&thisFile,0,sizeof(MPQFILE));
+                       thisFile.lpParentArc = (MPQARCHIVE *)hMPQ;
+                       thisFile.hFile = INVALID_HANDLE_VALUE;
+                       thisFile.lpHashEntry = &mpqOpenArc->lpHashTable[(DWORD)lpNameBuffers[i]];
+                       thisFile.lpBlockEntry = &mpqOpenArc->lpBlockTable[thisFile.lpHashEntry->dwBlockTableIndex];
+                       thisFile.lpFileName = thisFile.szFileName;
+                       strcpy(thisFile.lpFileName,INTERNAL_LISTFILE);
+                       thisFile.dwFilePointer = 0;
+                       thisFile.lpdwBlockOffsets = 0;
+                       BLOCKTABLEENTRY *lpBlockEntry = thisFile.lpBlockEntry;
+                       if (lpBlockEntry->dwFlags & MAFA_ENCRYPT) {
+                               thisFile.dwCryptKey = dwListCryptKey;
+                               if (lpBlockEntry->dwFlags & MAFA_MODCRYPTKEY)
+                                       thisFile.dwCryptKey = (thisFile.dwCryptKey + lpBlockEntry->dwFileOffset) ^ lpBlockEntry->dwFullSize;
+                       }
+                       fsz = lpBlockEntry->dwFullSize;
+                       lpNameBuffers[i] = (char *)SFAlloc(fsz+1);
+                       SFileReadFile(&thisFile,lpNameBuffers[i],fsz,0,0);
+                       if (thisFile.lpdwBlockOffsets) SFFree(thisFile.lpdwBlockOffsets);
+                       lpNameBuffers[i][fsz]=0;
+               }
+               for (lpLines=lpNameBuffers[i];lpLines;lpLines=nextline(lpLines)) {
+                       if (!*lpLines) break;
+                       dwTotalLines++;
+               }
+       }
+       lpNames = (char **)SFAlloc(dwTotalLines*sizeof(char *));
+       for (i=0;i<1+dwExtLists+dwIntLists;i++) {
+               dwOldLines=dwLines;
+               for (lpLines=lpNameBuffers[i];lpLines;lpLines=nextline(lpLines)) {
+                       if (!*lpLines) break;
+                       lpNames[dwLines] = lpLines;
+                       dwLines++;
+               }
+               for (j=dwOldLines;j<dwLines;j++) {
+                       lpNames[j][strlnlen(lpNames[j])]=0;
+               }
+       }
+       qsort(lpNames,dwTotalLines,sizeof(char *),StringICompare);
+       for (i=0;i<dwTotalLines-1;i++) {
+               if (stricmp(lpNames[i],lpNames[i+1])==0) {
+                       memmove(&lpNames[i],&lpNames[i+1],(dwTotalLines-(i+1))*sizeof(char *));
+                       dwTotalLines--;
+               }
+       }
+       if (dwTotalLines) {
+               lpdwNameHashA = (DWORD *)SFAlloc(dwTotalLines*sizeof(DWORD));
+               lpdwNameHashB = (DWORD *)SFAlloc(dwTotalLines*sizeof(DWORD));
+               for (i=0;i<dwTotalLines;i++) {
+                       lpdwNameHashA[i] = HashString(lpNames[i],HASH_NAME_A);
+                       lpdwNameHashB[i] = HashString(lpNames[i],HASH_NAME_B);
+               }
+       }
+       for (i=0;i<mpqOpenArc->MpqHeader.dwHashTableSize;i++) {
+               lpListBuffer[i].dwFileExists = 0;
+               lpListBuffer[i].szFileName[0] = 0;
+               if ((mpqOpenArc->lpHashTable[i].dwBlockTableIndex&0xFFFFFFFE)!=0xFFFFFFFE) {
+                       lpListBuffer[i].lcLocale = mpqOpenArc->lpHashTable[i].lcLocale;
+                       DWORD dwBlockIndex = mpqOpenArc->lpHashTable[i].dwBlockTableIndex;
+                       lpListBuffer[i].dwCompressedSize = mpqOpenArc->lpBlockTable[dwBlockIndex].dwCompressedSize;
+                       lpListBuffer[i].dwFullSize = mpqOpenArc->lpBlockTable[dwBlockIndex].dwFullSize;
+                       lpListBuffer[i].dwFlags = mpqOpenArc->lpBlockTable[dwBlockIndex].dwFlags;
+                       lpListBuffer[i].dwFileExists=0xFFFFFFFF;
+                       for (j=0;j<dwTotalLines;j++) {
+                               if (mpqOpenArc->lpHashTable[i].dwNameHashA==lpdwNameHashA[j] && mpqOpenArc->lpHashTable[i].dwNameHashB==lpdwNameHashB[j]) {
+                                       strncpy(lpListBuffer[i].szFileName,lpNames[j],260);
+                                       if (dwFlags&SFILE_LIST_ONLY_UNKNOWN && !(dwFlags&SFILE_LIST_ONLY_KNOWN)) {
+                                               lpListBuffer[i].dwFileExists = 0;
+                                       }
+                                       break;
+                               }
+                               if (j+1==dwTotalLines) {
+                                       sprintf(lpListBuffer[i].szFileName,UNKNOWN_OUT,i);
+                                       if (dwFlags&SFILE_LIST_ONLY_KNOWN) {
+                                               lpListBuffer[i].dwFileExists = 0;
+                                       }
+                               }
+                       }
+               }
+       }
+       if (lpNameBuffers) {
+               for (i=0;i<1+dwExtLists+dwIntLists;i++) {
+                       if (i>=1 && i<1+dwExtLists) {
+                               if ((dwFlags&SFILE_LIST_MEMORY_LIST)) {
+                                       continue;
+                               }
+                       }
+                       if (lpNameBuffers[i]) SFFree(lpNameBuffers[i]);
+               }
+               SFFree(lpNameBuffers);
+       }
+       if (dwExtLists) SFFree(lpFLCopy);
+       if (lpdwNameHashA) SFFree(lpdwNameHashA);
+       if (lpdwNameHashB) SFFree(lpdwNameHashB);
+       return TRUE;
+}
+
+MPQHANDLE SFMPQAPI WINAPI MpqOpenArchiveForUpdate(LPCSTR lpFileName, DWORD dwFlags, DWORD dwMaximumFilesInArchive)
+{
+       MPQHANDLE hMPQ;
+
+       MpqOpenArchiveEx(lpFileName,0,0,&hMPQ,dwFlags,dwMaximumFilesInArchive,USE_DEFAULT_BLOCK_SIZE);
+       return hMPQ;
+}
+
+MPQHANDLE SFMPQAPI WINAPI MpqOpenArchiveForUpdateEx(LPCSTR lpFileName, DWORD dwFlags, DWORD dwMaximumFilesInArchive, DWORD dwBlockSize)
+{
+       MPQHANDLE hMPQ;
+
+       MpqOpenArchiveEx(lpFileName,0,0,&hMPQ,dwFlags,dwMaximumFilesInArchive,dwBlockSize);
+       return hMPQ;
+}
+
+DWORD SFMPQAPI WINAPI MpqCloseUpdatedArchive(MPQHANDLE hMPQ, DWORD dwUnknown2)
+{
+       return SFileCloseArchive(hMPQ);
+}
+
+BOOL SFMPQAPI WINAPI MpqAddFileToArchiveEx(MPQHANDLE hMPQ, LPCSTR lpSourceFileName, LPCSTR lpDestFileName, DWORD dwFlags, DWORD dwCompressionType, DWORD dwCompressLevel)
+{
+       if (!hMPQ || !lpSourceFileName || !lpDestFileName) {
+               SetLastError(ERROR_INVALID_PARAMETER);
+               return FALSE;
+       }
+       if (!*lpSourceFileName || !*lpDestFileName) {
+               SetLastError(ERROR_INVALID_PARAMETER);
+               return FALSE;
+       }
+
+       if (!(((MPQARCHIVE *)hMPQ)->dwFlags&SFILE_OPEN_ALLOW_WRITE)) {
+               SetLastError(ERROR_ACCESS_DENIED);
+               return FALSE;
+       }
+       BOOL ReplaceExisting;
+       if (dwFlags&MAFA_REPLACE_EXISTING) {
+               dwFlags = dwFlags^MAFA_REPLACE_EXISTING;
+               ReplaceExisting = TRUE;
+       }
+       else ReplaceExisting = FALSE;
+       MPQHANDLE hFile = GetFreeHashTableEntry(hMPQ,lpDestFileName,LocaleID,ReplaceExisting);
+       if (!hFile) return FALSE;
+       HANDLE haFile = CreateFile(lpSourceFileName,GENERIC_READ,FILE_SHARE_READ,0,OPEN_EXISTING,0,0);
+       if (haFile==INVALID_HANDLE_VALUE) return FALSE;
+       DWORD fsz = GetFileSize(haFile,0),tsz;
+       DWORD ucfsz = fsz;
+       BOOL IsBNcache = FALSE;char *buffer,*hbuffer;
+       MPQARCHIVE *mpqOpenArc = (MPQARCHIVE *)hMPQ;
+       DWORD blockSize = 512 << mpqOpenArc->MpqHeader.wBlockSize;
+       DWORD TotalBlocks = fsz / blockSize;
+       if(fsz % blockSize)
+               TotalBlocks++;
+       DWORD ptsz = 0;
+       if (dwFlags&MAFA_COMPRESS || dwFlags&MAFA_COMPRESS2) ptsz = (TotalBlocks+1)*4;
+       if (memcmp(&mpqOpenArc->MpqHeader.dwMPQID,ID_BN3,4)==0)
+       {
+               IsBNcache = TRUE;
+               hbuffer = (char *)SFAlloc(fsz+324+ptsz);
+               if (!hbuffer) {
+                       CloseHandle(haFile);
+                       return FALSE;
+               }
+               hbuffer[0] = (char)0x44;
+               hbuffer[1] = (char)0x01;
+               DWORD lpFileNameLength = strlen(lpDestFileName);
+               if (lpFileNameLength<=260) memcpy(hbuffer+64,lpDestFileName,lpFileNameLength);
+               else strncpy(hbuffer+64,lpDestFileName,260);
+               buffer = hbuffer+324;
+       }
+       else buffer = (char *)SFAlloc(fsz+ptsz);
+       if (!buffer && fsz!=0) {
+               CloseHandle(haFile);
+               return FALSE;
+       }
+       if (fsz!=0) {
+               if (ReadFile(haFile,buffer,fsz,&tsz,0)==0) {
+                       SFFree(buffer);
+                       CloseHandle(haFile);
+                       return FALSE;
+               }
+       }
+       else {
+               if (dwFlags&MAFA_COMPRESS) dwFlags = dwFlags^MAFA_COMPRESS;
+               if (dwFlags&MAFA_COMPRESS2) dwFlags = dwFlags^MAFA_COMPRESS2;
+               if (dwFlags&MAFA_ENCRYPT) dwFlags = dwFlags^MAFA_ENCRYPT;
+               if (dwFlags&MAFA_MODCRYPTKEY) dwFlags = dwFlags^MAFA_MODCRYPTKEY;
+       }
+       CloseHandle(haFile);
+       DWORD i;
+       DWORD *dwBlkpt = (DWORD *)SFAlloc((TotalBlocks+1)*4);
+       if (!dwBlkpt) {
+               SFFree(buffer);
+               return FALSE;
+       }
+       if ((dwFlags & MAFA_COMPRESS) || (dwFlags & MAFA_COMPRESS2))
+       {
+               DWORD dwCompressionSubType = 0;
+
+               if ((dwCompressionType&0x40 || dwCompressionType&0x80) && (memcmp(buffer,ID_RIFF,4)!=0 || memcmp(buffer+8,ID_WAVE,8)!=0 || buffer[20]!=1 || buffer[34]!=16)) {
+                       dwCompressionType = 0x08;
+                       dwCompressLevel = 0;
+               }
+               if (dwCompressionType&0x40 || dwCompressionType&0x80) {
+                       switch (dwCompressLevel) {
+                               case MAWA_QUALITY_HIGH:
+                                       dwCompressLevel = 1;
+                                       break;
+                               case MAWA_QUALITY_LOW:
+                                       dwCompressLevel = 3;
+                                       break;
+                               default:
+                                       dwCompressLevel = 0;
+                       }
+               }
+               else if (dwCompressionType&0x01 || dwCompressionType&0x08 || ((dwFlags & MAFA_COMPRESS)!=MAFA_COMPRESS && (dwFlags & MAFA_COMPRESS2)==MAFA_COMPRESS2)) {
+                       dwCompressionSubType = dwCompressLevel;
+                       dwCompressLevel = 0;
+               }
+               else if (dwCompressionType&0x02) {
+                       dwCompressionSubType = 1;
+               }
+
+               DWORD LastOffset=ptsz;
+               BYTE *compbuffer = (BYTE *)SFAlloc(blockSize);
+               if (!compbuffer) {
+                       SFFree(dwBlkpt);
+                       SFFree(buffer);
+                       return FALSE;
+               }
+               char *outbuffer = (char *)SFAlloc(blockSize);
+               if (!outbuffer) {
+                       SFFree(compbuffer);
+                       SFFree(dwBlkpt);
+                       SFFree(buffer);
+                       return FALSE;
+               }
+               char *newbuffer = (char *)SFAlloc(fsz+ptsz);
+               if (!newbuffer) {
+                       SFFree(outbuffer);
+                       SFFree(compbuffer);
+                       SFFree(dwBlkpt);
+                       SFFree(buffer);
+                       return FALSE;
+               }
+               DWORD CurPos=0;
+               for (i=0;i<TotalBlocks;i++) {
+                       dwBlkpt[i] = LastOffset;
+                       if (i==TotalBlocks-1 && (ucfsz % blockSize)!=0) blockSize=ucfsz % blockSize;
+                       DWORD outLength=blockSize;
+                       BYTE *compdata = compbuffer;
+                       char *oldoutbuffer = outbuffer;
+                       if (dwFlags & MAFA_COMPRESS)
+                       {
+                               memcpy(compdata,(char *)buffer+CurPos,blockSize);
+                               if (i==0 && (dwCompressionType&0x40 || dwCompressionType&0x80)) {
+                                       if (SCompCompress(outbuffer, &outLength, compdata, blockSize, 0x08, 0, 0)==0)
+                                               outLength=blockSize;
+                               }
+                               else
+                               {
+                                       if (dwCompressionType&UNSUPPORTED_COMPRESSION) {
+                                               LoadStorm();
+                                               if (stormSCompCompress) {
+                                                       if (stormSCompCompress(outbuffer, &outLength, compdata, blockSize, dwCompressionType, dwCompressionSubType, dwCompressLevel)==0)
+                                                               outLength=blockSize;
+                                               }
+                                       }
+                                       else {
+                                               if (SCompCompress(outbuffer, &outLength, compdata, blockSize, dwCompressionType, dwCompressionSubType, dwCompressLevel)==0)
+                                                       outLength=blockSize;
+                                       }
+                               }
+                       }
+                       else if (dwFlags & MAFA_COMPRESS2)
+                       {
+                               memcpy(compdata,(char *)buffer+CurPos,blockSize);
+                               if (SCompCompress(outbuffer, &outLength, compdata, blockSize, 0x08, dwCompressionSubType, 0)==0) {
+                                       outLength=blockSize;
+                               }
+                               else {
+                                       outbuffer++;
+                                       outLength--;
+                               }
+                       }
+                       else
+                       {
+                               memcpy(compdata,(char *)buffer+CurPos,blockSize);
+                       }
+                       if (outLength>=blockSize)
+                       {
+                               memcpy((char *)newbuffer+LastOffset,compdata,blockSize);
+                               LastOffset+=blockSize;
+                       }
+                       else {
+                               memcpy((char *)newbuffer+LastOffset,outbuffer,outLength);
+                               LastOffset+=outLength;
+                       }
+                       outbuffer = oldoutbuffer;
+                       CurPos += blockSize;
+               }
+               fsz = LastOffset;
+               dwBlkpt[TotalBlocks] = fsz;
+               memcpy(newbuffer,dwBlkpt,ptsz);
+
+               SFFree(outbuffer);
+               SFFree(compbuffer);
+               memcpy(buffer,newbuffer,fsz);
+               SFFree(newbuffer);
+       }
+       else
+       {
+               for (i=0;i<TotalBlocks+1;i++) {
+                       if (i<TotalBlocks) dwBlkpt[i] = i * blockSize;
+                       else dwBlkpt[i] = ucfsz;
+               }
+       }
+       if (IsBNcache==TRUE)
+       {
+               buffer = hbuffer;
+               fsz += 324;
+       }
+       HASHTABLEENTRY *hashEntry = (HASHTABLEENTRY *)hFile;
+       BOOL IsNewBlockEntry = FALSE;DWORD OldBlockTableSize = sizeof(BLOCKTABLEENTRY) * mpqOpenArc->MpqHeader.dwBlockTableSize;
+       if ((hashEntry->dwBlockTableIndex&0xFFFFFFFE)==0xFFFFFFFE)
+       {
+               BLOCKTABLEENTRY *lpnBlockTable;
+               lpnBlockTable = (BLOCKTABLEENTRY *)SFAlloc(sizeof(BLOCKTABLEENTRY) * (mpqOpenArc->MpqHeader.dwBlockTableSize + 1));
+               if(!lpnBlockTable) {
+                       SFFree(buffer);
+                       return FALSE;
+               }
+               if (mpqOpenArc->lpBlockTable) memcpy(lpnBlockTable,mpqOpenArc->lpBlockTable,sizeof(BLOCKTABLEENTRY) * mpqOpenArc->MpqHeader.dwBlockTableSize);
+               mpqOpenArc->MpqHeader.dwBlockTableSize++;
+               if (mpqOpenArc->lpBlockTable) SFFree(mpqOpenArc->lpBlockTable);
+               mpqOpenArc->lpBlockTable = lpnBlockTable;
+               IsNewBlockEntry = TRUE;
+       }
+       DWORD BlockIndex = mpqOpenArc->MpqHeader.dwBlockTableSize - 1;
+       if ((hashEntry->dwBlockTableIndex&0xFFFFFFFE)==0xFFFFFFFE)
+       {
+               hashEntry->dwNameHashA = HashString(lpDestFileName,HASH_NAME_A);
+               hashEntry->dwNameHashB = HashString(lpDestFileName,HASH_NAME_B);
+               hashEntry->lcLocale = LocaleID;
+               hashEntry->dwBlockTableIndex = BlockIndex;
+               mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset = 0;
+
+       }
+       else
+       {
+               BlockIndex = hashEntry->dwBlockTableIndex;
+       }
+       if (mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset==0 || mpqOpenArc->lpBlockTable[BlockIndex].dwCompressedSize<fsz)
+       {
+               if (mpqOpenArc->MpqHeader.dwHashTableOffset+(mpqOpenArc->MpqHeader.dwHashTableSize * sizeof(HASHTABLEENTRY))+OldBlockTableSize==mpqOpenArc->MpqHeader.dwMPQSize)
+               {
+                       if (mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset+mpqOpenArc->lpBlockTable[BlockIndex].dwCompressedSize==mpqOpenArc->MpqHeader.dwHashTableOffset)
+                       {
+                               mpqOpenArc->MpqHeader.dwHashTableOffset += fsz-mpqOpenArc->lpBlockTable[BlockIndex].dwCompressedSize;
+                               mpqOpenArc->MpqHeader.dwBlockTableOffset += fsz-mpqOpenArc->lpBlockTable[BlockIndex].dwCompressedSize;
+                               mpqOpenArc->MpqHeader.dwMPQSize += fsz-mpqOpenArc->lpBlockTable[BlockIndex].dwCompressedSize;
+                               if (IsNewBlockEntry==TRUE) mpqOpenArc->MpqHeader.dwMPQSize += sizeof(BLOCKTABLEENTRY);
+                       }
+                       else
+                       {
+                               mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset = mpqOpenArc->MpqHeader.dwHashTableOffset;
+                               mpqOpenArc->MpqHeader.dwHashTableOffset += fsz;
+                               mpqOpenArc->MpqHeader.dwBlockTableOffset += fsz;
+                               mpqOpenArc->MpqHeader.dwMPQSize += fsz;
+                               if (IsNewBlockEntry==TRUE) mpqOpenArc->MpqHeader.dwMPQSize += sizeof(BLOCKTABLEENTRY);
+                       }
+               }
+               else if (mpqOpenArc->MpqHeader.dwBlockTableOffset+OldBlockTableSize==mpqOpenArc->MpqHeader.dwMPQSize)
+               {
+                       if (mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset+mpqOpenArc->lpBlockTable[BlockIndex].dwCompressedSize==mpqOpenArc->MpqHeader.dwBlockTableOffset)
+                       {
+                               mpqOpenArc->MpqHeader.dwBlockTableOffset += fsz-mpqOpenArc->lpBlockTable[BlockIndex].dwCompressedSize;
+                               mpqOpenArc->MpqHeader.dwMPQSize += fsz-mpqOpenArc->lpBlockTable[BlockIndex].dwCompressedSize;
+                               if (IsNewBlockEntry==TRUE) mpqOpenArc->MpqHeader.dwMPQSize += sizeof(BLOCKTABLEENTRY);
+                       }
+                       else
+                       {
+                               mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset = mpqOpenArc->MpqHeader.dwBlockTableOffset;
+                               mpqOpenArc->MpqHeader.dwBlockTableOffset += fsz;
+                               mpqOpenArc->MpqHeader.dwMPQSize += fsz;
+                               if (IsNewBlockEntry==TRUE) mpqOpenArc->MpqHeader.dwMPQSize += sizeof(BLOCKTABLEENTRY);
+                       }
+               }
+               else
+               {
+                       if (mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset+mpqOpenArc->lpBlockTable[BlockIndex].dwCompressedSize==mpqOpenArc->MpqHeader.dwMPQSize)
+                       {
+                               mpqOpenArc->MpqHeader.dwBlockTableOffset = mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset+fsz;
+                               mpqOpenArc->MpqHeader.dwMPQSize = mpqOpenArc->MpqHeader.dwBlockTableOffset+OldBlockTableSize;
+                               if (IsNewBlockEntry==TRUE) mpqOpenArc->MpqHeader.dwMPQSize += sizeof(BLOCKTABLEENTRY);
+                       }
+                       else
+                       {
+                               mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset = mpqOpenArc->MpqHeader.dwMPQSize;
+                               mpqOpenArc->MpqHeader.dwBlockTableOffset = mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset+fsz;
+                               mpqOpenArc->MpqHeader.dwMPQSize = mpqOpenArc->MpqHeader.dwBlockTableOffset+OldBlockTableSize;
+                               if (IsNewBlockEntry==TRUE) mpqOpenArc->MpqHeader.dwMPQSize += sizeof(BLOCKTABLEENTRY);
+                       }
+               }
+       }
+       mpqOpenArc->lpBlockTable[BlockIndex].dwCompressedSize = fsz;
+       mpqOpenArc->lpBlockTable[BlockIndex].dwFullSize = ucfsz;
+       mpqOpenArc->lpBlockTable[BlockIndex].dwFlags = dwFlags|MAFA_EXISTS;
+       DWORD dwFileOffset = mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset;
+       SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart,0,FILE_BEGIN);
+       WriteFile(mpqOpenArc->hFile,&mpqOpenArc->MpqHeader,mpqOpenArc->MpqHeader.dwHeaderSize,&tsz,0);
+       if (dwFlags & MAFA_ENCRYPT) {
+               DWORD dwCryptKey;
+               if (dwFlags&MAFA_ENCRYPT) dwCryptKey = HashString(lpDestFileName,HASH_KEY);
+               if (dwFlags&MAFA_MODCRYPTKEY) dwCryptKey = (dwCryptKey + mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset) ^ mpqOpenArc->lpBlockTable[BlockIndex].dwFullSize;
+               DWORD blockSize = 512 << mpqOpenArc->MpqHeader.wBlockSize;
+               DWORD TotalBlocks = mpqOpenArc->lpBlockTable[BlockIndex].dwFullSize / blockSize;
+               if(mpqOpenArc->lpBlockTable[BlockIndex].dwFullSize % blockSize)
+                       TotalBlocks++;
+               DWORD dwBlockEnd = mpqOpenArc->lpBlockTable[BlockIndex].dwFullSize % blockSize;
+               if (dwBlockEnd==0) dwBlockEnd = blockSize;
+               if ((dwFlags & MAFA_COMPRESS)==MAFA_COMPRESS || (dwFlags & MAFA_COMPRESS2)==MAFA_COMPRESS2) {
+                       EncryptData((LPBYTE)buffer,ptsz,dwCryptKey-1);
+               }
+               for (DWORD i=0;i<TotalBlocks;i++) {
+                       EncryptData((LPBYTE)buffer+dwBlkpt[i],dwBlkpt[i+1]-dwBlkpt[i],dwCryptKey);
+                       dwCryptKey++;
+               }
+       }
+       SFFree(dwBlkpt);
+       SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+dwFileOffset,0,FILE_BEGIN);
+       WriteFile(mpqOpenArc->hFile,buffer,fsz,&tsz,0);
+       SFFree(buffer);
+       buffer = (char *)SFAlloc(sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize);
+       if (buffer) {
+               memcpy(buffer,mpqOpenArc->lpHashTable,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize);
+               EncryptData((LPBYTE)buffer,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,dwHashTableKey);
+               SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->MpqHeader.dwHashTableOffset,0,FILE_BEGIN);
+               WriteFile(mpqOpenArc->hFile,buffer,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,&tsz,0);
+               SFFree(buffer);
+       }
+       else {
+               EncryptData((LPBYTE)mpqOpenArc->lpHashTable,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,dwHashTableKey);
+               SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->MpqHeader.dwHashTableOffset,0,FILE_BEGIN);
+               WriteFile(mpqOpenArc->hFile,mpqOpenArc->lpHashTable,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,&tsz,0);
+               DecryptData((LPBYTE)mpqOpenArc->lpHashTable,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,dwHashTableKey);
+       }
+       buffer = (char *)SFAlloc(sizeof(BLOCKTABLEENTRY) * mpqOpenArc->MpqHeader.dwBlockTableSize);
+       if (buffer) {
+               memcpy(buffer,mpqOpenArc->lpBlockTable,sizeof(BLOCKTABLEENTRY) * mpqOpenArc->MpqHeader.dwBlockTableSize);
+               EncryptData((LPBYTE)buffer,sizeof(BLOCKTABLEENTRY) * mpqOpenArc->MpqHeader.dwBlockTableSize,dwBlockTableKey);
+               SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->MpqHeader.dwBlockTableOffset,0,FILE_BEGIN);
+               WriteFile(mpqOpenArc->hFile,buffer,sizeof(BLOCKTABLEENTRY) * mpqOpenArc->MpqHeader.dwBlockTableSize,&tsz,0);
+               SFFree(buffer);
+       }
+       else {
+               EncryptData((LPBYTE)mpqOpenArc->lpBlockTable,sizeof(BLOCKTABLEENTRY) * mpqOpenArc->MpqHeader.dwBlockTableSize,dwBlockTableKey);
+               SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->MpqHeader.dwBlockTableOffset,0,FILE_BEGIN);
+               WriteFile(mpqOpenArc->hFile,mpqOpenArc->lpBlockTable,sizeof(BLOCKTABLEENTRY) * mpqOpenArc->MpqHeader.dwBlockTableSize,&tsz,0);
+               DecryptData((LPBYTE)mpqOpenArc->lpBlockTable,sizeof(BLOCKTABLEENTRY) * mpqOpenArc->MpqHeader.dwBlockTableSize,dwBlockTableKey);
+       }
+       AddToInternalListing(hMPQ,lpDestFileName);
+
+       return TRUE;
+}
+
+BOOL SFMPQAPI WINAPI MpqAddFileToArchive(MPQHANDLE hMPQ, LPCSTR lpSourceFileName, LPCSTR lpDestFileName, DWORD dwFlags)
+{
+       return MpqAddFileToArchiveEx(hMPQ,lpSourceFileName,lpDestFileName,dwFlags,0x08,0);
+}
+
+BOOL SFMPQAPI WINAPI MpqAddWaveToArchive(MPQHANDLE hMPQ, LPCSTR lpSourceFileName, LPCSTR lpDestFileName, DWORD dwFlags, DWORD dwQuality)
+{
+       return MpqAddFileToArchiveEx(hMPQ,lpSourceFileName,lpDestFileName,dwFlags,0x81,dwQuality);
+}
+
+BOOL SFMPQAPI WINAPI MpqAddFileFromBufferEx(MPQHANDLE hMPQ, LPVOID lpBuffer, DWORD dwLength, LPCSTR lpFileName, DWORD dwFlags, DWORD dwCompressionType, DWORD dwCompressLevel)
+{
+       if (!hMPQ || !lpBuffer || !lpFileName) {
+               SetLastError(ERROR_INVALID_PARAMETER);
+               return FALSE;
+       }
+       if (!*lpFileName) {
+               SetLastError(ERROR_INVALID_PARAMETER);
+               return FALSE;
+       }
+
+       if (!(((MPQARCHIVE *)hMPQ)->dwFlags&SFILE_OPEN_ALLOW_WRITE)) {
+               SetLastError(ERROR_ACCESS_DENIED);
+               return FALSE;
+       }
+       BOOL ReplaceExisting;
+       if (dwFlags&MAFA_REPLACE_EXISTING) {
+               dwFlags = dwFlags^MAFA_REPLACE_EXISTING;
+               ReplaceExisting = TRUE;
+
+       }
+       else ReplaceExisting = FALSE;
+       MPQHANDLE hFile = GetFreeHashTableEntry(hMPQ,lpFileName,LocaleID,ReplaceExisting);
+       if (hFile==0) return FALSE;
+       DWORD fsz = dwLength,tsz;
+       DWORD ucfsz = fsz;
+       BOOL IsBNcache = FALSE;char *buffer,*hbuffer;
+       MPQARCHIVE *mpqOpenArc = (MPQARCHIVE *)hMPQ;
+       DWORD blockSize = 512 << mpqOpenArc->MpqHeader.wBlockSize;
+       DWORD TotalBlocks = fsz / blockSize;
+       if(fsz % blockSize)
+               TotalBlocks++;
+       DWORD ptsz = 0;
+       if (dwFlags&MAFA_COMPRESS || dwFlags&MAFA_COMPRESS2) ptsz = (TotalBlocks+1)*4;
+       if (memcmp(&mpqOpenArc->MpqHeader.dwMPQID,ID_BN3,4)==0)
+       {
+               IsBNcache = TRUE;
+               hbuffer = (char *)SFAlloc(fsz+324+ptsz);
+               if (hbuffer==0) {
+                       return FALSE;
+               }
+               hbuffer[0] = (char)0x44;
+               hbuffer[1] = (char)0x01;
+               DWORD lpFileNameLength = strlen(lpFileName);
+               if (lpFileNameLength<=260) memcpy(hbuffer+64,lpFileName,lpFileNameLength);
+               else strncpy(hbuffer+64,lpFileName,260);
+               buffer = hbuffer+324;
+       }
+       else buffer = (char *)SFAlloc(fsz+ptsz);
+       if (buffer==0 && fsz!=0) {
+               return FALSE;
+       }
+       if (fsz!=0) memcpy(buffer,lpBuffer,fsz);
+       else {
+               if (dwFlags&MAFA_COMPRESS) dwFlags = dwFlags^MAFA_COMPRESS;
+               if (dwFlags&MAFA_COMPRESS2) dwFlags = dwFlags^MAFA_COMPRESS2;
+               if (dwFlags&MAFA_ENCRYPT) dwFlags = dwFlags^MAFA_ENCRYPT;
+               if (dwFlags&MAFA_MODCRYPTKEY) dwFlags = dwFlags^MAFA_MODCRYPTKEY;
+       }
+       DWORD i;
+       DWORD *dwBlkpt = (DWORD *)SFAlloc((TotalBlocks+1)*4);
+
+       if (dwBlkpt==0) {
+               SFFree(buffer);
+               return FALSE;
+       }
+       if ((dwFlags & MAFA_COMPRESS)==MAFA_COMPRESS || (dwFlags & MAFA_COMPRESS2)==MAFA_COMPRESS2)
+       {
+               DWORD dwCompressionSubType = 0;
+
+               if ((dwCompressionType&0x40 || dwCompressionType&0x80) && (memcmp(buffer,ID_RIFF,4)!=0 || memcmp(buffer+8,ID_WAVE,8)!=0 || buffer[20]!=1 || buffer[34]!=16)) {
+                       dwCompressionType = 0x08;
+                       dwCompressLevel = 0;
+               }
+               if (dwCompressionType&0x40 || dwCompressionType&0x80) {
+                       switch (dwCompressLevel) {
+                               case MAWA_QUALITY_HIGH:
+                                       dwCompressLevel = 1;
+                                       break;
+                               case MAWA_QUALITY_LOW:
+                                       dwCompressLevel = 3;
+                                       break;
+                               default:
+                                       dwCompressLevel = 0;
+                       }
+               }
+               else if (dwCompressionType&0x01 || dwCompressionType&0x08 || ((dwFlags & MAFA_COMPRESS)!=MAFA_COMPRESS && (dwFlags & MAFA_COMPRESS2)==MAFA_COMPRESS2)) {
+                       dwCompressionSubType = dwCompressLevel;
+                       dwCompressLevel = 0;
+               }
+               else if (dwCompressionType&0x02) {
+                       dwCompressionSubType = 1;
+               }
+
+               DWORD LastOffset=ptsz;
+               BYTE *compbuffer = (BYTE *)SFAlloc(blockSize);
+               if (compbuffer==0) {
+                       SFFree(dwBlkpt);
+                       SFFree(buffer);
+                       return FALSE;
+               }
+
+               char *outbuffer = (char *)SFAlloc(blockSize);
+               if (outbuffer==0) {
+                       SFFree(compbuffer);
+                       SFFree(dwBlkpt);
+                       SFFree(buffer);
+                       return FALSE;
+               }
+               char *newbuffer = (char *)SFAlloc(fsz+ptsz);
+               if (newbuffer==0) {
+                       SFFree(outbuffer);
+                       SFFree(compbuffer);
+                       SFFree(dwBlkpt);
+                       SFFree(buffer);
+                       return FALSE;
+               }
+               DWORD CurPos=0;
+               for (i=0;i<TotalBlocks;i++) {
+                       dwBlkpt[i] = LastOffset;
+                       if (i==TotalBlocks-1 && (ucfsz % blockSize)!=0) blockSize=ucfsz % blockSize;
+                       DWORD outLength=blockSize;
+                       BYTE *compdata = compbuffer;
+                       if (dwFlags & MAFA_COMPRESS)
+                       {
+                               memcpy(compdata,(char *)buffer+CurPos,blockSize);
+                               if (i==0 && (dwCompressionType&0x40 || dwCompressionType&0x80)) {
+                                       if (SCompCompress(outbuffer, &outLength, compdata, blockSize, 0x08, 0, 0)==0)
+                                               outLength=blockSize;
+                               }
+                               else
+                               {
+                                       if (dwCompressionType&UNSUPPORTED_COMPRESSION) {
+                                               LoadStorm();
+                                               if (stormSCompCompress!=0) {
+                                                       if (stormSCompCompress(outbuffer, &outLength, compdata, blockSize, dwCompressionType, dwCompressionSubType, dwCompressLevel)==0)
+                                                               outLength=blockSize;
+                                               }
+                                       }
+                                       else {
+                                               if (SCompCompress(outbuffer, &outLength, compdata, blockSize, dwCompressionType, dwCompressionSubType, dwCompressLevel)==0)
+                                                       outLength=blockSize;
+                                       }
+                               }
+                       }
+                       else if (dwFlags & MAFA_COMPRESS2)
+                       {
+                               memcpy(compdata,(char *)buffer+CurPos,blockSize);
+                               if (SCompCompress(outbuffer, &outLength, compdata, blockSize, 0x08, dwCompressionSubType, 0)==0) {
+                                       outLength=blockSize;
+                               }
+                               else {
+                                       outbuffer++;
+                                       outLength--;
+                               }
+                       }
+                       else
+                       {
+                               memcpy(compdata,(char *)buffer+CurPos,blockSize);
+                       }
+                       if (outLength>=blockSize)
+                       {
+                               memcpy((char *)newbuffer+LastOffset,compdata,blockSize);
+                               LastOffset+=blockSize;
+                       }
+                       else {
+                               memcpy((char *)newbuffer+LastOffset,outbuffer,outLength);
+                               LastOffset+=outLength;
+                       }
+                       CurPos += blockSize;
+               }
+               fsz = LastOffset;
+               dwBlkpt[TotalBlocks] = fsz;
+               memcpy(newbuffer,dwBlkpt,ptsz);
+               SFFree(outbuffer);
+               SFFree(compbuffer);
+               memcpy(buffer,newbuffer,fsz);
+               SFFree(newbuffer);
+       }
+       else
+       {
+               for (i=0;i<TotalBlocks+1;i++) {
+                       if (i<TotalBlocks) dwBlkpt[i] = i * blockSize;
+                       else dwBlkpt[i] = ucfsz;
+               }
+       }
+       if (IsBNcache==TRUE)
+       {
+               buffer = hbuffer;
+               fsz += 324;
+       }
+       HASHTABLEENTRY *hashEntry = (HASHTABLEENTRY *)hFile;
+
+       BOOL IsNewBlockEntry = FALSE;DWORD OldBlockTableSize = sizeof(BLOCKTABLEENTRY) * mpqOpenArc->MpqHeader.dwBlockTableSize;
+       if ((hashEntry->dwBlockTableIndex&0xFFFFFFFE)==0xFFFFFFFE)
+       {
+               BLOCKTABLEENTRY *lpnBlockTable;
+               lpnBlockTable = (BLOCKTABLEENTRY *)SFAlloc(sizeof(BLOCKTABLEENTRY) * (mpqOpenArc->MpqHeader.dwBlockTableSize + 1));
+               if(lpnBlockTable==0) {
+                       SFFree(buffer);
+                       return FALSE;
+               }
+               if (mpqOpenArc->lpBlockTable!=0) memcpy(lpnBlockTable,mpqOpenArc->lpBlockTable,sizeof(BLOCKTABLEENTRY) * mpqOpenArc->MpqHeader.dwBlockTableSize);
+               mpqOpenArc->MpqHeader.dwBlockTableSize++;
+               if (mpqOpenArc->lpBlockTable!=0) SFFree(mpqOpenArc->lpBlockTable);
+               mpqOpenArc->lpBlockTable = lpnBlockTable;
+               IsNewBlockEntry = TRUE;
+       }
+       DWORD BlockIndex = mpqOpenArc->MpqHeader.dwBlockTableSize - 1;
+       if ((hashEntry->dwBlockTableIndex&0xFFFFFFFE)==0xFFFFFFFE)
+       {
+               hashEntry->dwNameHashA = HashString(lpFileName,HASH_NAME_A);
+               hashEntry->dwNameHashB = HashString(lpFileName,HASH_NAME_B);
+               hashEntry->lcLocale = LocaleID;
+               hashEntry->dwBlockTableIndex = BlockIndex;
+               mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset = 0;
+       }
+       else
+       {
+               BlockIndex = hashEntry->dwBlockTableIndex;
+       }
+       if (mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset==0 || mpqOpenArc->lpBlockTable[BlockIndex].dwCompressedSize<fsz)
+       {
+               if (mpqOpenArc->MpqHeader.dwHashTableOffset+(mpqOpenArc->MpqHeader.dwHashTableSize * sizeof(HASHTABLEENTRY))+OldBlockTableSize==mpqOpenArc->MpqHeader.dwMPQSize)
+               {
+                       if (mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset+mpqOpenArc->lpBlockTable[BlockIndex].dwCompressedSize==mpqOpenArc->MpqHeader.dwHashTableOffset)
+                       {
+                               mpqOpenArc->MpqHeader.dwHashTableOffset += fsz-mpqOpenArc->lpBlockTable[BlockIndex].dwCompressedSize;
+                               mpqOpenArc->MpqHeader.dwBlockTableOffset += fsz-mpqOpenArc->lpBlockTable[BlockIndex].dwCompressedSize;
+                               mpqOpenArc->MpqHeader.dwMPQSize += fsz-mpqOpenArc->lpBlockTable[BlockIndex].dwCompressedSize;
+                               if (IsNewBlockEntry==TRUE) mpqOpenArc->MpqHeader.dwMPQSize += sizeof(BLOCKTABLEENTRY);
+                       }
+                       else
+                       {
+                               mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset = mpqOpenArc->MpqHeader.dwHashTableOffset;
+                               mpqOpenArc->MpqHeader.dwHashTableOffset += fsz;
+                               mpqOpenArc->MpqHeader.dwBlockTableOffset += fsz;
+                               mpqOpenArc->MpqHeader.dwMPQSize += fsz;
+                               if (IsNewBlockEntry==TRUE) mpqOpenArc->MpqHeader.dwMPQSize += sizeof(BLOCKTABLEENTRY);
+                       }
+               }
+               else if (mpqOpenArc->MpqHeader.dwBlockTableOffset+OldBlockTableSize==mpqOpenArc->MpqHeader.dwMPQSize)
+               {
+                       if (mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset+mpqOpenArc->lpBlockTable[BlockIndex].dwCompressedSize==mpqOpenArc->MpqHeader.dwBlockTableOffset)
+                       {
+                               mpqOpenArc->MpqHeader.dwBlockTableOffset += fsz-mpqOpenArc->lpBlockTable[BlockIndex].dwCompressedSize;
+                               mpqOpenArc->MpqHeader.dwMPQSize += fsz-mpqOpenArc->lpBlockTable[BlockIndex].dwCompressedSize;
+                               if (IsNewBlockEntry==TRUE) mpqOpenArc->MpqHeader.dwMPQSize += sizeof(BLOCKTABLEENTRY);
+                       }
+                       else
+                       {
+                               mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset = mpqOpenArc->MpqHeader.dwBlockTableOffset;
+                               mpqOpenArc->MpqHeader.dwBlockTableOffset += fsz;
+                               mpqOpenArc->MpqHeader.dwMPQSize += fsz;
+                               if (IsNewBlockEntry==TRUE) mpqOpenArc->MpqHeader.dwMPQSize += sizeof(BLOCKTABLEENTRY);
+                       }
+               }
+               else
+               {
+                       if (mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset+mpqOpenArc->lpBlockTable[BlockIndex].dwCompressedSize==mpqOpenArc->MpqHeader.dwMPQSize)
+                       {
+                               mpqOpenArc->MpqHeader.dwBlockTableOffset = mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset+fsz;
+                               mpqOpenArc->MpqHeader.dwMPQSize = mpqOpenArc->MpqHeader.dwBlockTableOffset+OldBlockTableSize;
+                               if (IsNewBlockEntry==TRUE) mpqOpenArc->MpqHeader.dwMPQSize += sizeof(BLOCKTABLEENTRY);
+                       }
+                       else
+                       {
+                               mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset = mpqOpenArc->MpqHeader.dwMPQSize;
+                               mpqOpenArc->MpqHeader.dwBlockTableOffset = mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset+fsz;
+                               mpqOpenArc->MpqHeader.dwMPQSize = mpqOpenArc->MpqHeader.dwBlockTableOffset+OldBlockTableSize;
+                               if (IsNewBlockEntry==TRUE) mpqOpenArc->MpqHeader.dwMPQSize += sizeof(BLOCKTABLEENTRY);
+                       }
+               }
+       }
+       mpqOpenArc->lpBlockTable[BlockIndex].dwCompressedSize = fsz;
+       mpqOpenArc->lpBlockTable[BlockIndex].dwFullSize = ucfsz;
+       mpqOpenArc->lpBlockTable[BlockIndex].dwFlags = dwFlags|MAFA_EXISTS;
+       DWORD dwFileOffset = mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset;
+       SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart,0,FILE_BEGIN);
+       WriteFile(mpqOpenArc->hFile,&mpqOpenArc->MpqHeader,mpqOpenArc->MpqHeader.dwHeaderSize,&tsz,0);
+       if (dwFlags & MAFA_ENCRYPT) {
+               DWORD dwCryptKey;
+               if (dwFlags&MAFA_ENCRYPT) dwCryptKey = HashString(lpFileName,HASH_KEY);
+               if (dwFlags&MAFA_MODCRYPTKEY) dwCryptKey = (dwCryptKey + mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset) ^ mpqOpenArc->lpBlockTable[BlockIndex].dwFullSize;
+               DWORD blockSize = 512 << mpqOpenArc->MpqHeader.wBlockSize;
+               DWORD TotalBlocks = mpqOpenArc->lpBlockTable[BlockIndex].dwFullSize / blockSize;
+
+               if(mpqOpenArc->lpBlockTable[BlockIndex].dwFullSize % blockSize)
+                       TotalBlocks++;
+               DWORD dwBlockEnd = mpqOpenArc->lpBlockTable[BlockIndex].dwFullSize % blockSize;
+               if (dwBlockEnd==0) dwBlockEnd = blockSize;
+               if ((dwFlags & MAFA_COMPRESS)==MAFA_COMPRESS || (dwFlags & MAFA_COMPRESS2)==MAFA_COMPRESS2) {
+                       EncryptData((LPBYTE)buffer,ptsz,dwCryptKey-1);
+               }
+               for (DWORD i=0;i<TotalBlocks;i++) {
+                       EncryptData((LPBYTE)buffer+dwBlkpt[i],dwBlkpt[i+1]-dwBlkpt[i],dwCryptKey);
+                       dwCryptKey++;
+               }
+       }
+       SFFree(dwBlkpt);
+       SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+dwFileOffset,0,FILE_BEGIN);
+       WriteFile(mpqOpenArc->hFile,buffer,fsz,&tsz,0);
+       SFFree(buffer);
+       buffer = (char *)SFAlloc(sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize);
+       if (buffer!=0) {
+               memcpy(buffer,mpqOpenArc->lpHashTable,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize);
+               EncryptData((LPBYTE)buffer,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,dwHashTableKey);
+               SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->MpqHeader.dwHashTableOffset,0,FILE_BEGIN);
+               WriteFile(mpqOpenArc->hFile,buffer,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,&tsz,0);
+               SFFree(buffer);
+       }
+       else {
+               EncryptData((LPBYTE)mpqOpenArc->lpHashTable,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,dwHashTableKey);
+               SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->MpqHeader.dwHashTableOffset,0,FILE_BEGIN);
+               WriteFile(mpqOpenArc->hFile,mpqOpenArc->lpHashTable,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,&tsz,0);
+               DecryptData((LPBYTE)mpqOpenArc->lpHashTable,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,dwHashTableKey);
+       }
+       buffer = (char *)SFAlloc(sizeof(BLOCKTABLEENTRY) * mpqOpenArc->MpqHeader.dwBlockTableSize);
+       if (buffer!=0) {
+               memcpy(buffer,mpqOpenArc->lpBlockTable,sizeof(BLOCKTABLEENTRY) * mpqOpenArc->MpqHeader.dwBlockTableSize);
+               EncryptData((LPBYTE)buffer,sizeof(BLOCKTABLEENTRY) * mpqOpenArc->MpqHeader.dwBlockTableSize,dwBlockTableKey);
+               SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->MpqHeader.dwBlockTableOffset,0,FILE_BEGIN);
+               WriteFile(mpqOpenArc->hFile,buffer,sizeof(BLOCKTABLEENTRY) * mpqOpenArc->MpqHeader.dwBlockTableSize,&tsz,0);
+               SFFree(buffer);
+       }
+       else {
+               EncryptData((LPBYTE)mpqOpenArc->lpBlockTable,sizeof(BLOCKTABLEENTRY) * mpqOpenArc->MpqHeader.dwBlockTableSize,dwBlockTableKey);
+               SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->MpqHeader.dwBlockTableOffset,0,FILE_BEGIN);
+               WriteFile(mpqOpenArc->hFile,mpqOpenArc->lpBlockTable,sizeof(BLOCKTABLEENTRY) * mpqOpenArc->MpqHeader.dwBlockTableSize,&tsz,0);
+               DecryptData((LPBYTE)mpqOpenArc->lpBlockTable,sizeof(BLOCKTABLEENTRY) * mpqOpenArc->MpqHeader.dwBlockTableSize,dwBlockTableKey);
+       }
+       AddToInternalListing(hMPQ,lpFileName);
+       return TRUE;
+}
+
+BOOL SFMPQAPI WINAPI MpqAddFileFromBuffer(MPQHANDLE hMPQ, LPVOID lpBuffer, DWORD dwLength, LPCSTR lpFileName, DWORD dwFlags)
+{
+       return MpqAddFileFromBufferEx(hMPQ,lpBuffer,dwLength,lpFileName,dwFlags,0x08,0);
+}
+
+BOOL SFMPQAPI WINAPI MpqAddWaveFromBuffer(MPQHANDLE hMPQ, LPVOID lpBuffer, DWORD dwLength, LPCSTR lpFileName, DWORD dwFlags, DWORD dwQuality)
+{
+       return MpqAddFileFromBufferEx(hMPQ,lpBuffer,dwLength,lpFileName,dwFlags,0x81,dwQuality);
+}
+
+BOOL SFMPQAPI WINAPI MpqRenameFile(MPQHANDLE hMPQ, LPCSTR lpcOldFileName, LPCSTR lpcNewFileName)
+{
+       return MpqRenameAndSetFileLocale(hMPQ,lpcOldFileName,lpcNewFileName,LocaleID,LocaleID);
+}
+
+BOOL SFMPQAPI WINAPI MpqRenameAndSetFileLocale(MPQHANDLE hMPQ, LPCSTR lpcOldFileName, LPCSTR lpcNewFileName, LCID nOldLocale, LCID nNewLocale)
+{
+       if (!hMPQ || !lpcOldFileName || !lpcNewFileName) {
+               SetLastError(ERROR_INVALID_PARAMETER);
+               return FALSE;
+       }
+       if (!*lpcNewFileName) {
+               SetLastError(ERROR_INVALID_PARAMETER);
+               return FALSE;
+       }
+
+       if (!(((MPQARCHIVE *)hMPQ)->dwFlags&SFILE_OPEN_ALLOW_WRITE)) {
+               SetLastError(ERROR_ACCESS_DENIED);
+               return FALSE;
+       }
+       if (stricmp(lpcOldFileName,lpcNewFileName)==0) {
+               SetLastError(ERROR_INVALID_PARAMETER);
+               return FALSE;
+       }
+       MPQARCHIVE *mpqOpenArc = (MPQARCHIVE *)hMPQ;
+       HASHTABLEENTRY *oldHashEntry = (HASHTABLEENTRY *)GetHashTableEntry(hMPQ,lpcOldFileName,nOldLocale);
+       if (oldHashEntry==0) {
+               SetLastError(MPQ_ERROR_FILE_NOT_FOUND);
+               return FALSE;
+       }
+       if (oldHashEntry->lcLocale!=nOldLocale) {
+               SetLastError(MPQ_ERROR_FILE_NOT_FOUND);
+               return FALSE;
+       }
+       HASHTABLEENTRY *newHashEntry = (HASHTABLEENTRY *)GetFreeHashTableEntry(hMPQ,lpcNewFileName,nNewLocale,TRUE);
+       if ((newHashEntry->dwBlockTableIndex&0xFFFFFFFE)!=0xFFFFFFFE)
+               return FALSE;
+       if (newHashEntry==0) newHashEntry = oldHashEntry;
+       DWORD tsz;
+       newHashEntry->dwNameHashA = HashString(lpcNewFileName,HASH_NAME_A);
+       newHashEntry->dwNameHashB = HashString(lpcNewFileName,HASH_NAME_B);
+       newHashEntry->lcLocale = nNewLocale;
+       newHashEntry->dwBlockTableIndex = oldHashEntry->dwBlockTableIndex;
+       DWORD BlockIndex = oldHashEntry->dwBlockTableIndex;
+       if (mpqOpenArc->lpBlockTable[BlockIndex].dwFlags & MAFA_ENCRYPT)
+       {
+               DWORD dwOldCryptKey = HashString(lpcOldFileName,HASH_KEY);
+               DWORD dwNewCryptKey = HashString(lpcNewFileName,HASH_KEY);
+               if (mpqOpenArc->lpBlockTable[BlockIndex].dwFlags & MAFA_MODCRYPTKEY) {
+                       dwOldCryptKey = (dwOldCryptKey + mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset) ^ mpqOpenArc->lpBlockTable[BlockIndex].dwFullSize;
+
+                       dwNewCryptKey = (dwNewCryptKey + mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset) ^ mpqOpenArc->lpBlockTable[BlockIndex].dwFullSize;
+               }
+               if (dwOldCryptKey!=dwNewCryptKey)
+               {
+                       DWORD HeaderLength=0;
+                       if (memcmp(&mpqOpenArc->MpqHeader.dwMPQID,ID_BN3,4)==0)
+                       {
+                               SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset,0,FILE_BEGIN);
+                               ReadFile(mpqOpenArc->hFile,&HeaderLength,4,&tsz,0);
+
+                       }
+                       DWORD blockSize = 512 << mpqOpenArc->MpqHeader.wBlockSize;
+                       DWORD TotalBlocks = mpqOpenArc->lpBlockTable[BlockIndex].dwFullSize / blockSize;
+                       if(mpqOpenArc->lpBlockTable[BlockIndex].dwFullSize % blockSize)
+                               TotalBlocks++;
+                       DWORD *dwBlockPtrTable = (DWORD *)SFAlloc((TotalBlocks+1)*4);
+                       if (dwBlockPtrTable==0) {
+                               return FALSE;
+                       }
+                       DWORD i;
+                       if ((mpqOpenArc->lpBlockTable[BlockIndex].dwFlags & MAFA_COMPRESS)==MAFA_COMPRESS || (mpqOpenArc->lpBlockTable[BlockIndex].dwFlags & MAFA_COMPRESS2)==MAFA_COMPRESS2)
+                       {
+                               SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset+HeaderLength,0,FILE_BEGIN);
+                               ReadFile(mpqOpenArc->hFile,dwBlockPtrTable,(TotalBlocks+1)*4,&tsz,0);
+                               DecryptData((LPBYTE)dwBlockPtrTable,(TotalBlocks+1)*4,dwOldCryptKey-1);
+                               char *EncryptedTable = (char *)SFAlloc((TotalBlocks+1)*4);
+                               if (EncryptedTable==0) {
+                                       SFFree(dwBlockPtrTable);
+                                       return FALSE;
+                               }
+                               memcpy(EncryptedTable,dwBlockPtrTable,(TotalBlocks+1)*4);
+                               EncryptData((LPBYTE)EncryptedTable,(TotalBlocks+1)*4,dwNewCryptKey-1);
+                               SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset+HeaderLength,0,FILE_BEGIN);
+                               WriteFile(mpqOpenArc->hFile,EncryptedTable,(TotalBlocks+1)*4,&tsz,0);
+                               SFFree(EncryptedTable);
+                       }
+                       else
+                       {
+                               for (i=0;i<TotalBlocks+1;i++) {
+                                       if (i<TotalBlocks) dwBlockPtrTable[i] = i * blockSize;
+                                       else dwBlockPtrTable[i] = mpqOpenArc->lpBlockTable[BlockIndex].dwFullSize;
+                               }
+                       }
+                       char *blkBuffer = (char *)SFAlloc(blockSize);
+                       if (blkBuffer==0) {
+                               EncryptData((LPBYTE)dwBlockPtrTable,(TotalBlocks+1)*4,dwOldCryptKey-1);
+                               SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset+HeaderLength,0,FILE_BEGIN);
+                               WriteFile(mpqOpenArc->hFile,dwBlockPtrTable,(TotalBlocks+1)*4,&tsz,0);
+                               SFFree(dwBlockPtrTable);
+                               return FALSE;
+                       }
+                       for (i=0;i<TotalBlocks;i++) {
+                               SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset+HeaderLength+dwBlockPtrTable[i],0,FILE_BEGIN);
+                               if (ReadFile(mpqOpenArc->hFile,blkBuffer,dwBlockPtrTable[i+1]-dwBlockPtrTable[i],&tsz,0)==0) {
+                                       EncryptData((LPBYTE)dwBlockPtrTable,(TotalBlocks+1)*4,dwOldCryptKey-1);
+                                       SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset+HeaderLength,0,FILE_BEGIN);
+                                       WriteFile(mpqOpenArc->hFile,dwBlockPtrTable,(TotalBlocks+1)*4,&tsz,0);
+                                       SFFree(dwBlockPtrTable);
+                                       SFFree(blkBuffer);
+                                       return FALSE;
+                               }
+                               DecryptData((LPBYTE)blkBuffer,dwBlockPtrTable[i+1]-dwBlockPtrTable[i],dwOldCryptKey+i);
+                               EncryptData((LPBYTE)blkBuffer,dwBlockPtrTable[i+1]-dwBlockPtrTable[i],dwNewCryptKey+i);
+                               SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset+HeaderLength+dwBlockPtrTable[i],0,FILE_BEGIN);
+                               WriteFile(mpqOpenArc->hFile,blkBuffer,dwBlockPtrTable[i+1]-dwBlockPtrTable[i],&tsz,0);
+                       }
+                       SFFree(dwBlockPtrTable);
+                       SFFree(blkBuffer);
+               }
+       }
+       if (oldHashEntry!=newHashEntry) {
+               oldHashEntry->dwNameHashA = 0xFFFFFFFF;
+               oldHashEntry->dwNameHashB = 0xFFFFFFFF;
+               oldHashEntry->lcLocale = 0xFFFFFFFF;
+               oldHashEntry->dwBlockTableIndex = 0xFFFFFFFE;
+               char *buffer = (char *)SFAlloc(sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize);
+               if (buffer!=0) {
+                       memcpy(buffer,mpqOpenArc->lpHashTable,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize);
+                       EncryptData((LPBYTE)buffer,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,dwHashTableKey);
+                       SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->MpqHeader.dwHashTableOffset,0,FILE_BEGIN);
+                       WriteFile(mpqOpenArc->hFile,buffer,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,&tsz,0);
+                       SFFree(buffer);
+               }
+               else {
+                       EncryptData((LPBYTE)mpqOpenArc->lpHashTable,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,dwHashTableKey);
+                       SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->MpqHeader.dwHashTableOffset,0,FILE_BEGIN);
+                       WriteFile(mpqOpenArc->hFile,mpqOpenArc->lpHashTable,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,&tsz,0);
+                       DecryptData((LPBYTE)mpqOpenArc->lpHashTable,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,dwHashTableKey);
+               }
+       }
+       LCID dwOldLocale=LocaleID;
+       LocaleID=nOldLocale;
+       RemoveFromInternalListing(hMPQ,lpcOldFileName);
+
+       LocaleID=nNewLocale;
+       AddToInternalListing(hMPQ,lpcNewFileName);
+       LocaleID=dwOldLocale;
+       return TRUE;
+}
+
+BOOL SFMPQAPI WINAPI MpqDeleteFile(MPQHANDLE hMPQ, LPCSTR lpFileName)
+{
+       return MpqDeleteFileWithLocale(hMPQ,lpFileName,LocaleID);
+}
+
+BOOL SFMPQAPI WINAPI MpqDeleteFileWithLocale(MPQHANDLE hMPQ, LPCSTR lpFileName, LCID nLocale)
+{
+       if (!hMPQ || !lpFileName) {
+               SetLastError(ERROR_INVALID_PARAMETER);
+               return FALSE;
+       }
+
+       if (!(((MPQARCHIVE *)hMPQ)->dwFlags&SFILE_OPEN_ALLOW_WRITE)) {
+
+               SetLastError(ERROR_ACCESS_DENIED);
+               return FALSE;
+       }
+       MPQARCHIVE *mpqOpenArc = (MPQARCHIVE *)hMPQ;
+       HASHTABLEENTRY *hashEntry = (HASHTABLEENTRY *)GetHashTableEntry(hMPQ,lpFileName,nLocale);
+       if (hashEntry==0) {
+               SetLastError(MPQ_ERROR_FILE_NOT_FOUND);
+               return FALSE;
+       }
+       if (hashEntry->lcLocale!=nLocale) return FALSE;
+       hashEntry->dwNameHashA = 0xFFFFFFFF;
+       hashEntry->dwNameHashB = 0xFFFFFFFF;
+       hashEntry->lcLocale = 0xFFFFFFFF;
+       hashEntry->dwBlockTableIndex = 0xFFFFFFFE;
+       DWORD tsz;
+       char *buffer = (char *)SFAlloc(sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize);
+       if (buffer!=0) {
+               memcpy(buffer,mpqOpenArc->lpHashTable,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize);
+               EncryptData((LPBYTE)buffer,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,dwHashTableKey);
+               SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->MpqHeader.dwHashTableOffset,0,FILE_BEGIN);
+
+               WriteFile(mpqOpenArc->hFile,buffer,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,&tsz,0);
+               SFFree(buffer);
+       }
+       else {
+               EncryptData((LPBYTE)mpqOpenArc->lpHashTable,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,dwHashTableKey);
+               SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->MpqHeader.dwHashTableOffset,0,FILE_BEGIN);
+               WriteFile(mpqOpenArc->hFile,mpqOpenArc->lpHashTable,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,&tsz,0);
+               DecryptData((LPBYTE)mpqOpenArc->lpHashTable,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,dwHashTableKey);
+       }
+       LCID dwOldLocale=LocaleID;
+       LocaleID=nLocale;
+       RemoveFromInternalListing(hMPQ,lpFileName);
+       LocaleID=dwOldLocale;
+       return TRUE;
+}
+
+BOOL SFMPQAPI WINAPI MpqCompactArchive(MPQHANDLE hMPQ)
+{
+       if (!hMPQ) {
+               SetLastError(ERROR_INVALID_PARAMETER);
+               return FALSE;
+       }
+
+       if (!(((MPQARCHIVE *)hMPQ)->dwFlags&SFILE_OPEN_ALLOW_WRITE)) {
+               SetLastError(ERROR_ACCESS_DENIED);
+               return FALSE;
+       }
+       MPQARCHIVE *mpqOpenArc = (MPQARCHIVE *)hMPQ;
+       TempAlloc NewAlloc;
+       char *lpFileName = (char *)NewAlloc.Alloc(strlen(mpqOpenArc->lpFileName)+13);
+       sprintf(lpFileName,"%s.compact",mpqOpenArc->lpFileName);
+       HANDLE hFile = CreateFile(lpFileName,GENERIC_READ|GENERIC_WRITE,0,0,CREATE_NEW,0,0);
+       DWORD i;
+       if (hFile==INVALID_HANDLE_VALUE) {
+               for (i=0;i<10000;i++) {
+                       sprintf(lpFileName,"%s.compact.%04ld",mpqOpenArc->lpFileName,i);
+
+                       hFile = CreateFile(lpFileName,GENERIC_READ|GENERIC_WRITE,0,0,CREATE_NEW,0,0);
+                       if (hFile!=INVALID_HANDLE_VALUE) break;
+               }
+               if (i==10000) return FALSE;
+       }
+       DWORD dwLastOffset = mpqOpenArc->MpqHeader.dwHeaderSize,tsz;
+       char *buffer = (char *)SFAlloc(65536);
+       if (buffer==0) {
+               CloseHandle(hFile);
+               DeleteFile(lpFileName);
+               return FALSE;
+       }
+       HASHTABLEENTRY *lpHashTable = (HASHTABLEENTRY *)SFAlloc(sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize);
+       if (lpHashTable==0) {
+               SFFree(buffer);
+               CloseHandle(hFile);
+               DeleteFile(lpFileName);
+               return FALSE;
+       }
+       BLOCKTABLEENTRY *lpBlockTable = (BLOCKTABLEENTRY *)SFAlloc(sizeof(BLOCKTABLEENTRY) * mpqOpenArc->MpqHeader.dwBlockTableSize);
+       if(mpqOpenArc->lpBlockTable!=0) {
+               if (lpBlockTable==0) {
+                       SFFree(lpHashTable);
+                       SFFree(buffer);
+                       CloseHandle(hFile);
+                       DeleteFile(lpFileName);
+
+                       return FALSE;
+               }
+       }
+       DWORD j=0,nBlkOffset=0,ReadSize=0;
+       memcpy(lpHashTable,mpqOpenArc->lpHashTable,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize);
+       for (i=0;i<mpqOpenArc->MpqHeader.dwBlockTableSize;i++) {
+               for (j=0;j<mpqOpenArc->MpqHeader.dwHashTableSize;j++) {
+                       if (lpHashTable[j].dwBlockTableIndex==(i-nBlkOffset)) break;
+               }
+               if (j<mpqOpenArc->MpqHeader.dwHashTableSize) {
+                       memcpy(&lpBlockTable[i-nBlkOffset],&mpqOpenArc->lpBlockTable[i],sizeof(BLOCKTABLEENTRY));
+                       lpBlockTable[i-nBlkOffset].dwFileOffset = dwLastOffset;
+                       dwLastOffset += mpqOpenArc->lpBlockTable[i].dwCompressedSize;
+                       DWORD dwWritten=FALSE;
+                       if (mpqOpenArc->lpBlockTable[i].dwFlags&MAFA_ENCRYPT && mpqOpenArc->lpBlockTable[i].dwFlags&MAFA_MODCRYPTKEY && (mpqOpenArc->lpBlockTable[i].dwFlags&MAFA_COMPRESS || mpqOpenArc->lpBlockTable[i].dwFlags&MAFA_COMPRESS2))
+                       {
+                               DWORD HeaderLength=0;
+                               if (memcmp(&mpqOpenArc->MpqHeader.dwMPQID,ID_BN3,4)==0)
+                               {
+                                       SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->lpBlockTable[i].dwFileOffset,0,FILE_BEGIN);
+                                       ReadFile(mpqOpenArc->hFile,&HeaderLength,4,&tsz,0);
+                               }
+                               DWORD blockSize = 512 << mpqOpenArc->MpqHeader.wBlockSize;
+                               DWORD TotalBlocks = mpqOpenArc->lpBlockTable[i].dwFullSize / blockSize;
+                               if(mpqOpenArc->lpBlockTable[i].dwFullSize % blockSize)
+                                       TotalBlocks++;
+                               DWORD *dwBlockPtrTable = (DWORD *)SFAlloc((TotalBlocks+1)*4);
+                               if (dwBlockPtrTable==0) {
+                                       SFFree(lpBlockTable);
+                                       SFFree(lpHashTable);
+                                       SFFree(buffer);
+                                       CloseHandle(hFile);
+                                       DeleteFile(lpFileName);
+                                       return FALSE;
+                               }
+                               SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->lpBlockTable[i].dwFileOffset+HeaderLength,0,FILE_BEGIN);
+                               ReadFile(mpqOpenArc->hFile,dwBlockPtrTable,(TotalBlocks+1)*4,&tsz,0);
+                               DWORD dwOldCryptKey = DetectFileSeed(dwBlockPtrTable,(TotalBlocks+1)*4,blockSize);
+                               DWORD dwNewCryptKey = (dwOldCryptKey ^ mpqOpenArc->lpBlockTable[i].dwFullSize) - mpqOpenArc->lpBlockTable[i].dwFileOffset;
+                               dwNewCryptKey = (dwNewCryptKey + lpBlockTable[i-nBlkOffset].dwFileOffset) ^ lpBlockTable[i-nBlkOffset].dwFullSize;
+                               if (dwOldCryptKey==0) {
+                                       DWORD dwNameHashA = HashString(INTERNAL_LISTFILE,HASH_NAME_A);
+                                       DWORD dwNameHashB = HashString(INTERNAL_LISTFILE,HASH_NAME_B);
+                                       if (lpHashTable[j].dwNameHashA==dwNameHashA && lpHashTable[j].dwNameHashB==dwNameHashB) {
+                                               dwOldCryptKey = HashString(INTERNAL_LISTFILE,HASH_KEY);
+                                               dwNewCryptKey = dwOldCryptKey;
+                                               dwOldCryptKey = (dwOldCryptKey + mpqOpenArc->lpBlockTable[i].dwFileOffset) ^ mpqOpenArc->lpBlockTable[i].dwFullSize;
+                                               dwNewCryptKey = (dwNewCryptKey + lpBlockTable[i-nBlkOffset].dwFileOffset) ^ lpBlockTable[i-nBlkOffset].dwFullSize;
+                                       }
+                                       else {
+                                               HANDLE hlFile;
+                                               DWORD fsz;
+                                               char *listbuffer;
+                                               LCID lcOldLocale = LocaleID;
+                                               for (DWORD lcn=0;lcn<nLocales;lcn++) {
+                                                       LocaleID = availLocales[lcn];
+                                                       if (SFileOpenFileEx(hMPQ,INTERNAL_LISTFILE,0,&hlFile)!=0) {
+                                                               if (((MPQFILE *)hlFile)->lpHashEntry->lcLocale==0 && LocaleID!=0) {
+
+                                                                       SFileCloseFile(hlFile);
+                                                                       continue;
+                                                               }
+                                                               fsz = SFileGetFileSize(hlFile,0);
+                                                               if (fsz>0) {
+                                                                       listbuffer = (char *)SFAlloc(fsz+1);
+                                                                       if (listbuffer==0) {
+                                                                               SFileCloseFile(hlFile);
+                                                                               continue;
+                                                                       }
+                                                                       if (SFileReadFile(hlFile,listbuffer,fsz,0,0)==0) {
+                                                                               SFFree(listbuffer);
+                                                                               listbuffer = 0;
+                                                                       }
+                                                               }
+                                                               SFileCloseFile(hlFile);
+                                                               if (listbuffer!=0) {
+                                                                       char *listline;
+                                                                       for (listline=listbuffer;listline!=0;listline=nextline(listline)) {
+                                                                               if (listline[0]==0) break;
+                                                                               DWORD lnlen=strlnlen(listline);
+                                                                               char prevchar=listline[lnlen];
+                                                                               listline[lnlen]=0;
+                                                                               dwNameHashA = HashString(listline,HASH_NAME_A);
+                                                                               dwNameHashB = HashString(listline,HASH_NAME_B);
+                                                                               if (lpHashTable[j].dwNameHashA==dwNameHashA && lpHashTable[j].dwNameHashB==dwNameHashB) {
+                                                                                       dwOldCryptKey = HashString(listline,HASH_KEY);
+                                                                                       dwNewCryptKey = dwOldCryptKey;
+                                                                                       dwOldCryptKey = (dwOldCryptKey + mpqOpenArc->lpBlockTable[i].dwFileOffset) ^ mpqOpenArc->lpBlockTable[i].dwFullSize;
+                                                                                       dwNewCryptKey = (dwNewCryptKey + lpBlockTable[i-nBlkOffset].dwFileOffset) ^ lpBlockTable[i-nBlkOffset].dwFullSize;
+                                                                                       break;
+                                                                               }
+                                                                               listline[lnlen]=prevchar;
+                                                                       }
+                                                                       if (listline!=0) {
+                                                                               if (listline[0]!=0) {
+                                                                                       SFFree(listbuffer);
+                                                                                       break;
+                                                                               }
+                                                                       }
+                                                                       SFFree(listbuffer);
+                                                               }
+                                                       }
+                                               }
+                                               LocaleID = lcOldLocale;
+                                       }
+                               }
+                               if (dwOldCryptKey!=dwNewCryptKey)
+                               {
+                                       DecryptData((LPBYTE)dwBlockPtrTable,(TotalBlocks+1)*4,dwOldCryptKey-1);
+                                       char *EncryptedTable = (char *)SFAlloc((TotalBlocks+1)*4);
+                                       if (EncryptedTable==0) {
+                                               SFFree(dwBlockPtrTable);
+                                               SFFree(lpBlockTable);
+                                               SFFree(lpHashTable);
+                                               SFFree(buffer);
+                                               CloseHandle(hFile);
+                                               DeleteFile(lpFileName);
+                                               return FALSE;
+                                       }
+                                       memcpy(EncryptedTable,dwBlockPtrTable,(TotalBlocks+1)*4);
+                                       EncryptData((LPBYTE)EncryptedTable,(TotalBlocks+1)*4,dwNewCryptKey-1);
+                                       SetFilePointer(hFile,lpBlockTable[i-nBlkOffset].dwFileOffset+HeaderLength,0,FILE_BEGIN);
+                                       WriteFile(hFile,EncryptedTable,(TotalBlocks+1)*4,&tsz,0);
+                                       SFFree(EncryptedTable);
+                                       char *blkBuffer = (char *)SFAlloc(blockSize);
+                                       if (blkBuffer==0) {
+                                               SFFree(dwBlockPtrTable);
+                                               SFFree(lpBlockTable);
+                                               SFFree(lpHashTable);
+                                               SFFree(buffer);
+                                               CloseHandle(hFile);
+                                               DeleteFile(lpFileName);
+                                               return FALSE;
+                                       }
+                                       for (DWORD k=0;k<TotalBlocks;k++) {
+                                               SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->lpBlockTable[i].dwFileOffset+HeaderLength+dwBlockPtrTable[k],0,FILE_BEGIN);
+                                               if (ReadFile(mpqOpenArc->hFile,blkBuffer,dwBlockPtrTable[k+1]-dwBlockPtrTable[k],&tsz,0)==0) {
+                                                       SFFree(dwBlockPtrTable);
+                                                       SFFree(blkBuffer);
+                                                       SFFree(lpBlockTable);
+                                                       SFFree(lpHashTable);
+                                                       SFFree(buffer);
+                                                       CloseHandle(hFile);
+                                                       DeleteFile(lpFileName);
+                                                       return FALSE;
+                                               }
+                                               DecryptData((LPBYTE)blkBuffer,dwBlockPtrTable[k+1]-dwBlockPtrTable[k],dwOldCryptKey+k);
+                                               EncryptData((LPBYTE)blkBuffer,dwBlockPtrTable[k+1]-dwBlockPtrTable[k],dwNewCryptKey+k);
+                                               SetFilePointer(hFile,lpBlockTable[i-nBlkOffset].dwFileOffset+HeaderLength+dwBlockPtrTable[k],0,FILE_BEGIN);
+                                               WriteFile(hFile,blkBuffer,dwBlockPtrTable[k+1]-dwBlockPtrTable[k],&tsz,0);
+                                       }
+                                       SFFree(blkBuffer);
+                                       dwWritten = TRUE;
+                               }
+                               SFFree(dwBlockPtrTable);
+                       }
+                       else if (mpqOpenArc->lpBlockTable[i].dwFlags&MAFA_ENCRYPT && mpqOpenArc->lpBlockTable[i].dwFlags&MAFA_MODCRYPTKEY)
+                       {
+                               DWORD HeaderLength=0;
+                               if (memcmp(&mpqOpenArc->MpqHeader.dwMPQID,ID_BN3,4)==0)
+
+                               {
+                                       SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->lpBlockTable[i].dwFileOffset,0,FILE_BEGIN);
+                                       ReadFile(mpqOpenArc->hFile,&HeaderLength,4,&tsz,0);
+                               }
+                               DWORD blockSize = 512 << mpqOpenArc->MpqHeader.wBlockSize;
+                               DWORD TotalBlocks = mpqOpenArc->lpBlockTable[i].dwFullSize / blockSize;
+                               if(mpqOpenArc->lpBlockTable[i].dwFullSize % blockSize)
+                                       TotalBlocks++;
+                               DWORD dwNameHashA = HashString(INTERNAL_LISTFILE,HASH_NAME_A);
+                               DWORD dwNameHashB = HashString(INTERNAL_LISTFILE,HASH_NAME_B);
+                               DWORD dwOldCryptKey=0;
+                               DWORD dwNewCryptKey=0;
+                               if (lpHashTable[j].dwNameHashA==dwNameHashA && lpHashTable[j].dwNameHashB==dwNameHashB) {
+                                       dwOldCryptKey = HashString(INTERNAL_LISTFILE,HASH_KEY);
+                                       dwNewCryptKey = dwOldCryptKey;
+                                       dwOldCryptKey = (dwOldCryptKey + mpqOpenArc->lpBlockTable[i].dwFileOffset) ^ mpqOpenArc->lpBlockTable[i].dwFullSize;
+                                       dwNewCryptKey = (dwNewCryptKey + lpBlockTable[i-nBlkOffset].dwFileOffset) ^ lpBlockTable[i-nBlkOffset].dwFullSize;
+                               }
+                               else {
+                                       HANDLE hlFile;
+                                       DWORD fsz;
+
+                                       char *listbuffer;
+                                       LCID lcOldLocale = LocaleID;
+                                       for (DWORD lcn=0;lcn<nLocales;lcn++) {
+                                               LocaleID = availLocales[lcn];
+                                               if (SFileOpenFileEx(hMPQ,INTERNAL_LISTFILE,0,&hlFile)!=0) {
+                                                       if (((MPQFILE *)hlFile)->lpHashEntry->lcLocale==0 && LocaleID!=0) {
+                                                               SFileCloseFile(hlFile);
+                                                               continue;
+                                                       }
+                                                       fsz = SFileGetFileSize(hlFile,0);
+                                                       if (fsz>0) {
+                                                               listbuffer = (char *)SFAlloc(fsz+1);
+                                                               if (listbuffer==0) {
+                                                                       SFileCloseFile(hlFile);
+                                                                       continue;
+                                                               }
+                                                               if (SFileReadFile(hlFile,listbuffer,fsz,0,0)==0) {
+                                                                       SFFree(listbuffer);
+                                                                       listbuffer = 0;
+                                                               }
+                                                       }
+                                                       SFileCloseFile(hlFile);
+                                                       if (listbuffer!=0) {
+                                                               char *listline;
+                                                               for (listline=listbuffer;listline!=0;listline=nextline(listline)) {
+                                                                       if (listline[0]==0) break;
+                                                                       DWORD lnlen=strlnlen(listline);
+                                                                       char prevchar=listline[lnlen];
+                                                                       listline[lnlen]=0;
+                                                                       dwNameHashA = HashString(listline,HASH_NAME_A);
+                                                                       dwNameHashB = HashString(listline,HASH_NAME_B);
+                                                                       if (lpHashTable[j].dwNameHashA==dwNameHashA && lpHashTable[j].dwNameHashB==dwNameHashB) {
+                                                                               dwOldCryptKey = HashString(listline,HASH_KEY);
+                                                                               dwNewCryptKey = dwOldCryptKey;
+                                                                               dwOldCryptKey = (dwOldCryptKey + mpqOpenArc->lpBlockTable[i].dwFileOffset) ^ mpqOpenArc->lpBlockTable[i].dwFullSize;
+                                                                               dwNewCryptKey = (dwNewCryptKey + lpBlockTable[i-nBlkOffset].dwFileOffset) ^ lpBlockTable[i-nBlkOffset].dwFullSize;
+                                                                               break;
+                                                                       }
+                                                                       listline[lnlen]=prevchar;
+                                                               }
+                                                               if (listline!=0) {
+                                                                       if (listline[0]!=0) {
+                                                                               SFFree(listbuffer);
+                                                                               break;
+                                                                       }
+                                                               }
+                                                               SFFree(listbuffer);
+                                                       }
+                                               }
+                                       }
+                                       LocaleID = lcOldLocale;
+                               }
+                               if (dwOldCryptKey!=dwNewCryptKey)
+                               {
+                                       char *blkBuffer = (char *)SFAlloc(blockSize);
+                                       if (blkBuffer==0) {
+                                               SFFree(lpBlockTable);
+                                               SFFree(lpHashTable);
+                                               SFFree(buffer);
+                                               CloseHandle(hFile);
+                                               DeleteFile(lpFileName);
+                                               return FALSE;
+                                       }
+                                       for (DWORD k=0;k<mpqOpenArc->lpBlockTable[i].dwFullSize;k+=blockSize) {
+                                               SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->lpBlockTable[i].dwFileOffset+HeaderLength+k,0,FILE_BEGIN);
+                                               if (k+blockSize>mpqOpenArc->lpBlockTable[i].dwFullSize) blockSize = mpqOpenArc->lpBlockTable[i].dwFullSize % blockSize;
+                                               if (ReadFile(mpqOpenArc->hFile,blkBuffer,blockSize,&tsz,0)==0) {
+                                                       SFFree(blkBuffer);
+                                                       SFFree(lpBlockTable);
+                                                       SFFree(lpHashTable);
+                                                       SFFree(buffer);
+                                                       CloseHandle(hFile);
+                                                       DeleteFile(lpFileName);
+                                                       return FALSE;
+
+                                               }
+                                               DecryptData((LPBYTE)blkBuffer,blockSize,dwOldCryptKey+k);
+                                               EncryptData((LPBYTE)blkBuffer,blockSize,dwNewCryptKey+k);
+                                               SetFilePointer(hFile,lpBlockTable[i-nBlkOffset].dwFileOffset+HeaderLength+k,0,FILE_BEGIN);
+                                               WriteFile(hFile,blkBuffer,blockSize,&tsz,0);
+                                       }
+                                       SFFree(blkBuffer);
+                                       dwWritten = TRUE;
+                               }
+                       }
+                       if (dwWritten==FALSE) {
+                               ReadSize = 65536;
+                               for (j=0;j<mpqOpenArc->lpBlockTable[i].dwCompressedSize;j+=65536) {
+                                       SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->lpBlockTable[i].dwFileOffset+j,0,FILE_BEGIN);
+                                       SetFilePointer(hFile,lpBlockTable[i-nBlkOffset].dwFileOffset+j,0,FILE_BEGIN);
+                                       if (j+65536>mpqOpenArc->lpBlockTable[i].dwCompressedSize) ReadSize = mpqOpenArc->lpBlockTable[i].dwCompressedSize-j;
+                                       if (ReadFile(mpqOpenArc->hFile,buffer,ReadSize,&tsz,0)==0) {
+                                               SFFree(lpBlockTable);
+                                               SFFree(lpHashTable);
+                                               SFFree(buffer);
+                                               CloseHandle(hFile);
+                                               DeleteFile(lpFileName);
+                                               return FALSE;
+                                       }
+                                       if (WriteFile(hFile,buffer,ReadSize,&tsz,0)==0) {
+                                               SFFree(lpBlockTable);
+                                               SFFree(lpHashTable);
+                                               SFFree(buffer);
+                                               CloseHandle(hFile);
+                                               DeleteFile(lpFileName);
+                                               return FALSE;
+                                       }
+                               }
+                       }
+               }
+               else {
+                       for (j=0;j<mpqOpenArc->MpqHeader.dwHashTableSize;j++) {
+                               if ((lpHashTable[j].dwBlockTableIndex&0xFFFFFFFE)!=0xFFFFFFFE)
+                                       if (lpHashTable[j].dwBlockTableIndex>(i-nBlkOffset)) lpHashTable[j].dwBlockTableIndex--;
+                       }
+                       nBlkOffset++;
+               }
+       }
+       mpqOpenArc->MpqHeader.dwBlockTableSize -= nBlkOffset;
+       mpqOpenArc->MpqHeader.dwHashTableOffset = dwLastOffset;
+       dwLastOffset += mpqOpenArc->MpqHeader.dwHashTableSize * sizeof(HASHTABLEENTRY);
+       mpqOpenArc->MpqHeader.dwBlockTableOffset = dwLastOffset;
+       dwLastOffset += mpqOpenArc->MpqHeader.dwBlockTableSize * sizeof(BLOCKTABLEENTRY);
+       mpqOpenArc->MpqHeader.dwMPQSize = dwLastOffset;
+       SFFree(mpqOpenArc->lpHashTable);
+       mpqOpenArc->lpHashTable = lpHashTable;
+       if(mpqOpenArc->lpBlockTable!=0) {
+               SFFree(mpqOpenArc->lpBlockTable);
+               mpqOpenArc->lpBlockTable = (BLOCKTABLEENTRY *)SFAlloc(mpqOpenArc->MpqHeader.dwBlockTableSize * sizeof(BLOCKTABLEENTRY));
+               if (mpqOpenArc->lpBlockTable==0) {
+                       mpqOpenArc->lpBlockTable = lpBlockTable;
+               }
+               else {
+                       memcpy(mpqOpenArc->lpBlockTable,lpBlockTable,mpqOpenArc->MpqHeader.dwBlockTableSize * sizeof(BLOCKTABLEENTRY));
+                       SFFree(lpBlockTable);
+               }
+       }
+       SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+dwLastOffset,0,FILE_BEGIN);
+       SetEndOfFile(mpqOpenArc->hFile);
+       SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart,0,FILE_BEGIN);
+       WriteFile(mpqOpenArc->hFile,&mpqOpenArc->MpqHeader,sizeof(MPQHEADER),&tsz,0);
+       dwLastOffset = mpqOpenArc->MpqHeader.dwHeaderSize;
+       ReadSize = 65536;
+       for (i=dwLastOffset;i<mpqOpenArc->MpqHeader.dwHashTableOffset;i+=65536) {
+               SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+i,0,FILE_BEGIN);
+               SetFilePointer(hFile,i,0,FILE_BEGIN);
+               if (i+65536>mpqOpenArc->MpqHeader.dwHashTableOffset) ReadSize = mpqOpenArc->MpqHeader.dwHashTableOffset-i;
+               ReadFile(hFile,buffer,ReadSize,&tsz,0);
+               WriteFile(mpqOpenArc->hFile,buffer,ReadSize,&tsz,0);
+       }
+       SFFree(buffer);
+       CloseHandle(hFile);
+       DeleteFile(lpFileName);
+       EncryptData((BYTE *)mpqOpenArc->lpHashTable,mpqOpenArc->MpqHeader.dwHashTableSize * sizeof(HASHTABLEENTRY),dwHashTableKey);
+       SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->MpqHeader.dwHashTableOffset,0,FILE_BEGIN);
+       WriteFile(mpqOpenArc->hFile,mpqOpenArc->lpHashTable,mpqOpenArc->MpqHeader.dwHashTableSize * sizeof(HASHTABLEENTRY),&tsz,0);
+       DecryptData((BYTE *)mpqOpenArc->lpHashTable,mpqOpenArc->MpqHeader.dwHashTableSize * sizeof(HASHTABLEENTRY),dwHashTableKey);
+       if(mpqOpenArc->lpBlockTable!=0) {
+               EncryptData((BYTE *)mpqOpenArc->lpBlockTable,mpqOpenArc->MpqHeader.dwBlockTableSize * sizeof(BLOCKTABLEENTRY),dwBlockTableKey);
+               SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->MpqHeader.dwBlockTableOffset,0,FILE_BEGIN);
+               WriteFile(mpqOpenArc->hFile,mpqOpenArc->lpBlockTable,mpqOpenArc->MpqHeader.dwBlockTableSize * sizeof(BLOCKTABLEENTRY),&tsz,0);
+               DecryptData((BYTE *)mpqOpenArc->lpBlockTable,mpqOpenArc->MpqHeader.dwBlockTableSize * sizeof(BLOCKTABLEENTRY),dwBlockTableKey);
+       }
+       return TRUE;
+}
+
+BOOL SFMPQAPI WINAPI MpqSetFileLocale(MPQHANDLE hMPQ, LPCSTR lpFileName, LCID nOldLocale, LCID nNewLocale)
+{
+       if (!hMPQ || !lpFileName) {
+               SetLastError(ERROR_INVALID_PARAMETER);
+               return FALSE;
+       }
+
+       if (!(((MPQARCHIVE *)hMPQ)->dwFlags&SFILE_OPEN_ALLOW_WRITE)) {
+               SetLastError(ERROR_ACCESS_DENIED);
+               return FALSE;
+       }
+       if (nOldLocale==nNewLocale) return FALSE;
+       MPQARCHIVE *mpqOpenArc = (MPQARCHIVE *)hMPQ;
+       HASHTABLEENTRY *hashEntry = (HASHTABLEENTRY *)GetHashTableEntry(hMPQ,lpFileName,nOldLocale);
+       if (hashEntry==0) return FALSE;
+       if (hashEntry->lcLocale!=nOldLocale) return FALSE;
+       hashEntry->lcLocale = nNewLocale;
+       DWORD tsz;
+
+       char *buffer = (char *)SFAlloc(sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize);
+       if (buffer!=0) {
+               memcpy(buffer,mpqOpenArc->lpHashTable,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize);
+               EncryptData((LPBYTE)buffer,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,dwHashTableKey);
+               SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->MpqHeader.dwHashTableOffset,0,FILE_BEGIN);
+               WriteFile(mpqOpenArc->hFile,buffer,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,&tsz,0);
+               SFFree(buffer);
+       }
+       else {
+               EncryptData((LPBYTE)mpqOpenArc->lpHashTable,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,dwHashTableKey);
+               SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->MpqHeader.dwHashTableOffset,0,FILE_BEGIN);
+               WriteFile(mpqOpenArc->hFile,mpqOpenArc->lpHashTable,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,&tsz,0);
+               DecryptData((LPBYTE)mpqOpenArc->lpHashTable,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,dwHashTableKey);
+       }
+       LCID dwOldLocale=LocaleID;
+       LocaleID=nOldLocale;
+       RemoveFromInternalListing(hMPQ,lpFileName);
+
+       LocaleID=nNewLocale;
+       AddToInternalListing(hMPQ,lpFileName);
+       LocaleID=dwOldLocale;
+       return TRUE;
+}
+
+DWORD SFMPQAPI WINAPI SFileFindMpqHeader(HANDLE hFile)
+{
+       if (hFile == INVALID_HANDLE_VALUE) {
+               SetLastError(ERROR_INVALID_PARAMETER);
+               return 0xFFFFFFFF;
+       }
+       DWORD FileLen = GetFileSize(hFile,0);
+       char pbuf[sizeof(MPQHEADER)];
+       DWORD tsz;
+       for (DWORD i=0;i<FileLen;i+=512)
+       {
+               SetFilePointer(hFile,i,0,FILE_BEGIN);
+               if (ReadFile(hFile,pbuf,sizeof(MPQHEADER),&tsz,0)==0) return 0xFFFFFFFF;
+               if (tsz<sizeof(MPQHEADER)) return 0xFFFFFFFF;
+               if (memcmp(pbuf,ID_MPQ,4)==0 || memcmp(pbuf,ID_BN3,4)==0)
+               {
+                       // Storm no longer does this, so mpq api shouldn't either
+                       /*FileLen -= i;
+                       if (memcmp(pbuf+8,&FileLen,4)==0)
+                               return i;
+                       else
+                               FileLen += i;*/
+                       return i;
+               }
+       }
+       return 0xFFFFFFFF;
+}
+
+DWORD WINAPI FindMpqHeaderAtLocation(HANDLE hFile, DWORD dwStart, DWORD dwLength)
+{
+       if (hFile == INVALID_HANDLE_VALUE) {
+               SetLastError(ERROR_INVALID_PARAMETER);
+               return 0xFFFFFFFF;
+       }
+       char pbuf[sizeof(MPQHEADER)];
+       DWORD tsz;
+       for (DWORD i=dwStart;i<dwStart+dwLength;i+=512)
+       {
+               SetFilePointer(hFile,i,0,FILE_BEGIN);
+               if (ReadFile(hFile,pbuf,sizeof(MPQHEADER),&tsz,0)==0) return 0xFFFFFFFF;
+               if (i+tsz>dwStart+dwLength) tsz = (dwStart+dwLength)-i;
+               if (tsz<sizeof(MPQHEADER)) return 0xFFFFFFFF;
+               if (memcmp(pbuf,ID_MPQ,4)==0 || memcmp(pbuf,ID_BN3,4)==0)
+               {
+                       // Storm no longer does this, so mpq api shouldn't either
+                       /*FileLen -= i;
+                       if (memcmp(pbuf+8,&FileLen,4)==0)
+                               return i;
+                       else
+                               FileLen += i;*/
+                       return i;
+               }
+       }
+       return 0xFFFFFFFF;
+}
+
+DWORD GetFullPath(LPCSTR lpFileName, char *lpBuffer, DWORD dwBufferLength)
+{
+       if (!lpFileName) return (DWORD)-1;
+       DWORD slen = strlen(lpFileName);
+       if (memcmp(lpFileName+1,":\\",2)==0) {
+               if (slen+1>dwBufferLength) return slen+1;
+               memcpy(lpBuffer,lpFileName,slen+1);
+       }
+#ifdef _WIN32
+       else if (lpFileName[0]=='\\') {
+#else
+       else if (lpFileName[0]=='/') {
+#endif
+               if (slen+3>dwBufferLength) return slen+3;
+               memcpy(lpBuffer,StormBasePath,2);
+               memcpy(lpBuffer+2,lpFileName,slen+1);
+       }
+       else {
+               DWORD sbslen = strlen(StormBasePath);
+               if (sbslen+slen+1>dwBufferLength) return sbslen+slen+1;
+               memcpy(lpBuffer,StormBasePath,sbslen);
+               memcpy(lpBuffer+sbslen,lpFileName,slen);
+               lpBuffer[sbslen+slen]=0;
+       }
+       return 0;
+}
+
+MPQHANDLE GetHashTableEntry(MPQHANDLE hMPQ, LPCSTR lpFileName, LCID FileLocale)
+{
+       if (!hMPQ || !lpFileName) return 0;
+       MPQARCHIVE *mpqOpenArc = (MPQARCHIVE *)hMPQ;
+       DWORD dwTablePos = HashString(lpFileName,HASH_POSITION) % mpqOpenArc->MpqHeader.dwHashTableSize;
+       DWORD dwNameHashA = HashString(lpFileName,HASH_NAME_A);
+       DWORD dwNameHashB = HashString(lpFileName,HASH_NAME_B);
+       StartTableSearch:
+       DWORD i=dwTablePos;
+       do
+       {
+               if (mpqOpenArc->lpHashTable[i].dwBlockTableIndex==0xFFFFFFFF)
+               {
+                       break;
+               }
+               else if (mpqOpenArc->lpHashTable[i].dwNameHashA==dwNameHashA && mpqOpenArc->lpHashTable[i].dwNameHashB==dwNameHashB && mpqOpenArc->lpHashTable[i].lcLocale==FileLocale && mpqOpenArc->lpHashTable[i].dwBlockTableIndex!=0xFFFFFFFE)
+               {
+                       return (MPQHANDLE)&mpqOpenArc->lpHashTable[i];
+               }
+               i = (i + 1) % mpqOpenArc->MpqHeader.dwHashTableSize;
+       } while (i!=dwTablePos);
+       if (FileLocale!=0) {FileLocale=0;goto StartTableSearch;}
+       return 0;
+}
+
+MPQHANDLE GetHashTableEntryOfHash(MPQHANDLE hMPQ, DWORD dwTablePos, DWORD dwNameHashA, DWORD dwNameHashB, LCID FileLocale)
+{
+       if (!hMPQ) return 0;
+       MPQARCHIVE *mpqOpenArc = (MPQARCHIVE *)hMPQ;
+       StartTableSearch:
+       DWORD i=dwTablePos;
+       do
+       {
+               if (mpqOpenArc->lpHashTable[i].dwBlockTableIndex==0xFFFFFFFF)
+               {
+                       break;
+               }
+               else if (mpqOpenArc->lpHashTable[i].dwNameHashA==dwNameHashA && mpqOpenArc->lpHashTable[i].dwNameHashB==dwNameHashB && mpqOpenArc->lpHashTable[i].lcLocale==FileLocale && mpqOpenArc->lpHashTable[i].dwBlockTableIndex!=0xFFFFFFFE)
+               {
+                       return (MPQHANDLE)&mpqOpenArc->lpHashTable[i];
+               }
+               i = (i + 1) % mpqOpenArc->MpqHeader.dwHashTableSize;
+       } while (i!=dwTablePos);
+       if (FileLocale!=0) {FileLocale=0;goto StartTableSearch;}
+       return 0;
+}
+
+MPQHANDLE GetFreeHashTableEntry(MPQHANDLE hMPQ, LPCSTR lpFileName, LCID FileLocale, BOOL ReturnExisting)
+{
+       if (!hMPQ || !lpFileName) return 0;
+       MPQARCHIVE *mpqOpenArc = (MPQARCHIVE *)hMPQ;
+       DWORD dwTablePos = HashString(lpFileName,HASH_POSITION) % mpqOpenArc->MpqHeader.dwHashTableSize;
+       DWORD dwNameHashA = HashString(lpFileName,HASH_NAME_A);
+       DWORD dwNameHashB = HashString(lpFileName,HASH_NAME_B);
+       DWORD i=dwTablePos;
+       do
+       {
+               if ((mpqOpenArc->lpHashTable[i].dwBlockTableIndex&0xFFFFFFFE)==0xFFFFFFFE)
+               {
+                       return (MPQHANDLE)&mpqOpenArc->lpHashTable[i];
+               }
+               else if (mpqOpenArc->lpHashTable[i].dwNameHashA==dwNameHashA && mpqOpenArc->lpHashTable[i].dwNameHashB==dwNameHashB && mpqOpenArc->lpHashTable[i].lcLocale==FileLocale)
+               {
+                       if (ReturnExisting!=FALSE)
+                               return (MPQHANDLE)&mpqOpenArc->lpHashTable[i];
+                       else {
+                               SetLastError(MPQ_ERROR_ALREADY_EXISTS);
+                               return 0;
+                       }
+               }
+               i = (i + 1) % mpqOpenArc->MpqHeader.dwHashTableSize;
+       } while (i!=dwTablePos);
+       SetLastError(MPQ_ERROR_HASH_TABLE_FULL);
+       return 0;
+}
+
+BOOL SearchOpenArchives(LPCSTR lpFileName, MPQHANDLE *hMPQ, MPQHANDLE *hFile)
+{
+       MPQHANDLE hnMPQ,hnFile,hndMPQ = 0,hndFile = 0;
+
+       DWORD dwTablePos = HashString(lpFileName,HASH_POSITION);
+       DWORD dwNameHashA = HashString(lpFileName,HASH_NAME_A);
+       DWORD dwNameHashB = HashString(lpFileName,HASH_NAME_B);
+
+       for (DWORD i=0;i<dwOpenMpqCount;i++) {
+               hnMPQ = (MPQHANDLE)lpOpenMpq[i];
+               hnFile = GetHashTableEntryOfHash(hnMPQ,dwTablePos % lpOpenMpq[i]->MpqHeader.dwHashTableSize,dwNameHashA,dwNameHashB,LocaleID);
+
+               if (hnFile!=0) {
+                       if (((HASHTABLEENTRY *)hnFile)->lcLocale == LocaleID) {
+                               *hMPQ = hnMPQ;
+                               *hFile = hnFile;
+                               return TRUE;
+                       }
+                       else if (hndMPQ == 0 || hndFile == 0) {
+                               hndMPQ = hnMPQ;
+                               hndFile = hnFile;
+                       }
+               }
+       }
+
+       if (hndMPQ != 0 && hndFile != 0) {
+               *hMPQ = hndMPQ;
+               *hFile = hndFile;
+               return TRUE;
+       }
+
+       *hMPQ = 0;
+       *hFile = 0;
+       return FALSE;
+}
+
+void SortOpenArchivesByPriority()
+{
+       MPQARCHIVE *hMPQ1,*hMPQ2;
+       for (DWORD i=1;i<dwOpenMpqCount;i++) {
+               do {
+                       hMPQ1 = lpOpenMpq[i-1];
+                       hMPQ2 = lpOpenMpq[i];
+                       if (hMPQ2->dwPriority > hMPQ1->dwPriority) {
+                               lpOpenMpq[i-1] = hMPQ2;
+                               lpOpenMpq[i] = hMPQ1;
+                               i--;
+                       }
+               } while (hMPQ2->dwPriority > hMPQ1->dwPriority && i>0);
+       }
+}
+
+DWORD GetHandleType(MPQHANDLE hFile)
+{
+       DWORD i;
+       for (i=0;i<dwOpenFileCount;i++) {
+               if ((MPQHANDLE)lpOpenFile[i]==hFile) return SFILE_TYPE_FILE;
+       }
+       for (i=0;i<dwOpenMpqCount;i++) {
+               if ((MPQHANDLE)lpOpenMpq[i]==hFile) return SFILE_TYPE_MPQ;
+       }
+       return 0;
+}
+
+BOOL AddToInternalListing(MPQHANDLE hMPQ, LPCSTR lpFileName)
+{
+       MPQARCHIVE *mpqOpenArc = (MPQARCHIVE *)hMPQ;
+       if ((mpqOpenArc->dwFlags & MOAU_MAINTAIN_LISTFILE)==MOAU_MAINTAIN_LISTFILE && stricmp(lpFileName,INTERNAL_LISTFILE)!=0)
+       {
+               MPQHANDLE hlFile;char *buffer=0;DWORD fsz,lsz;
+               lsz = strlen(lpFileName);
+               if (SFileOpenFileEx(hMPQ,INTERNAL_LISTFILE,0,&hlFile)!=0) {
+                       if (((MPQFILE *)hlFile)->lpHashEntry->lcLocale==LocaleID) {
+                               fsz = SFileGetFileSize(hlFile,0);
+                               if (fsz==0) {
+                                       SFileCloseFile(hlFile);
+                                       goto AddFileName;
+                               }
+                               buffer = (char *)SFAlloc(fsz+lsz+2);
+                               if (buffer==0) {
+                                       SFileCloseFile(hlFile);
+                                       return FALSE;
+                               }
+                               if (SFileReadFile(hlFile,buffer,fsz,0,0)==0) {
+                                       SFFree(buffer);
+                                       buffer = 0;
+                               }
+                               buffer[fsz]=0;
+                       }
+                       SFileCloseFile(hlFile);
+               }
+               AddFileName:
+               if (buffer==0) {
+                       fsz = 0;
+                       buffer = (char *)SFAlloc(lsz+2);
+                       buffer[0]=0;
+               }
+               else {
+                       char *buffercopy = strlwr(strdup(buffer));
+                       char *lwrFileName = strlwr(strdup(lpFileName));
+                       char *subbuffer=buffer;
+                       while ((subbuffer=strstr(subbuffer,lpFileName))!=NULL && subbuffer[0]!=0) {
+                               if (subbuffer==buffer && subbuffer[lsz]==0) {
+                                       SFFree(lwrFileName);
+                                       SFFree(buffercopy);
+                                       SFFree(buffer);
+                                       return TRUE;
+                               }
+                               else if (subbuffer==buffer && (subbuffer[lsz]=='\n' || subbuffer[lsz]=='\r')) {
+                                       SFFree(lwrFileName);
+                                       SFFree(buffercopy);
+                                       SFFree(buffer);
+                                       return TRUE;
+                               }
+                               else if (((subbuffer-1)[0]=='\n' || (subbuffer-1)[0]=='\r') && subbuffer[lsz]==0) {
+                                       SFFree(lwrFileName);
+                                       SFFree(buffercopy);
+                                       SFFree(buffer);
+                                       return TRUE;
+                               }
+                               else if (((subbuffer-1)[0]=='\n' || (subbuffer-1)[0]=='\r') && (subbuffer[lsz]=='\n' || subbuffer[lsz]=='\r')) {
+                                       SFFree(lwrFileName);
+                                       SFFree(buffercopy);
+                                       SFFree(buffer);
+                                       return TRUE;
+                               }
+                               subbuffer++;
+                       }
+                       SFFree(lwrFileName);
+                       SFFree(buffercopy);
+               }
+               memcpy(buffer+fsz,lpFileName,lsz);
+               memcpy(buffer+fsz+lsz,"\r\n",2);
+               //LCID dwOldLocale=LocaleID;
+               //LocaleID=0;
+               MpqAddFileFromBuffer(hMPQ,buffer,fsz+lsz+2,INTERNAL_LISTFILE,MAFA_COMPRESS|MAFA_ENCRYPT|MAFA_MODCRYPTKEY|MAFA_REPLACE_EXISTING);
+               //LocaleID=dwOldLocale;
+               SFFree(buffer);
+       }
+       return TRUE;
+}
+
+BOOL RemoveFromInternalListing(MPQHANDLE hMPQ, LPCSTR lpFileName)
+{
+       MPQARCHIVE *mpqOpenArc = (MPQARCHIVE *)hMPQ;
+       if ((mpqOpenArc->dwFlags & MOAU_MAINTAIN_LISTFILE)==MOAU_MAINTAIN_LISTFILE && stricmp(lpFileName,INTERNAL_LISTFILE)!=0)
+       {
+               MPQHANDLE hlFile;char *buffer=0;DWORD fsz,lsz;
+               lsz = strlen(lpFileName);
+               if (SFileOpenFileEx(hMPQ,INTERNAL_LISTFILE,0,&hlFile)!=0) {
+                       if (((MPQFILE *)hlFile)->lpHashEntry->lcLocale==LocaleID) {
+                               fsz = SFileGetFileSize(hlFile,0);
+                               if (fsz==0) {
+                                       SFileCloseFile(hlFile);
+
+                                       return FALSE;
+                               }
+
+                               buffer = (char *)SFAlloc(fsz+1);
+                               if (buffer==0) {
+                                       SFileCloseFile(hlFile);
+                                       return FALSE;
+                               }
+                               buffer[fsz] = 0;
+                               if (SFileReadFile(hlFile,buffer,fsz,0,0)==0) {
+                                       SFFree(buffer);
+                                       buffer = 0;
+                               }
+                       }
+                       SFileCloseFile(hlFile);
+               }
+               if (buffer==0) {
+                       return FALSE;
+               }
+               else {
+                       buffer[fsz]=0;
+                       char *buffercopy = strlwr(strdup(buffer));
+                       char *lwrFileName = strlwr(strdup(lpFileName));
+                       char *subbuffer=buffer;
+
+                       while ((subbuffer=strstr(subbuffer,lpFileName))!=NULL && subbuffer[0]!=0) {
+                               if (subbuffer==buffer && subbuffer[lsz]==0) {
+                                       SFFree(lwrFileName);
+                                       SFFree(buffercopy);
+                                       //LCID dwOldLocale=LocaleID;
+                                       //LocaleID=0;
+                                       MpqAddFileFromBuffer(hMPQ,(LPVOID)"\x00",0,INTERNAL_LISTFILE,MAFA_COMPRESS|MAFA_ENCRYPT|MAFA_MODCRYPTKEY|MAFA_REPLACE_EXISTING);
+                                       //LocaleID=dwOldLocale;
+                                       SFFree(buffer);
+                                       return TRUE;
+                               }
+                               else if (subbuffer==buffer && (subbuffer[lsz]=='\n' || subbuffer[lsz]=='\r')) {
+                                       SFFree(lwrFileName);
+                                       SFFree(buffercopy);
+                                       if (subbuffer[lsz+1]=='\n' || subbuffer[lsz+1]=='\r') lsz++;
+                                       memcpy(subbuffer,subbuffer+lsz+1,strlen(subbuffer+lsz+1));
+                                       //LCID dwOldLocale=LocaleID;
+                                       //LocaleID=0;
+                                       MpqAddFileFromBuffer(hMPQ,buffer,fsz-lsz-1,INTERNAL_LISTFILE,MAFA_COMPRESS|MAFA_ENCRYPT|MAFA_MODCRYPTKEY|MAFA_REPLACE_EXISTING);
+                                       //LocaleID=dwOldLocale;
+                                       SFFree(buffer);
+                                       return TRUE;
+                               }
+                               else if (((subbuffer-1)[0]=='\n' || (subbuffer-1)[0]=='\r') && subbuffer[lsz]==0) {
+                                       SFFree(lwrFileName);
+                                       SFFree(buffercopy);
+                                       //LCID dwOldLocale=LocaleID;
+                                       //LocaleID=0;
+                                       MpqAddFileFromBuffer(hMPQ,buffer,fsz-lsz,INTERNAL_LISTFILE,MAFA_COMPRESS|MAFA_ENCRYPT|MAFA_MODCRYPTKEY|MAFA_REPLACE_EXISTING);
+                                       //LocaleID=dwOldLocale;
+                                       SFFree(buffer);
+                                       return TRUE;
+                               }
+                               else if (((subbuffer-1)[0]=='\n' || (subbuffer-1)[0]=='\r') && (subbuffer[lsz]=='\n' || subbuffer[lsz]=='\r')) {
+                                       SFFree(lwrFileName);
+                                       SFFree(buffercopy);
+                                       if ((subbuffer-2)[0]=='\n' || (subbuffer-2)[0]=='\r') {subbuffer--;lsz++;}
+                                       memcpy(subbuffer-1,subbuffer+lsz,strlen(subbuffer+lsz));
+                                       //LCID dwOldLocale=LocaleID;
+                                       //LocaleID=0;
+                                       MpqAddFileFromBuffer(hMPQ,buffer,fsz-lsz-1,INTERNAL_LISTFILE,MAFA_COMPRESS|MAFA_ENCRYPT|MAFA_MODCRYPTKEY|MAFA_REPLACE_EXISTING);
+                                       //LocaleID=dwOldLocale;
+                                       SFFree(buffer);
+                                       return TRUE;
+                               }
+                               subbuffer++;
+                       }
+                       SFFree(lwrFileName);
+                       SFFree(buffercopy);
+               }
+               SFFree(buffer);
+       }
+       return TRUE;
+}
+
+size_t strlnlen(const char *strline)
+{
+       if (strline==0) return 0;
+       const char *strcr = strchr(strline,'\r');
+       const char *strlf = strchr(strline,'\n');
+       if (strcr==0 && strlf==0) return strlen(strline);
+       if (strcr!=0 && (strcr<strlf || strlf==0)) return strcr-strline;
+       if (strlf!=0 && (strlf<strcr || strcr==0)) return strlf-strline;
+       return strlen(strline);
+}
+
+char *nextline(const char *strline)
+{
+       if (strline==0) return 0;
+       const char *strcr = strchr(strline,'\r');
+       const char *strlf = strchr(strline,'\n');
+       if (strcr==0 && strlf==0) return 0;
+       const char *streol;
+       if (strcr!=0 && (strcr<strlf || strlf==0)) streol = strcr;
+       if (strlf!=0 && (strlf<strcr || strcr==0)) streol = strlf;
+       do {
+               streol++;
+       } while (streol[0]=='\r' || streol[0]=='\n');
+       if (streol[0]==0) return 0;
+       return (char *)streol;
+}
+
+// The InitCryptTable, HashString, DecryptData, and DetectFileKey are
+// based on the versions in StormLib which were written by Ladislav 
+// Zezula, but may have been modified somewhat by Quantam or ShadowFlare.
+BOOL InitCryptTable()
+{
+       DWORD seed   = 0x00100001;
+       DWORD index1 = 0;
+       DWORD index2 = 0;
+       int   i;
+               
+       if (!bCryptTableInit)
+       {
+                for(index1 = 0; index1 < 0x100; index1++)
+                {
+                         for(index2 = index1, i = 0; i < 5; i++, index2 += 0x100)
+                         {
+                                       DWORD temp1, temp2;
+               
+                                       seed  = (seed * 125 + 3) % 0x2AAAAB;
+                                       temp1 = (seed & 0xFFFF) << 0x10;
+               
+                                       seed  = (seed * 125 + 3) % 0x2AAAAB;
+                                       temp2 = (seed & 0xFFFF);
+               
+                                       dwCryptTable[index2] = (temp1 | temp2);
+                         }
+                }
+
+               bCryptTableInit = TRUE;
+       }
+
+       return TRUE;
+}
+
+DWORD HashString(LPCSTR lpszString, DWORD dwHashType)
+{
+    DWORD  seed1 = 0x7FED7FED;
+    DWORD  seed2 = 0xEEEEEEEE;
+    int    ch;
+
+       char szNull = 0;
+       if (!lpszString)
+               lpszString = &szNull;
+
+       if (dwHashType==HASH_KEY)
+               while (strchr(lpszString,'\\')!=NULL) lpszString = strchr(lpszString,'\\')+1;
+    while (*lpszString != 0)
+    {
+        ch = toupper(*lpszString++);
+
+        seed1 = dwCryptTable[(dwHashType << 8) + ch] ^ (seed1 + seed2);
+        seed2 = ch + seed1 + seed2 + (seed2 << 5) + 3;
+    }
+
+    return seed1;
+}
+
+// The EncryptData function is based on the DecryptData function by
+// Ladislav Zezula, but adapted by Quantam to encrypt rather than decrypt.
+BOOL EncryptData(LPBYTE lpbyBuffer, DWORD dwLength, DWORD dwKey)
+{
+    LPDWORD lpdwBuffer = (LPDWORD)lpbyBuffer;
+    DWORD seed = 0xEEEEEEEE;
+    DWORD ch;
+
+       if (!lpbyBuffer)
+               return FALSE;
+
+    // Round to DWORDs
+    dwLength >>= 2;
+
+    while(dwLength-- > 0)
+
+    {
+        seed += dwCryptTable[0x400 + (dwKey & 0xFF)];
+        ch = *lpdwBuffer ^ (dwKey + seed);
+
+        dwKey = ((~dwKey << 0x15) + 0x11111111) | (dwKey >> 0x0B);
+        seed = *lpdwBuffer + seed + (seed << 5) + 3;
+
+               *lpdwBuffer++ = ch;
+    }
+
+        return TRUE;
+}
+
+BOOL DecryptData(LPBYTE lpbyBuffer, DWORD dwLength, DWORD dwKey)
+{
+       LPDWORD lpdwBuffer = (LPDWORD)lpbyBuffer;
+    DWORD seed = 0xEEEEEEEE;
+    DWORD ch;
+
+       if (!lpbyBuffer)
+               return FALSE;
+
+    // Round to DWORDs
+    dwLength >>= 2;
+
+    while(dwLength-- > 0)
+    {
+        seed += dwCryptTable[0x400 + (dwKey & 0xFF)];
+        ch = *lpdwBuffer ^ (dwKey + seed);
+
+        dwKey = ((~dwKey << 0x15) + 0x11111111) | (dwKey >> 0x0B);
+        seed = ch + seed + (seed << 5) + 3;
+
+               *lpdwBuffer++ = ch;
+    }
+
+        return TRUE;
+}
+
+//-----------------------------------------------------------------------------
+// Functions tries to get file decryption key. The trick comes from block
+// positions which are stored at the begin of each compressed file. We know the
+// file size, that means we know number of blocks that means we know the first
+// DWORD value in block position. And if we know encrypted and decrypted value,
+// we can find the decryption key !!!
+//
+// hf    - MPQ file handle
+// block - DWORD array of block positions
+// ch    - Decrypted value of the first block pos
+
+static DWORD DetectFileSeed(DWORD * block, DWORD decrypted, DWORD blocksize)
+{
+    DWORD saveSeed1;
+    DWORD temp = *block ^ decrypted;    // temp = seed1 + seed2
+                                        // temp = seed1 + stormBuffer[0x400 + (seed1 & 0xFF)] + 0xEEEEEEEE
+    temp -= 0xEEEEEEEE;                 // temp = seed1 + stormBuffer[0x400 + (seed1 & 0xFF)]
+    
+
+    for(int i = 0; i < 0x100; i++)      // Try all 256 possibilities
+    {
+        DWORD seed1;
+        DWORD seed2 = 0xEEEEEEEE;
+        DWORD ch;
+
+        // Try the first DWORD (We exactly know the value)
+        seed1  = temp - dwCryptTable[0x400 + i];
+        seed2 += dwCryptTable[0x400 + (seed1 & 0xFF)];
+        ch     = block[0] ^ (seed1 + seed2);
+
+        if(ch != decrypted)
+            continue;
+
+        saveSeed1 = seed1 + 1;
+
+        // If OK, continue and test the second value. We don't know exactly the value,
+        // but we know that the second one has a value less than or equal to the
+               // size of the block position table plus the block size
+        seed1  = ((~seed1 << 0x15) + 0x11111111) | (seed1 >> 0x0B);
+        seed2  = ch + seed2 + (seed2 << 5) + 3;
+
+        seed2 += dwCryptTable[0x400 + (seed1 & 0xFF)];
+        ch     = block[1] ^ (seed1 + seed2);
+
+        if(ch <= decrypted + blocksize)
+            return saveSeed1;
+    }
+    return 0;
+}
+
+DWORD DetectFileSeedEx(MPQARCHIVE * mpqOpenArc, HASHTABLEENTRY * lpHashEntry, LPCSTR * lplpFileName)
+{
+       if (mpqOpenArc==0 || lpHashEntry==0) return 0;
+       DWORD dwCryptKey=0;
+       LPCSTR lpFileName = *lplpFileName;
+       DWORD dwBlockIndex = lpHashEntry->dwBlockTableIndex;
+       if (lpFileName)
+       {
+               dwCryptKey = HashString(lpFileName,HASH_KEY);
+               if (mpqOpenArc->lpBlockTable[dwBlockIndex].dwFlags&MAFA_MODCRYPTKEY)
+                       dwCryptKey = (dwCryptKey + mpqOpenArc->lpBlockTable[dwBlockIndex].dwFileOffset) ^ mpqOpenArc->lpBlockTable[dwBlockIndex].dwFullSize;
+       }
+       else
+       {
+               DWORD dwNameHashA = HashString(INTERNAL_LISTFILE,HASH_NAME_A);
+               DWORD dwNameHashB = HashString(INTERNAL_LISTFILE,HASH_NAME_B);
+               if (lpHashEntry->dwNameHashA==dwNameHashA && lpHashEntry->dwNameHashB==dwNameHashB) {
+                       dwCryptKey = HashString(INTERNAL_LISTFILE,HASH_KEY);
+                       if (mpqOpenArc->lpBlockTable[dwBlockIndex].dwFlags&MAFA_MODCRYPTKEY)
+                               dwCryptKey = (dwCryptKey + mpqOpenArc->lpBlockTable[dwBlockIndex].dwFileOffset) ^ mpqOpenArc->lpBlockTable[dwBlockIndex].dwFullSize;
+                       *lplpFileName = (char *)SFAlloc(strlen(INTERNAL_LISTFILE)+1);
+                       if (*lplpFileName)
+                               strcpy((LPSTR)*lplpFileName,INTERNAL_LISTFILE);
+               }
+               else {
+                       HANDLE hlFile,hMPQ=(HANDLE)mpqOpenArc;
+                       DWORD fsz;
+                       char *listbuffer;
+                       LCID lcOldLocale = LocaleID;
+                       for (DWORD lcn=0;lcn<nLocales;lcn++) {
+                               LocaleID = availLocales[lcn];
+                               if (SFileOpenFileEx(hMPQ,INTERNAL_LISTFILE,0,&hlFile)!=0) {
+                                       if (((MPQFILE *)hlFile)->lpHashEntry->lcLocale==0 && LocaleID!=0) {
+                                               SFileCloseFile(hlFile);
+                                               continue;
+                                       }
+                                       fsz = SFileGetFileSize(hlFile,0);
+                                       if (fsz>0) {
+                                               listbuffer = (char *)SFAlloc(fsz+1);
+                                               if (listbuffer==0) {
+                                                       SFileCloseFile(hlFile);
+                                                       continue;
+                                               }
+                                               if (SFileReadFile(hlFile,listbuffer,fsz,0,0)==0) {
+                                                       SFFree(listbuffer);
+                                                       listbuffer = 0;
+                                               }
+                                       }
+                                       SFileCloseFile(hlFile);
+                                       if (listbuffer!=0) {
+                                               char *listline;
+                                               for (listline=listbuffer;listline!=0;listline=nextline(listline)) {
+                                                       if (listline[0]==0) break;
+                                                       DWORD lnlen=strlnlen(listline);
+                                                       char prevchar=listline[lnlen];
+                                                       listline[lnlen]=0;
+                                                       dwNameHashA = HashString(listline,HASH_NAME_A);
+                                                       dwNameHashB = HashString(listline,HASH_NAME_B);
+                                                       if (lpHashEntry->dwNameHashA==dwNameHashA && lpHashEntry->dwNameHashB==dwNameHashB) {
+                                                               dwCryptKey = HashString(listline,HASH_KEY);
+                                                               if (mpqOpenArc->lpBlockTable[dwBlockIndex].dwFlags&MAFA_MODCRYPTKEY)
+                                                                       dwCryptKey = (dwCryptKey + mpqOpenArc->lpBlockTable[dwBlockIndex].dwFileOffset) ^ mpqOpenArc->lpBlockTable[dwBlockIndex].dwFullSize;
+                                                               *lplpFileName = (char *)SFAlloc(strlen(listline)+1);
+                                                               if (*lplpFileName)
+                                                                       strcpy((LPSTR)*lplpFileName,listline);
+                                                               break;
+                                                       }
+                                                       listline[lnlen]=prevchar;
+                                               }
+                                               if (listline!=0) {
+                                                       if (listline[0]!=0) {
+                                                               SFFree(listbuffer);
+                                                               break;
+                                                       }
+                                               }
+                                               SFFree(listbuffer);
+                                       }
+                               }
+                       }
+                       LocaleID = lcOldLocale;
+               }
+               if (dwCryptKey==0 && (mpqOpenArc->lpBlockTable[dwBlockIndex].dwFlags&MAFA_COMPRESS || mpqOpenArc->lpBlockTable[dwBlockIndex].dwFlags&MAFA_COMPRESS2))
+               {
+                       DWORD HeaderLength=0,tsz;
+                       if (memcmp(&mpqOpenArc->MpqHeader.dwMPQID,ID_BN3,4)==0)
+                       {
+                               SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->lpBlockTable[dwBlockIndex].dwFileOffset,0,FILE_BEGIN);
+                               ReadFile(mpqOpenArc->hFile,&HeaderLength,4,&tsz,0);
+                       }
+                       DWORD blockSize = 512 << mpqOpenArc->MpqHeader.wBlockSize;
+                       DWORD TotalBlocks = mpqOpenArc->lpBlockTable[dwBlockIndex].dwFullSize / blockSize;
+                       if(mpqOpenArc->lpBlockTable[dwBlockIndex].dwFullSize % blockSize)
+                               TotalBlocks++;
+                       DWORD *dwBlockPtrTable = (DWORD *)SFAlloc((TotalBlocks+1)*4);
+                       if (dwBlockPtrTable==0)
+                               return 0;
+                       SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->lpBlockTable[dwBlockIndex].dwFileOffset+HeaderLength,0,FILE_BEGIN);
+                       ReadFile(mpqOpenArc->hFile,dwBlockPtrTable,(TotalBlocks+1)*4,&tsz,0);
+                       dwCryptKey = DetectFileSeed(dwBlockPtrTable,(TotalBlocks+1)*4,blockSize);
+
+                       SFFree(dwBlockPtrTable);
+               }
+       }
+       return dwCryptKey;
+}
+
+long SFMPQAPI __inline SFMpqCompareVersion()
+{
+       SFMPQVERSION ExeVersion = SFMPQ_CURRENT_VERSION;
+       SFMPQVERSION DllVersion = SFMpqGetVersion();
+       if (DllVersion.Major>ExeVersion.Major) return 1;
+       else if (DllVersion.Major<ExeVersion.Major) return -1;
+       if (DllVersion.Minor>ExeVersion.Minor) return 1;
+       else if (DllVersion.Minor<ExeVersion.Minor) return -1;
+       if (DllVersion.Revision>ExeVersion.Revision) return 1;
+       else if (DllVersion.Revision<ExeVersion.Revision) return -1;
+       if (DllVersion.Subrevision>ExeVersion.Subrevision) return 1;
+       else if (DllVersion.Subrevision<ExeVersion.Subrevision) return -1;
+       return 0;
+}
+
+void LoadStorm()
+{
+#ifdef _WIN32
+       if (hStorm!=0) return;
+       hStorm = LoadLibrary(Storm_dll);
+       /*if (hStorm==0) {
+               HKEY hKey;
+               LPSTR lpDllPath;
+               DWORD dwStrLen;
+               if (RegOpenKeyEx(HKEY_CURRENT_USER,"Software\\Blizzard Entertainment\\Warcraft III",0,KEY_QUERY_VALUE,&hKey)!=ERROR_SUCCESS)
+                       if (RegOpenKeyEx(HKEY_USERS,".Default\\Software\\Blizzard Entertainment\\Warcraft III",0,KEY_QUERY_VALUE,&hKey)!=ERROR_SUCCESS)
+                               if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,"Software\\Blizzard Entertainment\\Warcraft III",0,KEY_QUERY_VALUE,&hKey)!=ERROR_SUCCESS)
+                                       return;
+               RegQueryValueEx(hKey,"InstallPath",0,0,0,&dwStrLen);
+               lpDllPath = (LPSTR)SFAlloc(dwStrLen+11);
+               if (lpDllPath) {
+                       memset(lpDllPath,0,dwStrLen+11);
+                       RegQueryValueEx(hKey,"InstallPath",0,0,(LPBYTE)lpDllPath,&dwStrLen);
+                       LPSTR lpLastBSlash = strrchr(lpDllPath,'\\');
+                       if (lpLastBSlash) {
+                               if (lpLastBSlash[1]!=0) lpLastBSlash[strlen(lpLastBSlash)]='\\';
+                               strcat(lpLastBSlash,Storm_dll);
+                               hStorm = LoadLibrary(lpDllPath);
+                       }
+                       SFFree(lpDllPath);
+               }
+               RegCloseKey(hKey);
+       }*/
+       if (hStorm==0) return;
+
+       unsigned int wSCCOrdinal=0xAC30;
+       wSCCOrdinal>>=4;
+       wSCCOrdinal/=5;
+       unsigned int wSCDcOrdinal=0xAC80;
+       wSCDcOrdinal>>=4;
+       wSCDcOrdinal/=5;
+
+       stormSCompCompress = (funcSCompCompress)GetProcAddress(hStorm,(LPCSTR)wSCCOrdinal);
+       stormSCompDecompress = (funcSCompDecompress)GetProcAddress(hStorm,(LPCSTR)wSCDcOrdinal);
+#endif
+}
+
+void FreeStorm()
+{
+#ifdef _WIN32
+       if (hStorm==0) return;
+       FreeLibrary(hStorm);
+       hStorm = 0;
+
+       stormSCompCompress = 0;
+       stormSCompDecompress = 0;
+#endif
+}
+
diff --git a/SFmpqapi.def b/SFmpqapi.def
new file mode 100644 (file)
index 0000000..88051ec
--- /dev/null
@@ -0,0 +1,111 @@
+; License information for this code is in license.txt
+
+EXPORTS
+       MpqInitialize=MpqInitialize @1
+       MpqGetVersion=MpqGetVersion @2
+       MpqGetVersionString=MpqGetVersionString @3
+
+       SFMpqGetVersionString=SFMpqGetVersionString @8
+       SFMpqGetVersion=SFMpqGetVersion @9
+       SFMpqGetVersionString2=SFMpqGetVersionString2 @10
+       SFMpqDestroy=SFMpqDestroy @11
+       AboutSFMpq=AboutSFMpq @12
+
+       MpqOpenArchiveForUpdate=MpqOpenArchiveForUpdate @16
+       MpqCloseUpdatedArchive=MpqCloseUpdatedArchive @17
+       MpqAddFileToArchive=MpqAddFileToArchive @18
+       MpqAddWaveToArchive=MpqAddWaveToArchive @19
+       MpqRenameFile=MpqRenameFile @20
+       MpqDeleteFile=MpqDeleteFile @21
+       MpqCompactArchive=MpqCompactArchive @22
+
+       MpqAddFileFromBuffer=MpqAddFileFromBuffer @23
+       MpqSetFileLocale=MpqSetFileLocale @24
+       MpqAddWaveFromBuffer=MpqAddWaveFromBuffer @25
+       MpqAddFileToArchiveEx=MpqAddFileToArchiveEx @26
+       MpqAddFileFromBufferEx=MpqAddFileFromBufferEx @27
+       MpqRenameAndSetFileLocale=MpqRenameAndSetFileLocale @28
+       MpqDeleteFileWithLocale=MpqDeleteFileWithLocale @29
+       MpqOpenArchiveForUpdateEx=MpqOpenArchiveForUpdateEx @30
+
+;Lmpqapi ordinals
+       SFOpenArchive=SFileOpenArchive @32 NONAME
+       SFCloseArchive=SFileCloseArchive @33 NONAME
+       SFOpenFileEx=SFileOpenFileEx @34 NONAME
+       SFCloseFile=SFileCloseFile @35 NONAME
+       SFGetFileSize=SFileGetFileSize @36 NONAME
+       SFileGetFileInfo=SFileGetFileInfo @37
+       SFSetFilePointer=SFileSetFilePointer @38 NONAME
+       SFReadFile=SFileReadFile @39 NONAME
+       SFSetLocale=SFileSetLocale @40 NONAME
+
+       SFOpenFile=SFileOpenFile @41 NONAME
+       SFileSetArchivePriority=SFileSetArchivePriority @42
+       SFileFindMpqHeader=SFileFindMpqHeader @43
+       SFileListFiles=SFileListFiles @44
+
+;Old Diablo Storm ordinals
+       SFDCloseArchive=SFileCloseArchive @63 NONAME
+       SFDCloseFile=SFileCloseFile @64 NONAME
+       SFDDestroy=SFileDestroy @73 NONAME
+       SFDGetFileArchive=SFileGetFileArchive @75 NONAME
+       SFDGetFileSize=SFileGetFileSize @76 NONAME
+       SFDOpenArchive=SFileOpenArchive @77 NONAME
+       SFDOpenFile=SFileOpenFile @78 NONAME
+       SFDOpenFileEx=SFileOpenFileEx @79 NONAME
+       SFDReadFile=SFileReadFile @80 NONAME
+       SFDSetBasePath=SFileSetBasePath @81 NONAME
+       SFDSetFilePointer=SFileSetFilePointer @82 NONAME
+       SFDSetLocale=SFileSetLocale @83 NONAME
+       SFDGetBasePath=SFileGetBasePath @84 NONAME
+       SFDGetArchiveName=SFileGetArchiveName @86 NONAME
+       SFDGetFileName=SFileGetFileName @87 NONAME
+       DStormDestroy=StormDestroy @112 NONAME
+
+;Storm ordinals
+       SFileCloseArchive=SFileCloseArchive @252
+       SFileCloseFile=SFileCloseFile @253
+       SFileDestroy=SFileDestroy @262
+       SFileGetFileArchive=SFileGetFileArchive @264
+       SFileGetFileSize=SFileGetFileSize @265
+       SFileOpenArchive=SFileOpenArchive @266
+       SFileOpenFile=SFileOpenFile @267
+       SFileOpenFileEx=SFileOpenFileEx @268
+       SFileReadFile=SFileReadFile @269
+       SFileSetBasePath=SFileSetBasePath @270
+       SFileSetFilePointer=SFileSetFilePointer @271
+       SFileSetLocale=SFileSetLocale @272
+       SFileGetBasePath=SFileGetBasePath @273
+       SFileGetArchiveName=SFileGetArchiveName @275
+       SFileGetFileName=SFileGetFileName @276
+       SFileOpenFileAsArchive=SFileOpenFileAsArchive @293
+       StormDestroy=StormDestroy @301
+       SCompCompress=SCompCompress @551 NONAME
+       SCompDecompress=SCompDecompress @552 NONAME
+
+;Zlib exports
+       adler32
+       compress
+       crc32
+       deflate
+       deflateCopy
+       deflateEnd
+       deflateInit2_
+       deflateInit_
+       deflateParams
+       deflateReset
+       deflateSetDictionary
+       inflate
+       inflateEnd
+       inflateInit2_
+       inflateInit_
+       inflateReset
+       inflateSetDictionary
+       inflateSync
+       uncompress
+       zlibVersion
+       zError
+       inflateSyncPoint
+       get_crc_table
+       compress2
+
diff --git a/SFmpqapi.dsp b/SFmpqapi.dsp
new file mode 100644 (file)
index 0000000..495ad44
--- /dev/null
@@ -0,0 +1,228 @@
+# Microsoft Developer Studio Project File - Name="SFmpqapi" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
+
+CFG=SFmpqapi - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE 
+!MESSAGE NMAKE /f "SFmpqapi.mak".
+!MESSAGE 
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE 
+!MESSAGE NMAKE /f "SFmpqapi.mak" CFG="SFmpqapi - Win32 Debug"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "SFmpqapi - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "SFmpqapi - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "SFmpqapi - Win32 Beta release" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF  "$(CFG)" == "SFmpqapi - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SFMPQAPI_EXPORTS" /YX /FD /c
+# ADD CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SFMPQAPI_EXPORTS" /D "ZLIB_DLL" /YX /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 /out:"Release/SFmpq.dll"
+# SUBTRACT LINK32 /pdb:none
+
+!ELSEIF  "$(CFG)" == "SFmpqapi - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SFMPQAPI_EXPORTS" /YX /FD /GZ /c
+# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SFMPQAPI_EXPORTS" /D "ZLIB_DLL" /YX /FD /GZ /c
+# SUBTRACT CPP /Fr
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /out:"Debug/SFmpq.dll" /pdbtype:sept
+
+!ELSEIF  "$(CFG)" == "SFmpqapi - Win32 Beta release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "SFmpqapi___Win32_Beta_release"
+# PROP BASE Intermediate_Dir "SFmpqapi___Win32_Beta_release"
+# PROP BASE Ignore_Export_Lib 0
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SFMPQAPI_EXPORTS" /YX /FD /c
+# ADD CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SFMPQAPI_EXPORTS" /D "ZLIB_DLL" /D "BETA" /YX /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG" /d "BETA"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 /out:"Release/SFmpq.dll"
+# SUBTRACT BASE LINK32 /pdb:none
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 /out:"Release/SFmpq.dll"
+# SUBTRACT LINK32 /pdb:none
+
+!ENDIF 
+
+# Begin Target
+
+# Name "SFmpqapi - Win32 Release"
+# Name "SFmpqapi - Win32 Debug"
+# Name "SFmpqapi - Win32 Beta release"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=..\SComp\explode.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\SComp\huffman.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\SComp\implode.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\SComp\SComp.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\SComp\SErr.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\SFmpqapi.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\SFmpqapi.def
+# End Source File
+# Begin Source File
+
+SOURCE=.\SFmpqapi.odl
+# End Source File
+# Begin Source File
+
+SOURCE=.\SFmpqapi.rc
+# End Source File
+# Begin Source File
+
+SOURCE=..\SComp\SMem.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\SComp\wave.cpp
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# Begin Source File
+
+SOURCE=..\SComp\Huffman.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\SComp\pklib.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\SComp.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\SComp\SComp.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\SComp\SErr.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\SFmpqapi.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\SComp\SMem.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\SComp\wave.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\SComp\zconf.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\SComp\zlib.h
+# End Source File
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+# Begin Source File
+
+SOURCE=.\about
+# End Source File
+# End Group
+# Begin Source File
+
+SOURCE=..\SComp\ZLib_Static_min.lib
+# End Source File
+# End Target
+# End Project
diff --git a/SFmpqapi.dsw b/SFmpqapi.dsw
new file mode 100644 (file)
index 0000000..5394195
--- /dev/null
@@ -0,0 +1,41 @@
+Microsoft Developer Studio Workspace File, Format Version 6.00
+# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
+
+###############################################################################
+
+Project: "SFmpqapi"=".\SFmpqapi.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Project: "SFmpqlib"=".\SFmpqlib.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Global:
+
+Package=<5>
+{{{
+}}}
+
+Package=<3>
+{{{
+}}}
+
+###############################################################################
+
diff --git a/SFmpqapi.h b/SFmpqapi.h
new file mode 100644 (file)
index 0000000..7fe313d
--- /dev/null
@@ -0,0 +1,455 @@
+/*
+
+  ShadowFlare MPQ API Library. (c) ShadowFlare Software 2002-2008
+  License information for this code is in license.txt and
+  included in this file at the end of this comment.
+
+  All functions below are actual functions that are part of this
+  library and do not need any additional dll files.  It does not
+  even require Storm to be able to decompress or compress files.
+
+  This library emulates the interface of Lmpqapi and Storm MPQ
+  functions, so it may be used as a replacement for them in
+  MPQ extractors/archivers without even needing to recompile
+  the program that uses Lmpqapi or Storm.  It has a few features
+  not included in Lmpqapi and Storm, such as extra flags for some
+  functions, setting the locale ID of existing files, and adding
+  files without having to write them somewhere else first.  Also,
+  MPQ handles used by functions prefixed with "SFile" and "Mpq"
+  can be used interchangably; all functions use the same type
+  of MPQ handles.  You cannot, however, use handles from this
+  library with storm or lmpqapi or vice-versa.  Doing so will
+  most likely result in a crash.
+
+  Revision History:
+  (Release date) 1.08 (ShadowFlare)
+  - Fixed a buffer overflow that would occur when reading files
+    if neither using a buffer that is large enough to contain the
+    entire file nor has a size that is a multiple of 4096
+  - Added SFileOpenFileAsArchive which opens an archive that is
+    contained within an already open archive
+  - Added MpqRenameAndSetFileLocale and MpqDeleteFileWithLocale.
+    These have extra parameters that allow you to use them with
+    files having language codes other than what was last set
+    using SFileSetLocale
+  - Fixed a bug that caused (listfile) to get cleared if adding
+    files with a locale ID other than 0
+  - Added MpqOpenArchiveForUpdateEx which allows creating
+    archives with different block sizes
+  - SFileListFiles can list the contents of bncache.dat without
+    needing an external list
+
+  06/12/2002 1.07 (ShadowFlare)
+  - No longer requires Storm.dll to compress or decompress
+    Warcraft III files
+  - Added SFileListFiles for getting names and information
+    about all of the files in an archive
+  - Fixed a bug with renaming and deleting files
+  - Fixed a bug with adding wave compressed files with
+    low compression setting
+  - Added a check in MpqOpenArchiveForUpdate for proper
+    dwMaximumFilesInArchive values (should be a number that
+    is a power of 2).  If it is not a proper value, it will
+    be rounded up to the next higher power of 2
+
+  05/09/2002 1.06 (ShadowFlare)
+  - Compresses files without Storm.dll!
+  - If Warcraft III is installed, this library will be able to
+    find Storm.dll on its own. (Storm.dll is needed to
+    decompress Warcraft III files)
+  - Fixed a bug where an embedded archive and the file that
+    contains it would be corrupted if the archive was modified
+  - Able to open all .w3m maps now
+
+  29/06/2002 1.05 (ShadowFlare)
+  - Supports decompressing files from Warcraft III MPQ archives
+    if using Storm.dll from Warcraft III
+  - Added MpqAddFileToArchiveEx and MpqAddFileFromBufferEx for
+    using extra compression types
+
+  29/05/2002 1.04 (ShadowFlare)
+  - Files can be compressed now!
+  - Fixed a bug in SFileReadFile when reading data not aligned
+    to the block size
+  - Optimized some of SFileReadFile's code.  It can read files
+    faster now
+  - SFile functions may now be used to access files not in mpq
+    archives as you can with the real storm functions
+  - MpqCompactArchive will no longer corrupt files with the
+    MODCRYPTKEY flag as long as the file is either compressed,
+    listed in "(listfile)", is "(listfile)", or is located in
+    the same place in the compacted archive; so it is safe
+    enough to use it on almost any archive
+  - Added MpqAddWaveFromBuffer
+  - Better handling of archives with no files
+  - Fixed compression with COMPRESS2 flag
+
+  15/05/2002 1.03 (ShadowFlare)
+  - Supports adding files with the compression attribute (does
+    not actually compress files).  Now archives created with
+    this dll can have files added to them through lmpqapi
+    without causing staredit to crash
+  - SFileGetBasePath and SFileSetBasePath work more like their
+    Storm equivalents now
+  - Implemented MpqCompactArchive, but it is not finished yet.
+    In its current state, I would recommend against using it
+    on archives that contain files with the MODCRYPTKEY flag,
+    since it will corrupt any files with that flag
+  - Added SFMpqGetVersionString2 which may be used in Visual
+    Basic to get the version string
+
+  07/05/2002 1.02 (ShadowFlare)
+  - SFileReadFile no longer passes the lpOverlapped parameter it
+    receives to ReadFile.  This is what was causing the function
+    to fail when used in Visual Basic
+  - Added support for more Storm MPQ functions
+  - GetLastError may now be used to get information about why a
+    function failed
+
+  01/05/2002 1.01 (ShadowFlare)
+  - Added ordinals for Storm MPQ functions
+  - Fixed MPQ searching functionality of SFileOpenFileEx
+  - Added a check for whether a valid handle is given when
+    SFileCloseArchive is called
+  - Fixed functionality of SFileSetArchivePriority when multiple
+    files are open
+  - File renaming works for all filenames now
+  - SFileReadFile no longer reallocates the buffer for each block
+    that is decompressed.  This should make SFileReadFile at least
+    a little faster
+
+  30/04/2002 1.00 (ShadowFlare)
+  - First version.
+  - Compression not yet supported
+  - Does not use SetLastError yet, so GetLastError will not return any
+    errors that have to do with this library
+  - MpqCompactArchive not implemented
+
+  Any comments or suggestions are accepted at blakflare@hotmail.com (ShadowFlare)
+
+  License information:
+
+  Copyright (c) 2002-2008, ShadowFlare <blakflare@hotmail.com>
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions
+  are met:
+
+  1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+  2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in the
+     documentation and/or other materials provided with the distribution.
+
+  THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND
+  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+  ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+  OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+  OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+  SUCH DAMAGE.
+*/
+
+#ifndef SHADOWFLARE_MPQ_API_INCLUDED
+#define SHADOWFLARE_MPQ_API_INCLUDED
+
+#include <windows.h>
+
+#ifndef SFMPQ_STATIC
+
+#ifdef SFMPQAPI_EXPORTS
+#define SFMPQAPI __declspec(dllexport)
+#else
+#define SFMPQAPI __declspec(dllimport)
+#endif
+
+#else
+#define SFMPQAPI
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct {
+       WORD Major;
+       WORD Minor;
+       WORD Revision;
+       WORD Subrevision;
+} SFMPQVERSION;
+
+// MpqInitialize does nothing.  It is only provided for
+// compatibility with MPQ archivers that use lmpqapi.
+BOOL   SFMPQAPI WINAPI MpqInitialize();
+
+LPCSTR SFMPQAPI WINAPI MpqGetVersionString();
+float  SFMPQAPI WINAPI MpqGetVersion();
+
+void SFMPQAPI WINAPI SFMpqDestroy(); // This no longer needs to be called.  It is only provided for compatibility with older versions
+
+void SFMPQAPI WINAPI AboutSFMpq(); // Displays an about page in a web browser (this has only been tested in Internet Explorer). This is only for the dll version of SFmpq
+
+// SFMpqGetVersionString2's return value is the required length of the buffer plus
+// the terminating null, so use SFMpqGetVersionString2(0, 0); to get the length.
+LPCSTR SFMPQAPI WINAPI SFMpqGetVersionString();
+DWORD  SFMPQAPI WINAPI SFMpqGetVersionString2(LPSTR lpBuffer, DWORD dwBufferLength);
+SFMPQVERSION SFMPQAPI WINAPI SFMpqGetVersion();
+
+// Returns 0 if the dll version is equal to the version your program was compiled
+// with, 1 if the dll is newer, -1 if the dll is older.
+long SFMPQAPI __inline SFMpqCompareVersion();
+
+// General error codes
+#define MPQ_ERROR_MPQ_INVALID      0x85200065
+#define MPQ_ERROR_FILE_NOT_FOUND   0x85200066
+#define MPQ_ERROR_DISK_FULL        0x85200068 //Physical write file to MPQ failed
+#define MPQ_ERROR_HASH_TABLE_FULL  0x85200069
+#define MPQ_ERROR_ALREADY_EXISTS   0x8520006A
+#define MPQ_ERROR_BAD_OPEN_MODE    0x8520006C //When MOAU_READ_ONLY is used without MOAU_OPEN_EXISTING
+
+#define MPQ_ERROR_COMPACT_ERROR    0x85300001
+
+// MpqOpenArchiveForUpdate flags
+#define MOAU_CREATE_NEW          0x00 //If archive does not exist, it will be created. If it exists, the function will fail
+#define MOAU_CREATE_ALWAYS       0x08 //Will always create a new archive
+#define MOAU_OPEN_EXISTING       0x04 //If archive exists, it will be opened. If it does not exist, the function will fail
+#define MOAU_OPEN_ALWAYS         0x20 //If archive exists, it will be opened. If it does not exist, it will be created
+#define MOAU_READ_ONLY           0x10 //Must be used with MOAU_OPEN_EXISTING. Archive will be opened without write access
+#define MOAU_MAINTAIN_ATTRIBUTES 0x02 //Will be used in a future version to create the (attributes) file
+#define MOAU_MAINTAIN_LISTFILE   0x01 //Creates and maintains a list of files in archive when they are added, replaced, or deleted
+
+// MpqOpenArchiveForUpdateEx constants
+#define DEFAULT_BLOCK_SIZE 3 // 512 << number = block size
+#define USE_DEFAULT_BLOCK_SIZE 0xFFFFFFFF // Use default block size that is defined internally
+
+// MpqAddFileToArchive flags
+#define MAFA_EXISTS           0x80000000 //This flag will be added if not present
+#define MAFA_UNKNOWN40000000  0x40000000 //Unknown flag
+#define MAFA_MODCRYPTKEY      0x00020000 //Used with MAFA_ENCRYPT. Uses an encryption key based on file position and size
+#define MAFA_ENCRYPT          0x00010000 //Encrypts the file. The file is still accessible when using this, so the use of this has depreciated
+#define MAFA_COMPRESS         0x00000200 //File is to be compressed when added. This is used for most of the compression methods
+#define MAFA_COMPRESS2        0x00000100 //File is compressed with standard compression only (was used in Diablo 1)
+#define MAFA_REPLACE_EXISTING 0x00000001 //If file already exists, it will be replaced
+
+// MpqAddFileToArchiveEx compression flags
+#define MAFA_COMPRESS_STANDARD 0x08 //Standard PKWare DCL compression
+#define MAFA_COMPRESS_DEFLATE  0x02 //ZLib's deflate compression
+#define MAFA_COMPRESS_WAVE     0x81 //Standard wave compression
+#define MAFA_COMPRESS_WAVE2    0x41 //Unused wave compression
+
+// Flags for individual compression types used for wave compression
+#define MAFA_COMPRESS_WAVECOMP1 0x80 //Main compressor for standard wave compression
+#define        MAFA_COMPRESS_WAVECOMP2 0x40 //Main compressor for unused wave compression
+#define MAFA_COMPRESS_WAVECOMP3 0x01 //Secondary compressor for wave compression
+
+// ZLib deflate compression level constants (used with MpqAddFileToArchiveEx and MpqAddFileFromBufferEx)
+#define Z_NO_COMPRESSION         0
+#define Z_BEST_SPEED             1
+#define Z_BEST_COMPRESSION       9
+#define Z_DEFAULT_COMPRESSION  (-1) //Default level is 6 with current ZLib version
+
+// MpqAddWaveToArchive quality flags
+#define MAWA_QUALITY_HIGH    1 //Higher compression, lower quality
+#define MAWA_QUALITY_MEDIUM  0 //Medium compression, medium quality
+#define MAWA_QUALITY_LOW     2 //Lower compression, higher quality
+
+// SFileGetFileInfo flags
+#define SFILE_INFO_BLOCK_SIZE      0x01 //Block size in MPQ
+#define SFILE_INFO_HASH_TABLE_SIZE 0x02 //Hash table size in MPQ
+#define SFILE_INFO_NUM_FILES       0x03 //Number of files in MPQ
+#define SFILE_INFO_TYPE            0x04 //Is MPQHANDLE a file or an MPQ?
+#define SFILE_INFO_SIZE            0x05 //Size of MPQ or uncompressed file
+#define SFILE_INFO_COMPRESSED_SIZE 0x06 //Size of compressed file
+#define SFILE_INFO_FLAGS           0x07 //File flags (compressed, etc.), file attributes if a file not in an archive
+#define SFILE_INFO_PARENT          0x08 //Handle of MPQ that file is in
+#define SFILE_INFO_POSITION        0x09 //Position of file pointer in files
+#define SFILE_INFO_LOCALEID        0x0A //Locale ID of file in MPQ
+#define SFILE_INFO_PRIORITY        0x0B //Priority of open MPQ
+#define SFILE_INFO_HASH_INDEX      0x0C //Hash table index of file in MPQ
+#define SFILE_INFO_BLOCK_INDEX     0x0D //Block table index of file in MPQ
+
+// Return values of SFileGetFileInfo when SFILE_INFO_TYPE flag is used
+#define SFILE_TYPE_MPQ  0x01
+#define SFILE_TYPE_FILE 0x02
+
+// SFileListFiles flags
+#define SFILE_LIST_MEMORY_LIST  0x01 // Specifies that lpFilelists is a file list from memory, rather than being a list of file lists
+#define SFILE_LIST_ONLY_KNOWN   0x02 // Only list files that the function finds a name for
+#define SFILE_LIST_ONLY_UNKNOWN 0x04 // Only list files that the function does not find a name for
+
+// SFileOpenArchive flags
+#define SFILE_OPEN_HARD_DISK_FILE 0x0000 //Open archive without regard to the drive type it resides on
+#define SFILE_OPEN_CD_ROM_FILE    0x0001 //Open the archive only if it is on a CD-ROM
+#define SFILE_OPEN_ALLOW_WRITE    0x8000 //Open file with write access
+
+// SFileOpenFileEx search scopes
+#define SFILE_SEARCH_CURRENT_ONLY 0x00 //Used with SFileOpenFileEx; only the archive with the handle specified will be searched for the file
+#define SFILE_SEARCH_ALL_OPEN     0x01 //SFileOpenFileEx will look through all open archives for the file. This flag also allows files outside the archive to be used
+
+typedef HANDLE MPQHANDLE;
+
+struct FILELISTENTRY {
+       DWORD dwFileExists; // Nonzero if this entry is used
+       LCID lcLocale; // Locale ID of file
+       DWORD dwCompressedSize; // Compressed size of file
+       DWORD dwFullSize; // Uncompressed size of file
+       DWORD dwFlags; // Flags for file
+       char szFileName[260];
+};
+
+struct MPQARCHIVE;
+struct MPQFILE;
+struct MPQHEADER;
+struct BLOCKTABLEENTRY;
+struct HASHTABLEENTRY;
+
+struct MPQHEADER {
+       DWORD dwMPQID; //"MPQ\x1A" for mpq's, "BN3\x1A" for bncache.dat
+       DWORD dwHeaderSize; // Size of this header
+       DWORD dwMPQSize; //The size of the mpq archive
+       WORD wUnused0C; // Seems to always be 0
+       WORD wBlockSize; // Size of blocks in files equals 512 << wBlockSize
+       DWORD dwHashTableOffset; // Offset to hash table
+       DWORD dwBlockTableOffset; // Offset to block table
+       DWORD dwHashTableSize; // Number of entries in hash table
+       DWORD dwBlockTableSize; // Number of entries in block table
+};
+
+//Archive handles may be typecasted to this struct so you can access
+//some of the archive's properties and the decrypted hash table and
+//block table directly.  This struct is based on Storm's internal
+//struct for archive handles.
+struct MPQARCHIVE {
+       // Arranged according to priority with lowest priority first
+       MPQARCHIVE * lpNextArc; //0// Pointer to the next MPQARCHIVE struct. Pointer to addresses of first and last archives if last archive
+       MPQARCHIVE * lpPrevArc; //4// Pointer to the previous MPQARCHIVE struct. 0xEAFC5E23 if first archive
+       char szFileName[260]; //8// Filename of the archive
+       HANDLE hFile; //10C// The archive's file handle
+       DWORD dwFlags1; //110// Some flags, bit 0 seems to be set when opening an archive from a hard drive if bit 1 in the flags for SFileOpenArchive is set, bit 1 (0 based) seems to be set when opening an archive from a CD
+       DWORD dwPriority; //114// Priority of the archive set when calling SFileOpenArchive
+       MPQFILE * lpLastReadFile; //118// Pointer to the last read file's MPQFILE struct. This is cleared when finished reading a block
+       DWORD dwUnk; //11C// Seems to always be 0
+       DWORD dwBlockSize; //120// Size of file blocks in bytes
+       BYTE * lpLastReadBlock; //124// Pointer to the read buffer for archive. This is cleared when finished reading a block
+       DWORD dwBufferSize; //128// Size of the read buffer for archive. This is cleared when finished reading a block
+       DWORD dwMPQStart; //12C// The starting offset of the archive
+       DWORD dwMPQEnd; //130// The ending offset of the archive
+       MPQHEADER * lpMPQHeader; //134// Pointer to the archive header
+       BLOCKTABLEENTRY * lpBlockTable; //138// Pointer to the start of the block table
+       HASHTABLEENTRY * lpHashTable; //13C// Pointer to the start of the hash table
+       DWORD dwReadOffset; //140// Offset to the data for a file
+       DWORD dwRefCount; //144// Count of references to this open archive.  This is incremented for each file opened from the archive, and decremented for each file closed
+       // Extra struct members used by SFmpq
+       MPQHEADER MpqHeader;
+       DWORD dwFlags; //The only flags that should be changed are MOAU_MAINTAIN_LISTFILE and MOAU_MAINTAIN_ATTRIBUTES, changing any others can have unpredictable effects
+       LPSTR lpFileName;
+       DWORD dwExtraFlags;
+};
+
+//Handles to files in the archive may be typecasted to this struct
+//so you can access some of the file's properties directly.  This
+//struct is based on Storm's internal struct for file handles.
+struct MPQFILE {
+       MPQFILE * lpNextFile; //0// Pointer to the next MPQFILE struct. Pointer to addresses of first and last files if last file
+       MPQFILE * lpPrevFile; //4// Pointer to the previous MPQFILE struct. 0xEAFC5E13 if first file
+       char szFileName[260]; //8// Filename of the file
+       HANDLE hFile; //10C// Always INVALID_HANDLE_VALUE for files in MPQ archives. For files not in MPQ archives, this is the file handle for the file and the rest of this struct is filled with zeros except for dwRefCount
+       MPQARCHIVE * lpParentArc; //110// Pointer to the MPQARCHIVE struct of the archive in which the file is contained
+       BLOCKTABLEENTRY * lpBlockEntry; //114// Pointer to the file's block table entry
+       DWORD dwCryptKey; //118// Decryption key for the file
+       DWORD dwFilePointer; //11C// Position of file pointer in the file
+       DWORD dwUnk; //120// Seems to always be 0
+       DWORD dwBlockCount; //124// Number of blocks in file
+       DWORD * lpdwBlockOffsets; //128// Offsets to blocks in file. There are 1 more of these than the number of blocks. The values for this are set after the first read
+       DWORD dwReadStarted; //12C// Set to 1 after first read
+       BOOL bStreaming; //130// 1 when streaming a WAVE
+       BYTE * lpLastReadBlock; //134// Pointer to the read buffer for file. This starts at the position specified in the last SFileSetFilePointer call. This is cleared when SFileSetFilePointer is called or when finished reading the block
+       DWORD dwBytesRead; //138// Total bytes read from the current block in the open file. This is cleared when SFileSetFilePointer is called or when finished reading the block
+       DWORD dwBufferSize; //13C// Size of the read buffer for file. This is cleared when SFileSetFilePointer is called or when finished reading the block
+       DWORD dwRefCount; //140// Count of references to this open file
+       // Extra struct members used by SFmpq
+       HASHTABLEENTRY *lpHashEntry;
+       LPSTR lpFileName;
+};
+
+struct BLOCKTABLEENTRY {
+       DWORD dwFileOffset; // Offset to file
+       DWORD dwCompressedSize; // Compressed size of file
+       DWORD dwFullSize; // Uncompressed size of file
+       DWORD dwFlags; // Flags for file
+};
+
+struct HASHTABLEENTRY {
+       DWORD dwNameHashA; // First name hash of file
+       DWORD dwNameHashB; // Second name hash of file
+       LCID lcLocale; // Locale ID of file
+       DWORD dwBlockTableIndex; // Index to the block table entry for the file
+};
+
+// Defines for backward compatibility with old lmpqapi function names
+#define MpqAddFileToArcive MpqAddFileToArchive
+#define MpqOpenArchive     SFileOpenArchive
+#define MpqOpenFileEx      SFileOpenFileEx
+#define MpqGetFileSize     SFileGetFileSize
+#define MpqReadFile        SFileReadFile
+#define MpqCloseFile       SFileCloseFile
+#define MpqCloseArchive    SFileCloseArchive
+
+// Storm functions implemented by this library
+BOOL      SFMPQAPI WINAPI SFileOpenArchive(LPCSTR lpFileName, DWORD dwPriority, DWORD dwFlags, MPQHANDLE *hMPQ);
+BOOL      SFMPQAPI WINAPI SFileCloseArchive(MPQHANDLE hMPQ);
+BOOL      SFMPQAPI WINAPI SFileOpenFileAsArchive(MPQHANDLE hSourceMPQ, LPCSTR lpFileName, DWORD dwPriority, DWORD dwFlags, MPQHANDLE *hMPQ);
+BOOL      SFMPQAPI WINAPI SFileGetArchiveName(MPQHANDLE hMPQ, LPSTR lpBuffer, DWORD dwBufferLength);
+BOOL      SFMPQAPI WINAPI SFileOpenFile(LPCSTR lpFileName, MPQHANDLE *hFile);
+BOOL      SFMPQAPI WINAPI SFileOpenFileEx(MPQHANDLE hMPQ, LPCSTR lpFileName, DWORD dwSearchScope, MPQHANDLE *hFile);
+BOOL      SFMPQAPI WINAPI SFileCloseFile(MPQHANDLE hFile);
+DWORD     SFMPQAPI WINAPI SFileGetFileSize(MPQHANDLE hFile, LPDWORD lpFileSizeHigh);
+BOOL      SFMPQAPI WINAPI SFileGetFileArchive(MPQHANDLE hFile, MPQHANDLE *hMPQ);
+BOOL      SFMPQAPI WINAPI SFileGetFileName(MPQHANDLE hFile, LPSTR lpBuffer, DWORD dwBufferLength);
+DWORD     SFMPQAPI WINAPI SFileSetFilePointer(MPQHANDLE hFile, LONG lDistanceToMove, PLONG lplDistanceToMoveHigh, DWORD dwMoveMethod);
+BOOL      SFMPQAPI WINAPI SFileReadFile(MPQHANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped);
+LCID      SFMPQAPI WINAPI SFileSetLocale(LCID nNewLocale);
+BOOL      SFMPQAPI WINAPI SFileGetBasePath(LPCSTR lpBuffer, DWORD dwBufferLength);
+BOOL      SFMPQAPI WINAPI SFileSetBasePath(LPCSTR lpNewBasePath);
+
+// Extra storm-related functions
+DWORD     SFMPQAPI WINAPI SFileGetFileInfo(MPQHANDLE hFile, DWORD dwInfoType);
+BOOL      SFMPQAPI WINAPI SFileSetArchivePriority(MPQHANDLE hMPQ, DWORD dwPriority);
+DWORD     SFMPQAPI WINAPI SFileFindMpqHeader(HANDLE hFile);
+BOOL      SFMPQAPI WINAPI SFileListFiles(MPQHANDLE hMPQ, LPCSTR lpFileLists, FILELISTENTRY *lpListBuffer, DWORD dwFlags);
+
+// Archive editing functions implemented by this library
+MPQHANDLE SFMPQAPI WINAPI MpqOpenArchiveForUpdate(LPCSTR lpFileName, DWORD dwFlags, DWORD dwMaximumFilesInArchive);
+DWORD     SFMPQAPI WINAPI MpqCloseUpdatedArchive(MPQHANDLE hMPQ, DWORD dwUnknown2);
+BOOL      SFMPQAPI WINAPI MpqAddFileToArchive(MPQHANDLE hMPQ, LPCSTR lpSourceFileName, LPCSTR lpDestFileName, DWORD dwFlags);
+BOOL      SFMPQAPI WINAPI MpqAddWaveToArchive(MPQHANDLE hMPQ, LPCSTR lpSourceFileName, LPCSTR lpDestFileName, DWORD dwFlags, DWORD dwQuality);
+BOOL      SFMPQAPI WINAPI MpqRenameFile(MPQHANDLE hMPQ, LPCSTR lpcOldFileName, LPCSTR lpcNewFileName);
+BOOL      SFMPQAPI WINAPI MpqDeleteFile(MPQHANDLE hMPQ, LPCSTR lpFileName);
+BOOL      SFMPQAPI WINAPI MpqCompactArchive(MPQHANDLE hMPQ);
+
+// Extra archive editing functions
+MPQHANDLE SFMPQAPI WINAPI MpqOpenArchiveForUpdateEx(LPCSTR lpFileName, DWORD dwFlags, DWORD dwMaximumFilesInArchive, DWORD dwBlockSize);
+BOOL      SFMPQAPI WINAPI MpqAddFileToArchiveEx(MPQHANDLE hMPQ, LPCSTR lpSourceFileName, LPCSTR lpDestFileName, DWORD dwFlags, DWORD dwCompressionType, DWORD dwCompressLevel);
+BOOL      SFMPQAPI WINAPI MpqAddFileFromBufferEx(MPQHANDLE hMPQ, LPVOID lpBuffer, DWORD dwLength, LPCSTR lpFileName, DWORD dwFlags, DWORD dwCompressionType, DWORD dwCompressLevel);
+BOOL      SFMPQAPI WINAPI MpqAddFileFromBuffer(MPQHANDLE hMPQ, LPVOID lpBuffer, DWORD dwLength, LPCSTR lpFileName, DWORD dwFlags);
+BOOL      SFMPQAPI WINAPI MpqAddWaveFromBuffer(MPQHANDLE hMPQ, LPVOID lpBuffer, DWORD dwLength, LPCSTR lpFileName, DWORD dwFlags, DWORD dwQuality);
+BOOL      SFMPQAPI WINAPI MpqRenameAndSetFileLocale(MPQHANDLE hMPQ, LPCSTR lpcOldFileName, LPCSTR lpcNewFileName, LCID nOldLocale, LCID nNewLocale);
+BOOL      SFMPQAPI WINAPI MpqDeleteFileWithLocale(MPQHANDLE hMPQ, LPCSTR lpFileName, LCID nLocale);
+BOOL      SFMPQAPI WINAPI MpqSetFileLocale(MPQHANDLE hMPQ, LPCSTR lpFileName, LCID nOldLocale, LCID nNewLocale);
+
+// These functions do nothing.  They are only provided for
+// compatibility with MPQ extractors that use storm.
+BOOL      SFMPQAPI WINAPI SFileDestroy();
+void      SFMPQAPI WINAPI StormDestroy();
+
+#ifdef __cplusplus
+};  // extern "C" 
+#endif
+
+#endif
+
diff --git a/SFmpqapi.odl b/SFmpqapi.odl
new file mode 100644 (file)
index 0000000..5a6b41e
--- /dev/null
@@ -0,0 +1,288 @@
+// License information for this code is in license.txt
+
+[ uuid(CF183E40-8316-11d6-9E07-00A0C9199875), version(1.08),
+  helpstring("ShadowFlare MPQ API Library v1.08")]
+
+library SFMPQAPI
+{
+       #define WINAPI __stdcall
+       #define HANDLE long
+       #define MPQHANDLE HANDLE
+       #define DWORD long
+       #define LPDWORD DWORD *
+       #define LCID DWORD
+       #define PLONG LONG *
+       #define LPVOID LPSTR
+       #define BOOL boolean
+       typedef struct _OVERLAPPED {
+               DWORD  Internal;
+               DWORD  InternalHigh;
+               DWORD  Offset;
+               DWORD  OffsetHigh;
+               HANDLE hEvent;
+       } OVERLAPPED;
+       //#define LPOVERLAPPED OVERLAPPED *
+       #define LPOVERLAPPED long
+       typedef struct _SFMPQVERSION {
+               WORD Major;
+               WORD Minor;
+               WORD Revision;
+               WORD Subrevision;
+       } SFMPQVERSION;
+       typedef struct _FILELISTENTRY {
+               DWORD dwFileExists; // Nonzero if this entry is used
+               LCID lcLocale; // Locale ID of file
+               DWORD dwCompressedSize; // Compressed size of file
+               DWORD dwFullSize; // Uncompressed size of file
+               DWORD dwFlags; // Flags for file
+               char szFileName[260];
+       } FILELISTENTRY;
+
+       //[uuid(CF183E43-8316-11d6-9E07-00A0C9199875)] 
+       [helpstring("General error codes")]
+       typedef enum {
+               MPQ_ERROR_MPQ_INVALID =     0x85200065,
+               MPQ_ERROR_FILE_NOT_FOUND =  0x85200066,
+               MPQ_ERROR_DISK_FULL =       0x85200068,
+               MPQ_ERROR_HASH_TABLE_FULL = 0x85200069,
+               MPQ_ERROR_ALREADY_EXISTS =  0x8520006A,
+               MPQ_ERROR_BAD_OPEN_MODE =   0x8520006C,
+               MPQ_ERROR_COMPACT_ERROR =   0x85300001,
+       } Error_Constants;
+
+       [helpstring("MpqOpenArchiveForUpdate flags")]
+       typedef enum {
+               MOAU_CREATE_NEW =       0x00,
+               MOAU_CREATE_ALWAYS =    0x08,
+               MOAU_OPEN_EXISTING =    0x04,
+               MOAU_OPEN_ALWAYS =      0x20,
+               MOAU_READ_ONLY =        0x10,
+               MOAU_MAINTAIN_ATTRIBUTES=0x02,
+               MOAU_MAINTAIN_LISTFILE =0x01,
+       } MpqOpenArchiveForUpdate_Flags;
+
+       [helpstring("MpqAddFileToArchive flags")]
+       typedef enum {
+               MAFA_EXISTS =          0x80000000,
+               MAFA_UNKNOWN40000000 = 0x40000000,
+               MAFA_MODCRYPTKEY =     0x00020000,
+               MAFA_ENCRYPT =         0x00010000,
+               MAFA_COMPRESS =        0x00000200,
+               MAFA_COMPRESS2 =       0x00000100,
+               MAFA_REPLACE_EXISTING =0x00000001,
+       } MpqAddFileToArchive_Flags;
+
+       [helpstring("MpqAddFileToArchiveEx compression flags")]
+       typedef enum {
+               MAFA_COMPRESS_STANDARD = 0x08,
+               MAFA_COMPRESS_DEFLATE  = 0x02,
+               MAFA_COMPRESS_WAVE     = 0x81,
+               MAFA_COMPRESS_WAVE2    = 0x41,
+               MAFA_COMPRESS_WAVECOMP1 = 0x80,
+               MAFA_COMPRESS_WAVECOMP2 = 0x40,
+               MAFA_COMPRESS_WAVECOMP3 = 0x01,
+       } MpqAddFileToArchiveEx_Compression_Types;
+
+       [helpstring("Deflate compression level constants")]
+       typedef enum {
+               Z_NO_COMPRESSION = 0,
+               Z_BEST_SPEED = 1,
+               Z_BEST_COMPRESSION = 9,
+               Z_DEFAULT_COMPRESSION = (-1),
+       } Deflate_Compress_Level;
+
+       [helpstring("MpqAddWaveToArchive quality flags")]
+       typedef enum {
+               MAWA_QUALITY_HIGH =   1,
+               MAWA_QUALITY_MEDIUM = 0,
+               MAWA_QUALITY_LOW =    2,
+       } MpqAddWaveToArchive_Quality;
+
+       [helpstring("SFileGetFileInfo flags")]
+       typedef enum {
+               SFILE_INFO_BLOCK_SIZE =     0x01,
+               SFILE_INFO_HASH_TABLE_SIZE =0x02,
+               SFILE_INFO_NUM_FILES =      0x03,
+               SFILE_INFO_TYPE =           0x04,
+               SFILE_INFO_SIZE =           0x05,
+               SFILE_INFO_COMPRESSED_SIZE =0x06,
+               SFILE_INFO_FLAGS =          0x07,
+               SFILE_INFO_PARENT =         0x08,
+               SFILE_INFO_POSITION =       0x09,
+               SFILE_INFO_LOCALEID =       0x0A,
+               SFILE_INFO_PRIORITY =       0x0B,
+               SFILE_INFO_HASH_INDEX =     0x0C,
+       } SFileGetFileInfo_Flags;
+
+       [helpstring("SFileListFiles flags")]
+       typedef enum {
+               SFILE_LIST_MEMORY_LIST  =0x01,
+               SFILE_LIST_ONLY_KNOWN   =0x02,
+               SFILE_LIST_ONLY_UNKNOWN =0x04,
+       } SFileListFiles_Flags;
+
+       [helpstring("Handle type constants")]
+       typedef enum {
+               SFILE_TYPE_MPQ = 0x01,
+               SFILE_TYPE_FILE =0x02,
+       } Handle_Type_Constants;
+
+       [helpstring("SFileOpenArchive flags")]
+       typedef enum {
+               SFILE_OPEN_HARD_DISK_FILE =0x0000,
+               SFILE_OPEN_CD_ROM_FILE =   0x0001,
+               SFILE_OPEN_ALLOW_WRITE =   0x8000,
+       } SFileOpenArchive_Flags;
+
+       [helpstring("SFileOpenFileEx flags")]
+       typedef enum {
+               SFILE_SEARCH_CURRENT_ONLY =0x00,
+               SFILE_SEARCH_ALL_OPEN =    0x01
+       } SFileOpenFileEx_Flags;
+
+       [helpstring("Other misc. flags and constants")]
+       typedef enum {
+               INVALID_HANDLE_VALUE = 0xFFFFFFFF,
+       } Other;
+
+
+       [helpstring("SFileSetFilePointer move methods")]
+       typedef enum {
+               FILE_BEGIN = 0,
+               FILE_CURRENT = 1,
+               FILE_END = 2
+       } SFileSetFilePointer_Move_Methods;
+
+       [helpstring("Windows defined error codes")]
+       typedef enum {
+               ERROR_SUCCESS           = 0,
+               NO_ERROR                = 0,
+               ERROR_FILE_NOT_FOUND    = 2,
+               ERROR_OUTOFMEMORY       = 14,
+               ERROR_INVALID_PARAMETER = 87,
+               ERROR_DISK_FULL         = 112,
+               ERROR_ALREADY_EXISTS    = 183,
+               ERROR_FILE_INVALID      = 1006,
+               ERROR_UNKNOWN_PROPERTY  = 1608
+       } WinErrors;
+
+       [dllname("sfmpq.dll")]
+
+       [helpstring("Version and other misc. functions")]
+       module SFMpq
+       {
+               [entry("MpqInitialize"),helpstring("MpqInitialize does nothing; it is only provided for compatibility with MPQ archivers that use lmpqapi.")]
+                       BOOL   WINAPI MpqInitialize();
+               [entry("MpqGetVersionString"),helpstring("")]
+                       LPCSTR WINAPI MpqGetVersionString();
+               [entry("MpqGetVersion"),helpstring("")]
+                       float  WINAPI MpqGetVersion();
+               [entry("SFMpqDestroy"),helpstring("This no longer needs to be called; it is only provided for compatibility with older versions")]
+                       void   WINAPI SFMpqDestroy();
+               [entry("SFMpqGetVersionString"),helpstring("")]
+                       LPCSTR WINAPI SFMpqGetVersionString();
+               [entry("SFMpqGetVersionString2"),helpstring("SFMpqGetVersionString2's return value is the required length of the buffer plus the terminating null, so use SFMpqGetVersionString2(0, 0) to get the length.")]
+                       DWORD  WINAPI SFMpqGetVersionString2(LPCSTR lpBuffer, DWORD dwBufferLength);
+               [entry("SFMpqGetVersion"),helpstring("")]
+                       SFMPQVERSION WINAPI SFMpqGetVersion();
+               [entry("SFMpqCompareVersion"),helpstring("Returns 0 if the dll version is equal to the version your program was compiled with, 1 if the dll is newer, -1 if the dll is older.")]
+                       long SFMpqCompareVersion();
+       };
+
+       [helpstring("Storm SFile emulated functions")]
+       module SFile
+       {
+               [entry("SFileOpenArchive"),helpstring("")]
+                       BOOL      WINAPI SFileOpenArchive(LPCSTR lpFileName, DWORD dwPriority, DWORD dwFlags, MPQHANDLE *hMPQ);
+               [entry("SFileCloseArchive"),helpstring("")]
+                       BOOL      WINAPI SFileCloseArchive(MPQHANDLE hMPQ);
+               [entry("SFileOpenFileAsArchive"),helpstring("")]
+                       BOOL      WINAPI SFileOpenFileAsArchive(MPQHANDLE hSourceMPQ, LPCSTR lpFileName, DWORD dwPriority, DWORD dwFlags, MPQHANDLE *hMPQ);
+               [entry("SFileGetArchiveName"),helpstring("")]
+                       BOOL      WINAPI SFileGetArchiveName(MPQHANDLE hMPQ, LPCSTR lpBuffer, DWORD dwBufferLength);
+               [entry("SFileOpenFile"),helpstring("")]
+                       BOOL      WINAPI SFileOpenFile(LPCSTR lpFileName, MPQHANDLE *hFile);
+               [entry("SFileOpenFileEx"),helpstring("")]
+                       BOOL      WINAPI SFileOpenFileEx(MPQHANDLE hMPQ, LPCSTR lpFileName, DWORD dwSearchScope, MPQHANDLE *hFile);
+               [entry("SFileCloseFile"),helpstring("")]
+                       BOOL      WINAPI SFileCloseFile(MPQHANDLE hFile);
+               [entry("SFileGetFileSize"),helpstring("")]
+                       DWORD     WINAPI SFileGetFileSize(MPQHANDLE hFile, LPDWORD lpFileSizeHigh);
+               [entry("SFileGetFileArchive"),helpstring("")]
+                       BOOL      WINAPI SFileGetFileArchive(MPQHANDLE hFile, MPQHANDLE *hMPQ);
+               [entry("SFileGetFileName"),helpstring("")]
+                       BOOL      WINAPI SFileGetFileName(MPQHANDLE hFile, LPCSTR lpBuffer, DWORD dwBufferLength);
+               [entry("SFileSetFilePointer"),helpstring("")]
+                       DWORD     WINAPI SFileSetFilePointer(MPQHANDLE hFile, long lDistanceToMove, PLONG lplDistanceToMoveHigh, DWORD dwMoveMethod);
+               [entry("SFileReadFile"),helpstring("")]
+                       BOOL      WINAPI SFileReadFile(MPQHANDLE hFile,LPVOID lpBuffer,DWORD nNumberOfBytesToRead,LPDWORD lpNumberOfBytesRead,LPOVERLAPPED lpOverlapped);
+               [entry("SFileReadFile"),helpstring("")]
+                       BOOL      WINAPI SFileReadFileB(MPQHANDLE hFile,byte *lpBuffer,DWORD nNumberOfBytesToRead,LPDWORD lpNumberOfBytesRead,LPOVERLAPPED lpOverlapped);
+               [entry("SFileSetLocale"),helpstring("")]
+                       LCID      WINAPI SFileSetLocale(LCID nNewLocale);
+               [entry("SFileGetBasePath"),helpstring("")]
+                       BOOL      WINAPI SFileGetBasePath(LPCSTR lpBuffer, DWORD dwBufferLength);
+               [entry("SFileSetBasePath"),helpstring("")]
+                       BOOL      WINAPI SFileSetBasePath(LPCSTR lpNewBasePath);
+               [entry("SFileGetFileInfo"),helpstring("")]
+                       DWORD     WINAPI SFileGetFileInfo(MPQHANDLE hFile, DWORD dwInfoType);
+               [entry("SFileSetArchivePriority"),helpstring("")]
+                       BOOL      WINAPI SFileSetArchivePriority(MPQHANDLE hMPQ, DWORD dwPriority);
+               [entry("SFileFindMpqHeader"),helpstring("")]
+                       DWORD     WINAPI SFileFindMpqHeader(HANDLE hFile);
+               [entry("SFileListFiles"),helpstring("")]
+                       BOOL      WINAPI SFileListFiles(MPQHANDLE hMPQ, LPCSTR lpFileLists, FILELISTENTRY *lpListBuffer, DWORD dwFlags);
+               [entry("SFileDestroy"),helpstring("")]
+                       BOOL      WINAPI SFileDestroy();
+               [entry("StormDestroy"),helpstring("")]
+                       void      WINAPI StormDestroy();
+       };
+
+       [helpstring("MPQ archive creation and editing functions")]
+       module MPQ
+       {
+               [entry("MpqOpenArchiveForUpdate"),helpstring("")]
+                       MPQHANDLE WINAPI MpqOpenArchiveForUpdate(LPCSTR lpFileName, DWORD dwFlags, DWORD dwMaximumFilesInArchive);
+               [entry("MpqCloseUpdatedArchive"),helpstring("")]
+                       DWORD     WINAPI MpqCloseUpdatedArchive(MPQHANDLE hMPQ, DWORD dwUnknown2);
+               [entry("MpqAddFileToArchive"),helpstring("")]
+                       BOOL      WINAPI MpqAddFileToArchive(MPQHANDLE hMPQ, LPCSTR lpSourceFileName, LPCSTR lpDestFileName, DWORD dwFlags);
+               [entry("MpqAddWaveToArchive"),helpstring("")]
+                       BOOL      WINAPI MpqAddWaveToArchive(MPQHANDLE hMPQ, LPCSTR lpSourceFileName, LPCSTR lpDestFileName, DWORD dwFlags, DWORD dwQuality);
+               [entry("MpqRenameFile"),helpstring("")]
+                       BOOL      WINAPI MpqRenameFile(MPQHANDLE hMPQ, LPCSTR lpcOldFileName, LPCSTR lpcNewFileName);
+               [entry("MpqDeleteFile"),helpstring("")]
+                       BOOL      WINAPI MpqDeleteFile(MPQHANDLE hMPQ, LPCSTR lpFileName);
+               [entry("MpqCompactArchive"),helpstring("")]
+                       BOOL      WINAPI MpqCompactArchive(MPQHANDLE hMPQ);
+               [entry("MpqAddFileToArchiveEx"),helpstring("")]
+                       BOOL      WINAPI MpqAddFileToArchiveEx(MPQHANDLE hMPQ, LPCSTR lpSourceFileName, LPCSTR lpDestFileName, DWORD dwFlags, DWORD dwCompressionType, DWORD dwCompressLevel);
+               [entry("MpqAddFileFromBufferEx"),helpstring("")]
+                       BOOL      WINAPI MpqAddFileFromBufferEx(MPQHANDLE hMPQ, LPVOID lpBuffer, DWORD dwLength, LPCSTR lpFileName, DWORD dwFlags, DWORD dwCompressionType, DWORD dwCompressLevel);
+               [entry("MpqAddFileFromBufferEx"),helpstring("")]
+                       BOOL      WINAPI MpqAddFileFromBufferExB(MPQHANDLE hMPQ, byte *lpBuffer, DWORD dwLength, LPCSTR lpFileName, DWORD dwFlags, DWORD dwCompressionType, DWORD dwCompressLevel);
+               [entry("MpqAddFileFromBuffer"),helpstring("")]
+                       BOOL      WINAPI MpqAddFileFromBuffer(MPQHANDLE hMPQ, LPVOID lpBuffer, DWORD dwLength, LPCSTR lpFileName, DWORD dwFlags);
+               [entry("MpqAddFileFromBuffer"),helpstring("")]
+                       BOOL      WINAPI MpqAddFileFromBufferB(MPQHANDLE hMPQ, byte *lpBuffer, DWORD dwLength, LPCSTR lpFileName, DWORD dwFlags);
+               [entry("MpqAddWaveFromBuffer"),helpstring("")]
+                       BOOL      WINAPI MpqAddWaveFromBuffer(MPQHANDLE hMPQ, LPVOID lpBuffer, DWORD dwLength, LPCSTR lpFileName, DWORD dwFlags, DWORD dwQuality);
+               [entry("MpqAddWaveFromBuffer"),helpstring("")]
+                       BOOL      WINAPI MpqAddWaveFromBufferB(MPQHANDLE hMPQ, byte *lpBuffer, DWORD dwLength, LPCSTR lpFileName, DWORD dwFlags, DWORD dwQuality);
+               [entry("MpqRenameAndSetFileLocale"),helpstring("")]
+                       BOOL      WINAPI MpqRenameAndSetFileLocale(MPQHANDLE hMPQ, LPCSTR lpcOldFileName, LPCSTR lpcNewFileName, LCID nOldLocale, LCID nNewLocale);
+               [entry("MpqDeleteFileWithLocale"),helpstring("")]
+                       BOOL      WINAPI MpqDeleteFileWithLocale(MPQHANDLE hMPQ, LPCSTR lpFileName, LCID nLocale);
+               [entry("MpqSetFileLocale"),helpstring("")]
+                       BOOL      WINAPI MpqSetFileLocale(MPQHANDLE hMPQ, LPCSTR lpFileName, LCID nOldLocale, LCID nNewLocale);
+       };
+
+       [dllname("kernel32.dll")]
+
+       module LastError
+       {
+               [entry("GetLastError"),helpstring("")]
+                       DWORD WINAPI GetLastError();
+       };
+};
+
diff --git a/SFmpqapi.rc b/SFmpqapi.rc
new file mode 100644 (file)
index 0000000..798bf00
--- /dev/null
@@ -0,0 +1,123 @@
+// License information for this code is in license.txt
+
+//Microsoft Developer Studio generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "afxres.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE DISCARDABLE 
+BEGIN
+    "resource.h\0"
+END
+
+2 TEXTINCLUDE DISCARDABLE 
+BEGIN
+    "#include ""afxres.h""\r\n"
+    "\0"
+END
+
+3 TEXTINCLUDE DISCARDABLE 
+BEGIN
+    "\r\n"
+    "\0"
+END
+
+#endif    // APSTUDIO_INVOKED
+
+
+#ifndef _MAC
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION 1,0,8,1
+ PRODUCTVERSION 1,0,8,1
+ FILEFLAGSMASK 0x3fL
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x40004L
+ FILETYPE 0x2L
+ FILESUBTYPE 0x0L
+BEGIN
+    BLOCK "StringFileInfo"
+    BEGIN
+        BLOCK "040904b0"
+        BEGIN
+            VALUE "About", "Open res://sfmpq.dll/about or res://path/to/sfmpq.dll/about (replace \x22path/to/\x22 with the actual location) in a web browser to see an about page. (This has only been tested on Internet Explorer)\0"
+#ifdef BETA
+            VALUE "Beta!", "This is a beta!  Anything new in this version has a possibility of being changed in the release version!\0"
+#endif
+            VALUE "CompanyName", "ShadowFlare Software\0"
+#ifdef _DEBUG
+            VALUE "FileDescription", "ShadowFlare MPQ API Library (debug build)\0"
+#else
+            VALUE "FileDescription", "ShadowFlare MPQ API Library\0"
+#endif
+            VALUE "FileVersion", "1.08\0"
+            VALUE "InternalName", "SFmpq\0"
+            VALUE "LegalCopyright", "Copyright Â© ShadowFlare Software 2002-2003\0"
+            VALUE "OriginalFilename", "SFmpq.dll\0"
+            VALUE "ProductName", "MPQ API Library\0"
+            VALUE "ProductVersion", "1, 0, 8, 1\0"
+            VALUE "Web Address", "http://shadowflare.gameproc.com/\0"
+        END
+    END
+    BLOCK "VarFileInfo"
+    BEGIN
+        VALUE "Translation", 0x409, 1200
+    END
+END
+
+#endif    // !_MAC
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// HTML
+//
+
+ABOUT                   HTML    DISCARDABLE     "about"
+#endif    // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif    // not APSTUDIO_INVOKED
+
diff --git a/SFmpqapiVB.rtf b/SFmpqapiVB.rtf
new file mode 100644 (file)
index 0000000..12ee227
Binary files /dev/null and b/SFmpqapiVB.rtf differ
diff --git a/SFmpqapi_no-lib.cpp b/SFmpqapi_no-lib.cpp
new file mode 100644 (file)
index 0000000..73d5af9
--- /dev/null
@@ -0,0 +1,592 @@
+/* License information for this code is in license.txt */
+
+// Code for loading SFmpqapi at run-time
+
+// Comment out the next line to load SFmpqapi at the
+// start of your program, rather that when it is first
+// used.
+#define SFMPQAPI_DELAY_LOAD
+
+#include "SFmpqapi_no-lib.h"
+
+struct SFMPQAPI_DELAY_LOADER {
+#ifndef SFMPQAPI_DELAY_LOAD
+       SFMPQAPI_DELAY_LOADER();
+#endif
+       ~SFMPQAPI_DELAY_LOADER();
+} SFMpqApi_Delay_Loader;
+
+HINSTANCE hSFMpq = 0;
+
+void LoadSFMpqDll();
+
+void LoadSFMpqDll()
+{
+       if (!hSFMpq) hSFMpq = LoadLibrary("SFmpq.dll");
+}
+
+BOOL WINAPI MpqInitialize_stub()
+{
+       LoadSFMpqDll();
+       if (hSFMpq) {
+               *(FARPROC *)&MpqInitialize = GetProcAddress(hSFMpq,"MpqInitialize");
+               if (MpqInitialize) return MpqInitialize();
+       }
+       return FALSE;
+}
+
+LPCSTR WINAPI MpqGetVersionString_stub()
+{
+       LoadSFMpqDll();
+       if (hSFMpq) {
+               *(FARPROC *)&MpqGetVersionString = GetProcAddress(hSFMpq,"MpqGetVersionString");
+               if (MpqGetVersionString) return MpqGetVersionString();
+       }
+       return 0;
+}
+
+float WINAPI MpqGetVersion_stub()
+{
+       LoadSFMpqDll();
+       if (hSFMpq) {
+               *(FARPROC *)&MpqGetVersion = GetProcAddress(hSFMpq,"MpqGetVersion");
+               if (MpqGetVersion) return MpqGetVersion();
+       }
+       return 0;
+}
+
+void WINAPI SFMpqDestroy_stub()
+{
+       LoadSFMpqDll();
+       if (hSFMpq) {
+               *(FARPROC *)&SFMpqDestroy = GetProcAddress(hSFMpq,"SFMpqDestroy");
+               if (SFMpqDestroy) SFMpqDestroy();
+       }
+}
+
+void WINAPI AboutSFMpq_stub()
+{
+       LoadSFMpqDll();
+       if (hSFMpq) {
+               *(FARPROC *)&AboutSFMpq = GetProcAddress(hSFMpq,"AboutSFMpq");
+               if (AboutSFMpq) AboutSFMpq();
+       }
+}
+
+LPCSTR WINAPI SFMpqGetVersionString_stub()
+{
+       LoadSFMpqDll();
+       if (hSFMpq) {
+               *(FARPROC *)&SFMpqGetVersionString = GetProcAddress(hSFMpq,"SFMpqGetVersionString");
+               if (SFMpqGetVersionString) return SFMpqGetVersionString();
+       }
+       return 0;
+}
+
+DWORD WINAPI SFMpqGetVersionString2_stub(LPCSTR lpBuffer, DWORD dwBufferLength)
+{
+       LoadSFMpqDll();
+       if (hSFMpq) {
+               *(FARPROC *)&SFMpqGetVersionString2 = GetProcAddress(hSFMpq,"SFMpqGetVersionString2");
+               if (SFMpqGetVersionString2) return SFMpqGetVersionString2(lpBuffer,dwBufferLength);
+       }
+       return 0;
+}
+
+SFMPQVERSION WINAPI SFMpqGetVersion_stub()
+{
+       LoadSFMpqDll();
+       if (hSFMpq) {
+               *(FARPROC *)&SFMpqGetVersion = GetProcAddress(hSFMpq,"SFMpqGetVersion");
+               if (SFMpqGetVersion) return SFMpqGetVersion();
+       }
+       SFMPQVERSION NoVersionData = {0,0,0,0};
+       return NoVersionData;
+}
+
+BOOL WINAPI SFileOpenArchive_stub(LPCSTR lpFileName, DWORD dwPriority, DWORD dwFlags, MPQHANDLE *hMPQ)
+{
+       LoadSFMpqDll();
+       if (hSFMpq) {
+               *(FARPROC *)&SFileOpenArchive = GetProcAddress(hSFMpq,"SFileOpenArchive");
+               if (SFileOpenArchive) return SFileOpenArchive(lpFileName,dwPriority,dwFlags,hMPQ);
+       }
+       return FALSE;
+}
+
+BOOL WINAPI SFileCloseArchive_stub(MPQHANDLE hMPQ)
+{
+       LoadSFMpqDll();
+       if (hSFMpq) {
+               *(FARPROC *)&SFileCloseArchive = GetProcAddress(hSFMpq,"SFileCloseArchive");
+               if (SFileCloseArchive) return SFileCloseArchive(hMPQ);
+       }
+       return FALSE;
+}
+
+BOOL WINAPI SFileOpenFileAsArchive_stub(MPQHANDLE hSourceMPQ, LPCSTR lpFileName, DWORD dwPriority, DWORD dwFlags, MPQHANDLE *hMPQ)
+{
+       LoadSFMpqDll();
+       if (hSFMpq) {
+               *(FARPROC *)&SFileOpenFileAsArchive = GetProcAddress(hSFMpq,"SFileOpenFileAsArchive");
+               if (SFileOpenFileAsArchive) return SFileOpenFileAsArchive(hSourceMPQ,lpFileName,dwPriority,dwFlags,hMPQ);
+       }
+       return FALSE;
+}
+
+BOOL WINAPI SFileGetArchiveName_stub(MPQHANDLE hMPQ, LPCSTR lpBuffer, DWORD dwBufferLength)
+{
+       LoadSFMpqDll();
+       if (hSFMpq) {
+               *(FARPROC *)&SFileGetArchiveName = GetProcAddress(hSFMpq,"SFileGetArchiveName");
+               if (SFileGetArchiveName) return SFileGetArchiveName(hMPQ,lpBuffer,dwBufferLength);
+       }
+       return FALSE;
+}
+
+BOOL WINAPI SFileOpenFile_stub(LPCSTR lpFileName, MPQHANDLE *hFile)
+{
+       LoadSFMpqDll();
+       if (hSFMpq) {
+               *(FARPROC *)&SFileOpenFile = GetProcAddress(hSFMpq,"SFileOpenFile");
+               if (SFileOpenFile) return SFileOpenFile(lpFileName,hFile);
+       }
+       return FALSE;
+}
+
+BOOL WINAPI SFileOpenFileEx_stub(MPQHANDLE hMPQ, LPCSTR lpFileName, DWORD dwSearchScope, MPQHANDLE *hFile)
+{
+       LoadSFMpqDll();
+       if (hSFMpq) {
+               *(FARPROC *)&SFileOpenFileEx = GetProcAddress(hSFMpq,"SFileOpenFileEx");
+               if (SFileOpenFileEx) return SFileOpenFileEx(hMPQ,lpFileName,dwSearchScope,hFile);
+       }
+       return FALSE;
+}
+
+BOOL WINAPI SFileCloseFile_stub(MPQHANDLE hFile)
+{
+       LoadSFMpqDll();
+       if (hSFMpq) {
+               *(FARPROC *)&SFileCloseFile = GetProcAddress(hSFMpq,"SFileCloseFile");
+               if (SFileCloseFile) return SFileCloseFile(hFile);
+       }
+       return FALSE;
+}
+
+DWORD WINAPI SFileGetFileSize_stub(MPQHANDLE hFile, LPDWORD lpFileSizeHigh)
+{
+       LoadSFMpqDll();
+       if (hSFMpq) {
+               *(FARPROC *)&SFileGetFileSize = GetProcAddress(hSFMpq,"SFileGetFileSize");
+               if (SFileGetFileSize) return SFileGetFileSize(hFile,lpFileSizeHigh);
+       }
+       return (DWORD)-1;
+}
+
+BOOL WINAPI SFileGetFileArchive_stub(MPQHANDLE hFile, MPQHANDLE *hMPQ)
+{
+       LoadSFMpqDll();
+       if (hSFMpq) {
+               *(FARPROC *)&SFileGetFileArchive = GetProcAddress(hSFMpq,"SFileGetFileArchive");
+               if (SFileGetFileArchive) return SFileGetFileArchive(hFile,hMPQ);
+       }
+       return FALSE;
+}
+
+BOOL WINAPI SFileGetFileName_stub(MPQHANDLE hFile, LPCSTR lpBuffer, DWORD dwBufferLength)
+{
+       LoadSFMpqDll();
+       if (hSFMpq) {
+               *(FARPROC *)&SFileGetFileName = GetProcAddress(hSFMpq,"SFileGetFileName");
+               if (SFileGetFileName) return SFileGetFileName(hFile,lpBuffer,dwBufferLength);
+       }
+       return FALSE;
+}
+
+DWORD WINAPI SFileSetFilePointer_stub(MPQHANDLE hFile, long lDistanceToMove, PLONG lplDistanceToMoveHigh, DWORD dwMoveMethod)
+{
+       LoadSFMpqDll();
+       if (hSFMpq) {
+               *(FARPROC *)&SFileSetFilePointer = GetProcAddress(hSFMpq,"SFileSetFilePointer");
+               if (SFileSetFilePointer) return SFileSetFilePointer(hFile,lDistanceToMove,lplDistanceToMoveHigh,dwMoveMethod);
+       }
+       return (DWORD)-1;
+}
+
+BOOL WINAPI SFileReadFile_stub(MPQHANDLE hFile,LPVOID lpBuffer,DWORD nNumberOfBytesToRead,LPDWORD lpNumberOfBytesRead,LPOVERLAPPED lpOverlapped)
+{
+       LoadSFMpqDll();
+       if (hSFMpq) {
+               *(FARPROC *)&SFileReadFile = GetProcAddress(hSFMpq,"SFileReadFile");
+               if (SFileReadFile) return SFileReadFile(hFile,lpBuffer,nNumberOfBytesToRead,lpNumberOfBytesRead,lpOverlapped);
+       }
+       return FALSE;
+}
+
+LCID WINAPI SFileSetLocale_stub(LCID nNewLocale)
+{
+       LoadSFMpqDll();
+       if (hSFMpq) {
+               *(FARPROC *)&SFileSetLocale = GetProcAddress(hSFMpq,"SFileSetLocale");
+               if (SFileSetLocale) return SFileSetLocale(nNewLocale);
+       }
+       return 0;
+}
+
+BOOL WINAPI SFileGetBasePath_stub(LPCSTR lpBuffer, DWORD dwBufferLength)
+{
+       LoadSFMpqDll();
+       if (hSFMpq) {
+               *(FARPROC *)&SFileGetBasePath = GetProcAddress(hSFMpq,"SFileGetBasePath");
+               if (SFileGetBasePath) return SFileGetBasePath(lpBuffer,dwBufferLength);
+       }
+       return FALSE;
+}
+
+BOOL WINAPI SFileSetBasePath_stub(LPCSTR lpNewBasePath)
+{
+       LoadSFMpqDll();
+       if (hSFMpq) {
+               *(FARPROC *)&SFileSetBasePath = GetProcAddress(hSFMpq,"SFileSetBasePath");
+               if (SFileSetBasePath) return SFileSetBasePath(lpNewBasePath);
+       }
+       return FALSE;
+}
+
+DWORD WINAPI SFileGetFileInfo_stub(MPQHANDLE hFile, DWORD dwInfoType)
+{
+       LoadSFMpqDll();
+       if (hSFMpq) {
+               *(FARPROC *)&SFileGetFileInfo = GetProcAddress(hSFMpq,"SFileGetFileInfo");
+               if (SFileGetFileInfo) return SFileGetFileInfo(hFile,dwInfoType);
+       }
+       return (DWORD)-1;
+}
+
+BOOL WINAPI SFileSetArchivePriority_stub(MPQHANDLE hMPQ, DWORD dwPriority)
+{
+       LoadSFMpqDll();
+       if (hSFMpq) {
+               *(FARPROC *)&SFileSetArchivePriority = GetProcAddress(hSFMpq,"SFileSetArchivePriority");
+               if (SFileSetArchivePriority) return SFileSetArchivePriority(hMPQ,dwPriority);
+       }
+       return FALSE;
+}
+
+DWORD WINAPI SFileFindMpqHeader_stub(HANDLE hFile)
+{
+       LoadSFMpqDll();
+       if (hSFMpq) {
+               *(FARPROC *)&SFileFindMpqHeader = GetProcAddress(hSFMpq,"SFileFindMpqHeader");
+               if (SFileFindMpqHeader) return SFileFindMpqHeader(hFile);
+       }
+       return (DWORD)-1;
+}
+
+BOOL WINAPI SFileListFiles_stub(MPQHANDLE hMPQ, LPCSTR lpFileLists, FILELISTENTRY *lpListBuffer, DWORD dwFlags)
+{
+       LoadSFMpqDll();
+       if (hSFMpq) {
+               *(FARPROC *)&SFileListFiles = GetProcAddress(hSFMpq,"SFileListFiles");
+               if (SFileListFiles) return SFileListFiles(hMPQ,lpFileLists,lpListBuffer,dwFlags);
+       }
+       return FALSE;
+}
+
+MPQHANDLE WINAPI MpqOpenArchiveForUpdate_stub(LPCSTR lpFileName, DWORD dwFlags, DWORD dwMaximumFilesInArchive)
+{
+       LoadSFMpqDll();
+       if (hSFMpq) {
+               *(FARPROC *)&MpqOpenArchiveForUpdate = GetProcAddress(hSFMpq,"MpqOpenArchiveForUpdate");
+               if (MpqOpenArchiveForUpdate) return MpqOpenArchiveForUpdate(lpFileName,dwFlags,dwMaximumFilesInArchive);
+       }
+       return INVALID_HANDLE_VALUE;
+}
+
+DWORD WINAPI MpqCloseUpdatedArchive_stub(MPQHANDLE hMPQ, DWORD dwUnknown2)
+{
+       LoadSFMpqDll();
+       if (hSFMpq) {
+               *(FARPROC *)&MpqCloseUpdatedArchive = GetProcAddress(hSFMpq,"MpqCloseUpdatedArchive");
+               if (MpqCloseUpdatedArchive) return MpqCloseUpdatedArchive(hMPQ,dwUnknown2);
+       }
+       return 0;
+}
+
+BOOL WINAPI MpqAddFileToArchive_stub(MPQHANDLE hMPQ, LPCSTR lpSourceFileName, LPCSTR lpDestFileName, DWORD dwFlags)
+{
+       LoadSFMpqDll();
+       if (hSFMpq) {
+               *(FARPROC *)&MpqAddFileToArchive = GetProcAddress(hSFMpq,"MpqAddFileToArchive");
+               if (MpqAddFileToArchive) return MpqAddFileToArchive(hMPQ,lpSourceFileName,lpDestFileName,dwFlags);
+       }
+       return FALSE;
+}
+
+BOOL WINAPI MpqAddWaveToArchive_stub(MPQHANDLE hMPQ, LPCSTR lpSourceFileName, LPCSTR lpDestFileName, DWORD dwFlags, DWORD dwQuality)
+{
+       LoadSFMpqDll();
+       if (hSFMpq) {
+               *(FARPROC *)&MpqAddWaveToArchive = GetProcAddress(hSFMpq,"MpqAddWaveToArchive");
+               if (MpqAddWaveToArchive) return MpqAddWaveToArchive(hMPQ,lpSourceFileName,lpDestFileName,dwFlags,dwQuality);
+       }
+       return FALSE;
+}
+
+BOOL WINAPI MpqRenameFile_stub(MPQHANDLE hMPQ, LPCSTR lpcOldFileName, LPCSTR lpcNewFileName)
+{
+       LoadSFMpqDll();
+       if (hSFMpq) {
+               *(FARPROC *)&MpqRenameFile = GetProcAddress(hSFMpq,"MpqRenameFile");
+               if (MpqRenameFile) return MpqRenameFile(hMPQ,lpcOldFileName,lpcNewFileName);
+       }
+       return FALSE;
+}
+
+BOOL WINAPI MpqDeleteFile_stub(MPQHANDLE hMPQ, LPCSTR lpFileName)
+{
+       LoadSFMpqDll();
+       if (hSFMpq) {
+               *(FARPROC *)&MpqDeleteFile = GetProcAddress(hSFMpq,"MpqDeleteFile");
+               if (MpqDeleteFile) return MpqDeleteFile(hMPQ,lpFileName);
+       }
+       return FALSE;
+}
+
+BOOL WINAPI MpqCompactArchive_stub(MPQHANDLE hMPQ)
+{
+       LoadSFMpqDll();
+       if (hSFMpq) {
+               *(FARPROC *)&MpqCompactArchive = GetProcAddress(hSFMpq,"MpqCompactArchive");
+               if (MpqCompactArchive) return MpqCompactArchive(hMPQ);
+       }
+       return FALSE;
+}
+
+BOOL WINAPI MpqAddFileToArchiveEx_stub(MPQHANDLE hMPQ, LPCSTR lpSourceFileName, LPCSTR lpDestFileName, DWORD dwFlags, DWORD dwCompressionType, DWORD dwCompressLevel)
+{
+       LoadSFMpqDll();
+       if (hSFMpq) {
+               *(FARPROC *)&MpqAddFileToArchiveEx = GetProcAddress(hSFMpq,"MpqAddFileToArchiveEx");
+               if (MpqAddFileToArchiveEx) return MpqAddFileToArchiveEx(hMPQ,lpSourceFileName,lpDestFileName,dwFlags,dwCompressionType,dwCompressLevel);
+       }
+       return FALSE;
+}
+
+BOOL WINAPI MpqAddFileFromBufferEx_stub(MPQHANDLE hMPQ, LPVOID lpBuffer, DWORD dwLength, LPCSTR lpFileName, DWORD dwFlags, DWORD dwCompressionType, DWORD dwCompressLevel)
+{
+       LoadSFMpqDll();
+       if (hSFMpq) {
+               *(FARPROC *)&MpqAddFileFromBufferEx = GetProcAddress(hSFMpq,"MpqAddFileFromBufferEx");
+               if (MpqAddFileFromBufferEx) return MpqAddFileFromBufferEx(hMPQ,lpBuffer,dwLength,lpFileName,dwFlags,dwCompressionType,dwCompressLevel);
+       }
+       return FALSE;
+}
+
+BOOL WINAPI MpqAddFileFromBuffer_stub(MPQHANDLE hMPQ, LPVOID lpBuffer, DWORD dwLength, LPCSTR lpFileName, DWORD dwFlags)
+{
+       LoadSFMpqDll();
+       if (hSFMpq) {
+               *(FARPROC *)&MpqAddFileFromBuffer = GetProcAddress(hSFMpq,"MpqAddFileFromBuffer");
+               if (MpqAddFileFromBuffer) return MpqAddFileFromBuffer(hMPQ,lpBuffer,dwLength,lpFileName,dwFlags);
+       }
+       return FALSE;
+}
+
+BOOL WINAPI MpqAddWaveFromBuffer_stub(MPQHANDLE hMPQ, LPVOID lpBuffer, DWORD dwLength, LPCSTR lpFileName, DWORD dwFlags, DWORD dwQuality)
+{
+       LoadSFMpqDll();
+       if (hSFMpq) {
+               *(FARPROC *)&MpqAddWaveFromBuffer = GetProcAddress(hSFMpq,"MpqAddWaveFromBuffer");
+               if (MpqAddWaveFromBuffer) return MpqAddWaveFromBuffer(hMPQ,lpBuffer,dwLength,lpFileName,dwFlags,dwQuality);
+       }
+       return FALSE;
+}
+
+BOOL WINAPI MpqRenameAndSetFileLocale_stub(MPQHANDLE hMPQ, LPCSTR lpcOldFileName, LPCSTR lpcNewFileName, LCID nOldLocale, LCID nNewLocale)
+{
+       LoadSFMpqDll();
+       if (hSFMpq) {
+               *(FARPROC *)&MpqRenameAndSetFileLocale = GetProcAddress(hSFMpq,"MpqRenameAndSetFileLocale");
+               if (MpqRenameAndSetFileLocale) return MpqRenameAndSetFileLocale(hMPQ,lpcOldFileName,lpcNewFileName,nOldLocale,nNewLocale);
+       }
+       return FALSE;
+}
+
+BOOL WINAPI MpqDeleteFileWithLocale_stub(MPQHANDLE hMPQ, LPCSTR lpFileName, LCID nLocale)
+{
+       LoadSFMpqDll();
+       if (hSFMpq) {
+               *(FARPROC *)&MpqDeleteFileWithLocale = GetProcAddress(hSFMpq,"MpqDeleteFileWithLocale");
+               if (MpqDeleteFileWithLocale) return MpqDeleteFileWithLocale(hMPQ,lpFileName,nLocale);
+       }
+       return FALSE;
+}
+
+BOOL WINAPI MpqSetFileLocale_stub(MPQHANDLE hMPQ, LPCSTR lpFileName, LCID nOldLocale, LCID nNewLocale)
+{
+       LoadSFMpqDll();
+       if (hSFMpq) {
+               *(FARPROC *)&MpqSetFileLocale = GetProcAddress(hSFMpq,"MpqSetFileLocale");
+               if (MpqSetFileLocale) return MpqSetFileLocale(hMPQ,lpFileName,nOldLocale,nNewLocale);
+       }
+       return FALSE;
+}
+
+BOOL WINAPI SFileDestroy_stub()
+{
+       LoadSFMpqDll();
+       if (hSFMpq) {
+               *(FARPROC *)&SFileDestroy = GetProcAddress(hSFMpq,"SFileDestroy");
+               if (SFileDestroy) return SFileDestroy();
+       }
+       return FALSE;
+}
+
+void WINAPI StormDestroy_stub()
+{
+       LoadSFMpqDll();
+       if (hSFMpq) {
+               *(FARPROC *)&StormDestroy = GetProcAddress(hSFMpq,"StormDestroy");
+               if (StormDestroy) StormDestroy();
+       }
+}
+
+BOOL   (WINAPI* MpqInitialize)() = MpqInitialize_stub;
+
+LPCSTR (WINAPI* MpqGetVersionString)() = MpqGetVersionString_stub;
+float  (WINAPI* MpqGetVersion)() = MpqGetVersion_stub;
+
+void (WINAPI* SFMpqDestroy)() = SFMpqDestroy_stub;
+
+void (WINAPI* AboutSFMpq)() = AboutSFMpq_stub;
+
+LPCSTR (WINAPI* SFMpqGetVersionString)() = SFMpqGetVersionString_stub;
+DWORD  (WINAPI* SFMpqGetVersionString2)(LPCSTR lpBuffer, DWORD dwBufferLength) = SFMpqGetVersionString2_stub;
+SFMPQVERSION (WINAPI* SFMpqGetVersion)() = SFMpqGetVersion_stub;
+
+BOOL      (WINAPI* SFileOpenArchive)(LPCSTR lpFileName, DWORD dwPriority, DWORD dwFlags, MPQHANDLE *hMPQ) = SFileOpenArchive_stub;
+BOOL      (WINAPI* SFileCloseArchive)(MPQHANDLE hMPQ) = SFileCloseArchive_stub;
+BOOL      (WINAPI* SFileOpenFileAsArchive)(MPQHANDLE hSourceMPQ, LPCSTR lpFileName, DWORD dwPriority, DWORD dwFlags, MPQHANDLE *hMPQ) = SFileOpenFileAsArchive_stub;
+BOOL      (WINAPI* SFileGetArchiveName)(MPQHANDLE hMPQ, LPCSTR lpBuffer, DWORD dwBufferLength) = SFileGetArchiveName_stub;
+BOOL      (WINAPI* SFileOpenFile)(LPCSTR lpFileName, MPQHANDLE *hFile) = SFileOpenFile_stub;
+BOOL      (WINAPI* SFileOpenFileEx)(MPQHANDLE hMPQ, LPCSTR lpFileName, DWORD dwSearchScope, MPQHANDLE *hFile) = SFileOpenFileEx_stub;
+BOOL      (WINAPI* SFileCloseFile)(MPQHANDLE hFile) = SFileCloseFile_stub;
+DWORD     (WINAPI* SFileGetFileSize)(MPQHANDLE hFile, LPDWORD lpFileSizeHigh) = SFileGetFileSize_stub;
+BOOL      (WINAPI* SFileGetFileArchive)(MPQHANDLE hFile, MPQHANDLE *hMPQ) = SFileGetFileArchive_stub;
+BOOL      (WINAPI* SFileGetFileName)(MPQHANDLE hFile, LPCSTR lpBuffer, DWORD dwBufferLength) = SFileGetFileName_stub;
+DWORD     (WINAPI* SFileSetFilePointer)(MPQHANDLE hFile, long lDistanceToMove, PLONG lplDistanceToMoveHigh, DWORD dwMoveMethod) = SFileSetFilePointer_stub;
+BOOL      (WINAPI* SFileReadFile)(MPQHANDLE hFile,LPVOID lpBuffer,DWORD nNumberOfBytesToRead,LPDWORD lpNumberOfBytesRead,LPOVERLAPPED lpOverlapped) = SFileReadFile_stub;
+LCID      (WINAPI* SFileSetLocale)(LCID nNewLocale) = SFileSetLocale_stub;
+BOOL      (WINAPI* SFileGetBasePath)(LPCSTR lpBuffer, DWORD dwBufferLength) = SFileGetBasePath_stub;
+BOOL      (WINAPI* SFileSetBasePath)(LPCSTR lpNewBasePath) = SFileSetBasePath_stub;
+
+DWORD     (WINAPI* SFileGetFileInfo)(MPQHANDLE hFile, DWORD dwInfoType) = SFileGetFileInfo_stub;
+BOOL      (WINAPI* SFileSetArchivePriority)(MPQHANDLE hMPQ, DWORD dwPriority) = SFileSetArchivePriority_stub;
+DWORD     (WINAPI* SFileFindMpqHeader)(HANDLE hFile) = SFileFindMpqHeader_stub;
+BOOL      (WINAPI* SFileListFiles)(MPQHANDLE hMPQ, LPCSTR lpFileLists, FILELISTENTRY *lpListBuffer, DWORD dwFlags) = SFileListFiles_stub;
+
+MPQHANDLE (WINAPI* MpqOpenArchiveForUpdate)(LPCSTR lpFileName, DWORD dwFlags, DWORD dwMaximumFilesInArchive) = MpqOpenArchiveForUpdate_stub;
+DWORD     (WINAPI* MpqCloseUpdatedArchive)(MPQHANDLE hMPQ, DWORD dwUnknown2) = MpqCloseUpdatedArchive_stub;
+BOOL      (WINAPI* MpqAddFileToArchive)(MPQHANDLE hMPQ, LPCSTR lpSourceFileName, LPCSTR lpDestFileName, DWORD dwFlags) = MpqAddFileToArchive_stub;
+BOOL      (WINAPI* MpqAddWaveToArchive)(MPQHANDLE hMPQ, LPCSTR lpSourceFileName, LPCSTR lpDestFileName, DWORD dwFlags, DWORD dwQuality) = MpqAddWaveToArchive_stub;
+BOOL      (WINAPI* MpqRenameFile)(MPQHANDLE hMPQ, LPCSTR lpcOldFileName, LPCSTR lpcNewFileName) = MpqRenameFile_stub;
+BOOL      (WINAPI* MpqDeleteFile)(MPQHANDLE hMPQ, LPCSTR lpFileName) = MpqDeleteFile_stub;
+BOOL      (WINAPI* MpqCompactArchive)(MPQHANDLE hMPQ) = MpqCompactArchive_stub;
+
+BOOL      (WINAPI* MpqAddFileToArchiveEx)(MPQHANDLE hMPQ, LPCSTR lpSourceFileName, LPCSTR lpDestFileName, DWORD dwFlags, DWORD dwCompressionType, DWORD dwCompressLevel) = MpqAddFileToArchiveEx_stub;
+BOOL      (WINAPI* MpqAddFileFromBufferEx)(MPQHANDLE hMPQ, LPVOID lpBuffer, DWORD dwLength, LPCSTR lpFileName, DWORD dwFlags, DWORD dwCompressionType, DWORD dwCompressLevel) = MpqAddFileFromBufferEx_stub;
+BOOL      (WINAPI* MpqAddFileFromBuffer)(MPQHANDLE hMPQ, LPVOID lpBuffer, DWORD dwLength, LPCSTR lpFileName, DWORD dwFlags) = MpqAddFileFromBuffer_stub;
+BOOL      (WINAPI* MpqAddWaveFromBuffer)(MPQHANDLE hMPQ, LPVOID lpBuffer, DWORD dwLength, LPCSTR lpFileName, DWORD dwFlags, DWORD dwQuality) = MpqAddWaveFromBuffer_stub;
+BOOL      (WINAPI* MpqRenameAndSetFileLocale)(MPQHANDLE hMPQ, LPCSTR lpcOldFileName, LPCSTR lpcNewFileName, LCID nOldLocale, LCID nNewLocale) = MpqRenameAndSetFileLocale_stub;
+BOOL      (WINAPI* MpqDeleteFileWithLocale)(MPQHANDLE hMPQ, LPCSTR lpFileName, LCID nLocale) = MpqDeleteFileWithLocale_stub;
+BOOL      (WINAPI* MpqSetFileLocale)(MPQHANDLE hMPQ, LPCSTR lpFileName, LCID nOldLocale, LCID nNewLocale) = MpqSetFileLocale_stub;
+
+BOOL      (WINAPI* SFileDestroy)() = SFileDestroy_stub;
+void      (WINAPI* StormDestroy)() = StormDestroy_stub;
+
+#ifndef SFMPQAPI_DELAY_LOAD
+SFMPQAPI_DELAY_LOADER::SFMPQAPI_DELAY_LOADER()
+{
+       LoadSFMpqDll();
+}
+#endif
+
+SFMPQAPI_DELAY_LOADER::~SFMPQAPI_DELAY_LOADER()
+{
+       MpqInitialize = 0;
+
+       MpqGetVersionString = 0;
+       MpqGetVersion = 0;
+
+       AboutSFMpq = 0;
+
+       SFMpqGetVersionString = 0;
+       SFMpqGetVersionString2 = 0;
+       SFMpqGetVersion = 0;
+
+       SFileOpenArchive = 0;
+       SFileCloseArchive = 0;
+       SFileOpenFileAsArchive = 0;
+       SFileGetArchiveName = 0;
+       SFileOpenFile = 0;
+       SFileOpenFileEx = 0;
+       SFileCloseFile = 0;
+       SFileGetFileSize = 0;
+       SFileGetFileArchive = 0;
+       SFileGetFileName = 0;
+       SFileSetFilePointer = 0;
+       SFileReadFile = 0;
+       SFileSetLocale = 0;
+       SFileGetBasePath = 0;
+       SFileSetBasePath = 0;
+
+       SFileGetFileInfo = 0;
+       SFileSetArchivePriority = 0;
+       SFileFindMpqHeader = 0;
+       SFileListFiles = 0;
+
+       MpqOpenArchiveForUpdate = 0;
+       MpqCloseUpdatedArchive = 0;
+       MpqAddFileToArchive = 0;
+       MpqAddWaveToArchive = 0;
+       MpqRenameFile = 0;
+       MpqDeleteFile = 0;
+       MpqCompactArchive = 0;
+
+       MpqAddFileToArchiveEx = 0;
+       MpqAddFileFromBufferEx = 0;
+       MpqAddFileFromBuffer = 0;
+       MpqAddWaveFromBuffer = 0;
+       MpqRenameAndSetFileLocale = 0;
+       MpqDeleteFileWithLocale = 0;
+       MpqSetFileLocale = 0;
+
+       SFileDestroy = 0;
+       StormDestroy = 0;
+
+       if (hSFMpq==0) return;
+       if (SFMpqDestroy!=0) SFMpqDestroy();
+
+       SFMpqDestroy = 0;
+
+       FreeLibrary(hSFMpq);
+       hSFMpq = 0;
+}
+
+long SFMpqCompareVersion()
+{
+       SFMPQVERSION ExeVersion = {1,0,8,1};
+       SFMPQVERSION DllVersion = SFMpqGetVersion();
+       if (DllVersion.Major>ExeVersion.Major) return 1;
+       else if (DllVersion.Major<ExeVersion.Major) return -1;
+       if (DllVersion.Minor>ExeVersion.Minor) return 1;
+       else if (DllVersion.Minor<ExeVersion.Minor) return -1;
+       if (DllVersion.Revision>ExeVersion.Revision) return 1;
+       else if (DllVersion.Revision<ExeVersion.Revision) return -1;
+       if (DllVersion.Subrevision>ExeVersion.Subrevision) return 1;
+       else if (DllVersion.Subrevision<ExeVersion.Subrevision) return -1;
+       return 0;
+}
+
diff --git a/SFmpqapi_no-lib.h b/SFmpqapi_no-lib.h
new file mode 100644 (file)
index 0000000..72bb672
--- /dev/null
@@ -0,0 +1,438 @@
+/*
+
+  ShadowFlare MPQ API Library. (c) ShadowFlare Software 2002-2008
+  License information for this code is in license.txt and
+  included in this file at the end of this comment.
+
+  All functions below are actual functions that are part of this
+  library and do not need any additional dll files.  It does not
+  even require Storm to be able to decompress or compress files.
+
+  This library emulates the interface of Lmpqapi and Storm MPQ
+  functions, so it may be used as a replacement for them in
+  MPQ extractors/archivers without even needing to recompile
+  the program that uses Lmpqapi or Storm.  It has a few features
+  not included in Lmpqapi and Storm, such as extra flags for some
+  functions, setting the locale ID of existing files, and adding
+  files without having to write them somewhere else first.  Also,
+  MPQ handles used by functions prefixed with "SFile" and "Mpq"
+  can be used interchangably; all functions use the same type
+  of MPQ handles.  You cannot, however, use handles from this
+  library with storm or lmpqapi or vice-versa.  Doing so will
+  most likely result in a crash.
+
+  Revision History:
+  (Release date) 1.08 (ShadowFlare)
+  - Fixed a buffer overflow that would occur when reading files
+    if neither using a buffer that is large enough to contain the
+    entire file nor has a size that is a multiple of 4096
+  - Added SFileOpenFileAsArchive which opens an archive that is
+    contained within an already open archive
+  - Added MpqRenameAndSetFileLocale and MpqDeleteFileWithLocale.
+    These have extra parameters that allow you to use them with
+    files having language codes other than what was last set
+    using SFileSetLocale
+  - Fixed a bug that caused (listfile) to get cleared if adding
+    files with a locale ID other than 0
+
+  06/12/2002 1.07 (ShadowFlare)
+  - No longer requires Storm.dll to compress or decompress
+    Warcraft III files
+  - Added SFileListFiles for getting names and information
+    about all of the files in an archive
+  - Fixed a bug with renaming and deleting files
+  - Fixed a bug with adding wave compressed files with
+    low compression setting
+  - Added a check in MpqOpenArchiveForUpdate for proper
+    dwMaximumFilesInArchive values (should be a number that
+    is a power of 2).  If it is not a proper value, it will
+    be rounded up to the next higher power of 2
+
+  05/09/2002 1.06 (ShadowFlare)
+  - Compresses files without Storm.dll!
+  - If Warcraft III is installed, this library will be able to
+    find Storm.dll on its own. (Storm.dll is needed to
+    decompress Warcraft III files)
+  - Fixed a bug where an embedded archive and the file that
+    contains it would be corrupted if the archive was modified
+  - Able to open all .w3m maps now
+
+  29/06/2002 1.05 (ShadowFlare)
+  - Supports decompressing files from Warcraft III MPQ archives
+    if using Storm.dll from Warcraft III
+  - Added MpqAddFileToArchiveEx and MpqAddFileFromBufferEx for
+    using extra compression types
+
+  29/05/2002 1.04 (ShadowFlare)
+  - Files can be compressed now!
+  - Fixed a bug in SFileReadFile when reading data not aligned
+    to the block size
+  - Optimized some of SFileReadFile's code.  It can read files
+    faster now
+  - SFile functions may now be used to access files not in mpq
+    archives as you can with the real storm functions
+  - MpqCompactArchive will no longer corrupt files with the
+    MODCRYPTKEY flag as long as the file is either compressed,
+    listed in "(listfile)", is "(listfile)", or is located in
+    the same place in the compacted archive; so it is safe
+    enough to use it on almost any archive
+  - Added MpqAddWaveFromBuffer
+  - Better handling of archives with no files
+  - Fixed compression with COMPRESS2 flag
+
+  15/05/2002 1.03 (ShadowFlare)
+  - Supports adding files with the compression attribute (does
+    not actually compress files).  Now archives created with
+    this dll can have files added to them through lmpqapi
+    without causing staredit to crash
+  - SFileGetBasePath and SFileSetBasePath work more like their
+    Storm equivalents now
+  - Implemented MpqCompactArchive, but it is not finished yet.
+    In its current state, I would recommend against using it
+    on archives that contain files with the MODCRYPTKEY flag,
+    since it will corrupt any files with that flag
+  - Added SFMpqGetVersionString2 which may be used in Visual
+    Basic to get the version string
+
+  07/05/2002 1.02 (ShadowFlare)
+  - SFileReadFile no longer passes the lpOverlapped parameter it
+    receives to ReadFile.  This is what was causing the function
+    to fail when used in Visual Basic
+  - Added support for more Storm MPQ functions
+  - GetLastError may now be used to get information about why a
+    function failed
+
+  01/05/2002 1.01 (ShadowFlare)
+  - Added ordinals for Storm MPQ functions
+  - Fixed MPQ searching functionality of SFileOpenFileEx
+  - Added a check for whether a valid handle is given when
+    SFileCloseArchive is called
+  - Fixed functionality of SFileSetArchivePriority when multiple
+    files are open
+  - File renaming works for all filenames now
+  - SFileReadFile no longer reallocates the buffer for each block
+    that is decompressed.  This should make SFileReadFile at least
+    a little faster
+
+  30/04/2002 1.00 (ShadowFlare)
+  - First version.
+  - Compression not yet supported
+  - Does not use SetLastError yet, so GetLastError will not return any
+    errors that have to do with this library
+  - MpqCompactArchive not implemented
+
+  Any comments or suggestions are accepted at blakflare@hotmail.com (ShadowFlare)
+
+  License information:
+
+  Copyright (c) 2002-2008, ShadowFlare <blakflare@hotmail.com>
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions
+  are met:
+
+  1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+  2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in the
+     documentation and/or other materials provided with the distribution.
+
+  THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND
+  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+  ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+  OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+  OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+  SUCH DAMAGE.
+*/
+
+#ifndef SHADOWFLARE_MPQ_API_INCLUDED
+#define SHADOWFLARE_MPQ_API_INCLUDED
+
+#include <windows.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct {
+       WORD Major;
+       WORD Minor;
+       WORD Revision;
+       WORD Subrevision;
+} SFMPQVERSION;
+
+// These no longer need to be called.  They only provided for
+// compatibility with older versions of this code
+#define LoadSFMpq()
+#define FreeSFMpq()
+
+// MpqInitialize does nothing.  It is only provided for
+// compatibility with MPQ archivers that use lmpqapi.
+extern BOOL   (WINAPI* MpqInitialize)();
+
+extern LPCSTR (WINAPI* MpqGetVersionString)();
+extern float  (WINAPI* MpqGetVersion)();
+
+extern void (WINAPI* SFMpqDestroy)(); // This no longer needs to be called.  It is only provided for compatibility with older versions
+
+extern void (WINAPI* AboutSFMpq)(); // Displays an about page in a web browser (this has only been tested in Internet Explorer). This is only for the dll version of SFmpq
+
+// SFMpqGetVersionString2's return value is the required length of the buffer plus
+// the terminating null, so use SFMpqGetVersionString2(0, 0); to get the length.
+extern LPCSTR (WINAPI* SFMpqGetVersionString)();
+extern DWORD  (WINAPI* SFMpqGetVersionString2)(LPCSTR lpBuffer, DWORD dwBufferLength);
+extern SFMPQVERSION (WINAPI* SFMpqGetVersion)();
+
+// Returns 0 if the dll version is equal to the version your program was compiled
+// with, 1 if the dll is newer, -1 if the dll is older.
+long SFMpqCompareVersion();
+
+// General error codes
+#define MPQ_ERROR_MPQ_INVALID      0x85200065
+#define MPQ_ERROR_FILE_NOT_FOUND   0x85200066
+#define MPQ_ERROR_DISK_FULL        0x85200068 //Physical write file to MPQ failed. Not sure of exact meaning
+#define MPQ_ERROR_HASH_TABLE_FULL  0x85200069
+#define MPQ_ERROR_ALREADY_EXISTS   0x8520006A
+#define MPQ_ERROR_BAD_OPEN_MODE    0x8520006C //When MOAU_READ_ONLY is used without MOAU_OPEN_EXISTING
+
+#define MPQ_ERROR_COMPACT_ERROR    0x85300001
+
+// MpqOpenArchiveForUpdate flags
+#define MOAU_CREATE_NEW          0x00 //If archive does not exist, it will be created. If it exists, the function will fail
+#define MOAU_CREATE_ALWAYS       0x08 //Will always create a new archive
+#define MOAU_OPEN_EXISTING       0x04 //If archive exists, it will be opened. If it does not exist, the function will fail
+#define MOAU_OPEN_ALWAYS         0x20 //If archive exists, it will be opened. If it does not exist, it will be created
+#define MOAU_READ_ONLY           0x10 //Must be used with MOAU_OPEN_EXISTING. Archive will be opened without write access
+#define MOAU_MAINTAIN_ATTRIBUTES 0x02 //Will be used in a future version to create the (attributes) file. Contact me about any information you may have about the format of this file
+#define MOAU_MAINTAIN_LISTFILE   0x01 //Creates and maintains a list of files in archive when they are added, replaced, or deleted
+
+// MpqAddFileToArchive flags
+#define MAFA_EXISTS           0x80000000 //This flag will be added if not present
+#define MAFA_UNKNOWN40000000  0x40000000 //Unknown flag
+#define MAFA_MODCRYPTKEY      0x00020000 //Used with MAFA_ENCRYPT. Uses an encryption key based on file position and size
+#define MAFA_ENCRYPT          0x00010000 //Encrypts the file. The file is still accessible when using this, so the use of this has depreciated
+#define MAFA_COMPRESS         0x00000200 //File is to be compressed when added. This is used for most of the compression methods
+#define MAFA_COMPRESS2        0x00000100 //File is compressed with standard compression only (was used in Diablo 1)
+#define MAFA_REPLACE_EXISTING 0x00000001 //If file already exists, it will be replaced
+
+// MpqAddFileToArchiveEx compression flags
+#define MAFA_COMPRESS_STANDARD 0x08 //Standard PKWare DCL compression
+#define MAFA_COMPRESS_DEFLATE  0x02 //ZLib's deflate compression
+#define MAFA_COMPRESS_WAVE     0x81 //Standard wave compression
+#define MAFA_COMPRESS_WAVE2    0x41 //Unused wave compression
+
+// Flags for individual compression types used for wave compression
+#define MAFA_COMPRESS_WAVECOMP1 0x80 //Main compressor for standard wave compression
+#define        MAFA_COMPRESS_WAVECOMP2 0x40 //Main compressor for unused wave compression
+#define MAFA_COMPRESS_WAVECOMP3 0x01 //Secondary compressor for wave compression
+
+// ZLib deflate compression level constants (used with MpqAddFileToArchiveEx and MpqAddFileFromBufferEx)
+#define Z_NO_COMPRESSION         0
+#define Z_BEST_SPEED             1
+#define Z_BEST_COMPRESSION       9
+#define Z_DEFAULT_COMPRESSION  (-1) //Default level is 6 with current ZLib version
+
+// MpqAddWaveToArchive quality flags
+#define MAWA_QUALITY_HIGH    1 //Higher compression, lower quality
+#define MAWA_QUALITY_MEDIUM  0 //Medium compression, medium quality
+#define MAWA_QUALITY_LOW     2 //Lower compression, higher quality
+
+// SFileGetFileInfo flags
+#define SFILE_INFO_BLOCK_SIZE      0x01 //Block size in MPQ
+#define SFILE_INFO_HASH_TABLE_SIZE 0x02 //Hash table size in MPQ
+#define SFILE_INFO_NUM_FILES       0x03 //Number of files in MPQ
+#define SFILE_INFO_TYPE            0x04 //Is MPQHANDLE a file or an MPQ?
+#define SFILE_INFO_SIZE            0x05 //Size of MPQ or uncompressed file
+#define SFILE_INFO_COMPRESSED_SIZE 0x06 //Size of compressed file
+#define SFILE_INFO_FLAGS           0x07 //File flags (compressed, etc.), file attributes if a file not in an archive
+#define SFILE_INFO_PARENT          0x08 //Handle of MPQ that file is in
+#define SFILE_INFO_POSITION        0x09 //Position of file pointer in files
+#define SFILE_INFO_LOCALEID        0x0A //Locale ID of file in MPQ
+#define SFILE_INFO_PRIORITY        0x0B //Priority of open MPQ
+#define SFILE_INFO_HASH_INDEX      0x0C //Hash index of file in MPQ
+
+// Return values of SFileGetFileInfo when SFILE_INFO_TYPE flag is used
+#define SFILE_TYPE_MPQ  0x01
+#define SFILE_TYPE_FILE 0x02
+
+// SFileListFiles flags
+#define SFILE_LIST_MEMORY_LIST  0x01 // Specifies that lpFilelists is a file list from memory, rather than being a list of file lists
+#define SFILE_LIST_ONLY_KNOWN   0x02 // Only list files that the function finds a name for
+#define SFILE_LIST_ONLY_UNKNOWN 0x04 // Only list files that the function does not find a name for
+
+// SFileOpenArchive flags
+#define SFILE_OPEN_HARD_DISK_FILE 0x0000 //Open archive without regard to the drive type it resides on
+#define SFILE_OPEN_CD_ROM_FILE    0x0001 //Open the archive only if it is on a CD-ROM
+#define SFILE_OPEN_ALLOW_WRITE    0x8000 //Open file with write access
+
+// SFileOpenFileEx search scopes
+#define SFILE_SEARCH_CURRENT_ONLY 0x00 //Used with SFileOpenFileEx; only the archive with the handle specified will be searched for the file
+#define SFILE_SEARCH_ALL_OPEN     0x01 //SFileOpenFileEx will look through all open archives for the file. This flag also allows files outside the archive to be used
+
+typedef HANDLE MPQHANDLE;
+
+struct FILELISTENTRY {
+       DWORD dwFileExists; // Nonzero if this entry is used
+       LCID lcLocale; // Locale ID of file
+       DWORD dwCompressedSize; // Compressed size of file
+       DWORD dwFullSize; // Uncompressed size of file
+       DWORD dwFlags; // Flags for file
+       char szFileName[260];
+};
+
+struct MPQARCHIVE;
+struct MPQFILE;
+struct MPQHEADER;
+struct BLOCKTABLEENTRY;
+struct HASHTABLEENTRY;
+
+struct MPQHEADER {
+       DWORD dwMPQID; //"MPQ\x1A" for mpq's, "BN3\x1A" for bncache.dat
+       DWORD dwHeaderSize; // Size of this header
+       DWORD dwMPQSize; //The size of the mpq archive
+       WORD wUnused0C; // Seems to always be 0
+       WORD wBlockSize; // Size of blocks in files equals 512 << wBlockSize
+       DWORD dwHashTableOffset; // Offset to hash table
+       DWORD dwBlockTableOffset; // Offset to block table
+       DWORD dwHashTableSize; // Number of entries in hash table
+       DWORD dwBlockTableSize; // Number of entries in block table
+};
+
+//Archive handles may be typecasted to this struct so you can access
+//some of the archive's properties and the decrypted hash table and
+//block table directly.  This struct is based on Storm's internal
+//struct for archive handles.
+struct MPQARCHIVE {
+       // Arranged according to priority with lowest priority first
+       MPQARCHIVE * lpNextArc; //0// Pointer to the next MPQARCHIVE struct. Pointer to addresses of first and last archives if last archive
+       MPQARCHIVE * lpPrevArc; //4// Pointer to the previous MPQARCHIVE struct. 0xEAFC5E23 if first archive
+       char szFileName[260]; //8// Filename of the archive
+       HANDLE hFile; //10C// The archive's file handle
+       DWORD dwFlags1; //110// Some flags, bit 0 seems to be set when opening an archive from a hard drive if bit 1 in the flags for SFileOpenArchive is set, bit 1 (0 based) seems to be set when opening an archive from a CD
+       DWORD dwPriority; //114// Priority of the archive set when calling SFileOpenArchive
+       MPQFILE * lpLastReadFile; //118// Pointer to the last read file's MPQFILE struct. This is cleared when finished reading a block
+       DWORD dwUnk; //11C// Seems to always be 0
+       DWORD dwBlockSize; //120// Size of file blocks in bytes
+       BYTE * lpLastReadBlock; //124// Pointer to the read buffer for archive. This is cleared when finished reading a block
+       DWORD dwBufferSize; //128// Size of the read buffer for archive. This is cleared when finished reading a block
+       DWORD dwMPQStart; //12C// The starting offset of the archive
+       DWORD dwMPQEnd; //130// The ending offset of the archive
+       MPQHEADER * lpMPQHeader; //134// Pointer to the archive header
+       BLOCKTABLEENTRY * lpBlockTable; //138// Pointer to the start of the block table
+       HASHTABLEENTRY * lpHashTable; //13C// Pointer to the start of the hash table
+       DWORD dwReadOffset; //140// Offset to the data for a file
+       DWORD dwRefCount; //144// Count of references to this open archive.  This is incremented for each file opened from the archive, and decremented for each file closed
+       // Extra struct members used by SFmpq
+       MPQHEADER MpqHeader;
+       DWORD dwFlags; //The only flags that should be changed are MOAU_MAINTAIN_LISTFILE and MOAU_MAINTAIN_ATTRIBUTES, changing any others can have unpredictable effects
+       LPSTR lpFileName;
+       DWORD dwExtraFlags;
+};
+
+//Handles to files in the archive may be typecasted to this struct
+//so you can access some of the file's properties directly.  This
+//struct is based on Storm's internal struct for file handles.
+struct MPQFILE {
+       MPQFILE * lpNextFile; //0// Pointer to the next MPQFILE struct. Pointer to addresses of first and last files if last file
+       MPQFILE * lpPrevFile; //4// Pointer to the previous MPQFILE struct. 0xEAFC5E13 if first file
+       char szFileName[260]; //8// Filename of the file
+       HANDLE hFile; //10C// Always INVALID_HANDLE_VALUE for files in MPQ archives. For files not in MPQ archives, this is the file handle for the file and the rest of this struct is filled with zeros except for dwRefCount
+       MPQARCHIVE * lpParentArc; //110// Pointer to the MPQARCHIVE struct of the archive in which the file is contained
+       BLOCKTABLEENTRY * lpBlockEntry; //114// Pointer to the file's block table entry
+       DWORD dwCryptKey; //118// Decryption key for the file
+       DWORD dwFilePointer; //11C// Position of file pointer in the file
+       DWORD dwUnk; //120// Seems to always be 0
+       DWORD dwBlockCount; //124// Number of blocks in file
+       DWORD * lpdwBlockOffsets; //128// Offsets to blocks in file. There are 1 more of these than the number of blocks. The values for this are set after the first read
+       DWORD dwReadStarted; //12C// Set to 1 after first read
+       BOOL bStreaming; //130// 1 when streaming a WAVE
+       BYTE * lpLastReadBlock; //134// Pointer to the read buffer for file. This starts at the position specified in the last SFileSetFilePointer call. This is cleared when SFileSetFilePointer is called or when finished reading the block
+       DWORD dwBytesRead; //138// Total bytes read from the current block in the open file. This is cleared when SFileSetFilePointer is called or when finished reading the block
+       DWORD dwBufferSize; //13C// Size of the read buffer for file. This is cleared when SFileSetFilePointer is called or when finished reading the block
+       DWORD dwRefCount; //140// Count of references to this open file
+       // Extra struct members used by SFmpq
+       HASHTABLEENTRY *lpHashEntry;
+       LPSTR lpFileName;
+};
+
+struct BLOCKTABLEENTRY {
+       DWORD dwFileOffset; // Offset to file
+       DWORD dwCompressedSize; // Compressed size of file
+       DWORD dwFullSize; // Uncompressed size of file
+       DWORD dwFlags; // Flags for file
+};
+
+struct HASHTABLEENTRY {
+       DWORD dwNameHashA; // First name hash of file
+       DWORD dwNameHashB; // Second name hash of file
+       LCID lcLocale; // Locale ID of file
+       DWORD dwBlockTableIndex; // Index to the block table entry for the file
+};
+
+// Defines for backward compatibility with old lmpqapi function names
+#define MpqAddFileToArcive MpqAddFileToArchive
+#define MpqOpenArchive     SFileOpenArchive
+#define MpqOpenFileEx      SFileOpenFileEx
+#define MpqGetFileSize     SFileGetFileSize
+#define MpqReadFile        SFileReadFile
+#define MpqCloseFile       SFileCloseFile
+#define MpqCloseArchive    SFileCloseArchive
+
+// Storm functions implemented by this library
+extern BOOL      (WINAPI* SFileOpenArchive)(LPCSTR lpFileName, DWORD dwPriority, DWORD dwFlags, MPQHANDLE *hMPQ);
+extern BOOL      (WINAPI* SFileCloseArchive)(MPQHANDLE hMPQ);
+extern BOOL      (WINAPI* SFileOpenFileAsArchive)(MPQHANDLE hSourceMPQ, LPCSTR lpFileName, DWORD dwPriority, DWORD dwFlags, MPQHANDLE *hMPQ);
+extern BOOL      (WINAPI* SFileGetArchiveName)(MPQHANDLE hMPQ, LPCSTR lpBuffer, DWORD dwBufferLength);
+extern BOOL      (WINAPI* SFileOpenFile)(LPCSTR lpFileName, MPQHANDLE *hFile);
+extern BOOL      (WINAPI* SFileOpenFileEx)(MPQHANDLE hMPQ, LPCSTR lpFileName, DWORD dwSearchScope, MPQHANDLE *hFile);
+extern BOOL      (WINAPI* SFileCloseFile)(MPQHANDLE hFile);
+extern DWORD     (WINAPI* SFileGetFileSize)(MPQHANDLE hFile, LPDWORD lpFileSizeHigh);
+extern BOOL      (WINAPI* SFileGetFileArchive)(MPQHANDLE hFile, MPQHANDLE *hMPQ);
+extern BOOL      (WINAPI* SFileGetFileName)(MPQHANDLE hFile, LPCSTR lpBuffer, DWORD dwBufferLength);
+extern DWORD     (WINAPI* SFileSetFilePointer)(MPQHANDLE hFile, long lDistanceToMove, PLONG lplDistanceToMoveHigh, DWORD dwMoveMethod);
+extern BOOL      (WINAPI* SFileReadFile)(MPQHANDLE hFile,LPVOID lpBuffer,DWORD nNumberOfBytesToRead,LPDWORD lpNumberOfBytesRead,LPOVERLAPPED lpOverlapped);
+extern LCID      (WINAPI* SFileSetLocale)(LCID nNewLocale);
+extern BOOL      (WINAPI* SFileGetBasePath)(LPCSTR lpBuffer, DWORD dwBufferLength);
+extern BOOL      (WINAPI* SFileSetBasePath)(LPCSTR lpNewBasePath);
+
+// Extra storm-related functions
+extern DWORD     (WINAPI* SFileGetFileInfo)(MPQHANDLE hFile, DWORD dwInfoType);
+extern BOOL      (WINAPI* SFileSetArchivePriority)(MPQHANDLE hMPQ, DWORD dwPriority);
+extern DWORD     (WINAPI* SFileFindMpqHeader)(HANDLE hFile);
+extern BOOL      (WINAPI* SFileListFiles)(MPQHANDLE hMPQ, LPCSTR lpFileLists, FILELISTENTRY *lpListBuffer, DWORD dwFlags);
+
+// Archive editing functions implemented by this library
+extern MPQHANDLE (WINAPI* MpqOpenArchiveForUpdate)(LPCSTR lpFileName, DWORD dwFlags, DWORD dwMaximumFilesInArchive);
+extern DWORD     (WINAPI* MpqCloseUpdatedArchive)(MPQHANDLE hMPQ, DWORD dwUnknown2);
+extern BOOL      (WINAPI* MpqAddFileToArchive)(MPQHANDLE hMPQ, LPCSTR lpSourceFileName, LPCSTR lpDestFileName, DWORD dwFlags);
+extern BOOL      (WINAPI* MpqAddWaveToArchive)(MPQHANDLE hMPQ, LPCSTR lpSourceFileName, LPCSTR lpDestFileName, DWORD dwFlags, DWORD dwQuality);
+extern BOOL      (WINAPI* MpqRenameFile)(MPQHANDLE hMPQ, LPCSTR lpcOldFileName, LPCSTR lpcNewFileName);
+extern BOOL      (WINAPI* MpqDeleteFile)(MPQHANDLE hMPQ, LPCSTR lpFileName);
+extern BOOL      (WINAPI* MpqCompactArchive)(MPQHANDLE hMPQ);
+
+// Extra archive editing functions
+extern BOOL      (WINAPI* MpqAddFileToArchiveEx)(MPQHANDLE hMPQ, LPCSTR lpSourceFileName, LPCSTR lpDestFileName, DWORD dwFlags, DWORD dwCompressionType, DWORD dwCompressLevel);
+extern BOOL      (WINAPI* MpqAddFileFromBufferEx)(MPQHANDLE hMPQ, LPVOID lpBuffer, DWORD dwLength, LPCSTR lpFileName, DWORD dwFlags, DWORD dwCompressionType, DWORD dwCompressLevel);
+extern BOOL      (WINAPI* MpqAddFileFromBuffer)(MPQHANDLE hMPQ, LPVOID lpBuffer, DWORD dwLength, LPCSTR lpFileName, DWORD dwFlags);
+extern BOOL      (WINAPI* MpqAddWaveFromBuffer)(MPQHANDLE hMPQ, LPVOID lpBuffer, DWORD dwLength, LPCSTR lpFileName, DWORD dwFlags, DWORD dwQuality);
+extern BOOL      (WINAPI* MpqRenameAndSetFileLocale)(MPQHANDLE hMPQ, LPCSTR lpcOldFileName, LPCSTR lpcNewFileName, LCID nOldLocale, LCID nNewLocale);
+extern BOOL      (WINAPI* MpqDeleteFileWithLocale)(MPQHANDLE hMPQ, LPCSTR lpFileName, LCID nLocale);
+extern BOOL      (WINAPI* MpqSetFileLocale)(MPQHANDLE hMPQ, LPCSTR lpFileName, LCID nOldLocale, LCID nNewLocale);
+
+// These functions do nothing.  They are only provided for
+// compatibility with MPQ extractors that use storm.
+extern BOOL      (WINAPI* SFileDestroy)();
+extern void      (WINAPI* StormDestroy)();
+
+#ifdef __cplusplus
+};  // extern "C" 
+#endif
+
+#endif
+
diff --git a/SFmpqlib.dsp b/SFmpqlib.dsp
new file mode 100644 (file)
index 0000000..f2a9953
--- /dev/null
@@ -0,0 +1,164 @@
+# Microsoft Developer Studio Project File - Name="SFmpqlib" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Static Library" 0x0104
+
+CFG=SFmpqlib - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE 
+!MESSAGE NMAKE /f "SFmpqlib.mak".
+!MESSAGE 
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE 
+!MESSAGE NMAKE /f "SFmpqlib.mak" CFG="SFmpqlib - Win32 Debug"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "SFmpqlib - Win32 Release" (based on "Win32 (x86) Static Library")
+!MESSAGE "SFmpqlib - Win32 Debug" (based on "Win32 (x86) Static Library")
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF  "$(CFG)" == "SFmpqlib - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "SFmpqlib___Win32_Release"
+# PROP BASE Intermediate_Dir "SFmpqlib___Win32_Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "SFmpqlib___Win32_Release"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c
+# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_LIB" /D "SFMPQ_STATIC" /D "ZLIB_DLL" /YX /FD /c
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo /out:"Release\SFmpq_static.lib"
+
+!ELSEIF  "$(CFG)" == "SFmpqlib - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "SFmpqlib___Win32_Debug"
+# PROP BASE Intermediate_Dir "SFmpqlib___Win32_Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "SFmpqlib___Win32_Debug"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c
+# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_LIB" /D "SFMPQ_STATIC" /D "ZLIB_DLL" /YX /FD /GZ /c
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo /out:"Debug\SFmpq_static.lib"
+
+!ENDIF 
+
+# Begin Target
+
+# Name "SFmpqlib - Win32 Release"
+# Name "SFmpqlib - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=..\SComp\explode.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\SComp\huffman.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\SComp\implode.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\SComp\SComp.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\SComp\SErr.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\SFmpq_static.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\SFmpqapi.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\SComp\SMem.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\SComp\wave.cpp
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# Begin Source File
+
+SOURCE=..\SComp\Huffman.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\SComp\pklib.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\SComp\SComp.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\SComp\SErr.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\SFmpq_static.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\SFmpqapi.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\SComp\SMem.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\SComp\wave.h
+# End Source File
+# End Group
+# Begin Source File
+
+SOURCE=..\SComp\ZLib_Static_min.lib
+# End Source File
+# End Target
+# End Project
diff --git a/WinError.bas b/WinError.bas
new file mode 100644 (file)
index 0000000..42fac2c
--- /dev/null
@@ -0,0 +1,18 @@
+Attribute VB_Name = "WinError"
+Option Explicit
+
+' GetLastError and the constants for the values returned by it
+' (only the ones known to be used by Storm or Lmpqapi are included)
+
+Declare Function GetLastError Lib "Kernel32" () As Long
+
+Public Const ERROR_SUCCESS           As Long = 0
+Public Const NO_ERROR                As Long = 0
+Public Const ERROR_FILE_NOT_FOUND    As Long = 2
+Public Const ERROR_OUTOFMEMORY       As Long = 14
+Public Const ERROR_INVALID_PARAMETER As Long = 87
+Public Const ERROR_DISK_FULL         As Long = 112
+Public Const ERROR_ALREADY_EXISTS    As Long = 183
+Public Const ERROR_FILE_INVALID      As Long = 1006
+Public Const ERROR_UNKNOWN_PROPERTY  As Long = 1608
+
diff --git a/about b/about
new file mode 100644 (file)
index 0000000..4e77830
--- /dev/null
+++ b/about
@@ -0,0 +1,154 @@
+<html>
+<title>About ShadowFlare MPQ API Library</title>
+<pre>  ShadowFlare MPQ API Library v1.08 (c) ShadowFlare Software 2002-2008
+
+  This library emulates the interface of Lmpqapi and Storm MPQ
+  functions, so it may be used as a replacement for them in
+  MPQ extractors/archivers without even needing to recompile
+  the program that uses Lmpqapi or Storm.  It has a few features
+  not included in Lmpqapi and Storm, such as extra flags for some
+  functions, setting the locale ID of existing files, and adding
+  files without having to write them somewhere else first.  Also,
+  MPQ handles used by functions prefixed with "SFile" and "Mpq"
+  can be used interchangably; all functions use the same type
+  of MPQ handles.  You cannot, however, use handles from this
+  library with storm or lmpqapi or vice-versa.  Doing so will
+  most likely result in a crash.
+
+  This library does not require Storm to be able to decompress
+  or compress files.
+
+  Revision History:
+  (Release date) 1.08 (<a href="mailto:blakflare@hotmail.com">ShadowFlare</a>)
+  - Fixed a buffer overflow that would occur when reading files
+    if neither using a buffer that is large enough to contain the
+    entire file nor has a size that is a multiple of 4096
+  - Added SFileOpenFileAsArchive which opens an archive that is
+    contained within an already open archive
+  - Added MpqRenameAndSetFileLocale and MpqDeleteFileWithLocale.
+    These have extra parameters that allow you to use them with
+    files having language codes other than what was last set
+    using SFileSetLocale
+  - Fixed a bug that caused (listfile) to get cleared if adding
+    files with a locale ID other than 0
+  - Added MpqOpenArchiveForUpdateEx which allows creating
+    archives with different block sizes
+  - SFileListFiles can list the contents of bncache.dat without
+    needing an external list
+
+  06/12/2002 1.07 (<a href="mailto:blakflare@hotmail.com">ShadowFlare</a>)
+  - No longer requires Storm.dll to compress or decompress
+    Warcraft III files
+  - Added SFileListFiles for getting names and information
+    about all of the files in an archive
+  - Fixed a bug with renaming and deleting files
+  - Fixed a bug with adding wave compressed files with
+    low compression setting
+  - Added a check in MpqOpenArchiveForUpdate for proper
+    dwMaximumFilesInArchive values (should be a number that
+    is a power of 2).  If it is not a proper value, it will
+    be rounded up to the next higher power of 2
+
+  05/09/2002 1.06 (<a href="mailto:blakflare@hotmail.com">ShadowFlare</a>)
+  - Compresses files without Storm.dll!
+  - If Warcraft III is installed, this library will be able to
+    find Storm.dll on its own. (Storm.dll is needed to
+    decompress Warcraft III files)
+  - Fixed a bug where an embedded archive and the file that
+    contains it would be corrupted if the archive was modified
+  - Able to open all .w3m maps now
+
+  29/06/2002 1.05 (<a href="mailto:blakflare@hotmail.com">ShadowFlare</a>)
+  - Supports decompressing files from Warcraft III MPQ archives
+    if using Storm.dll from Warcraft III
+  - Added MpqAddFileToArchiveEx and MpqAddFileFromBufferEx for
+    using extra compression types
+
+  29/05/2002 1.04 (<a href="mailto:blakflare@hotmail.com">ShadowFlare</a>)
+  - Files can be compressed now!
+  - Fixed a bug in SFileReadFile when reading data not aligned
+    to the block size
+  - Optimized some of SFileReadFile's code.  It can read files
+    faster now
+  - SFile functions may now be used to access files not in mpq
+    archives as you can with the real storm functions
+  - MpqCompactArchive will no longer corrupt files with the
+    MODCRYPTKEY flag as long as the file is either compressed,
+    listed in "(listfile)", is "(listfile)", or is located in
+    the same place in the compacted archive; so it is safe
+    enough to use it on almost any archive
+  - Added MpqAddWaveFromBuffer
+  - Better handling of archives with no files
+  - Fixed compression with COMPRESS2 flag
+
+  15/05/2002 1.03 (<a href="mailto:blakflare@hotmail.com">ShadowFlare</a>)
+  - Supports adding files with the compression attribute (does
+    not actually compress files).  Now archives created with
+    this dll can have files added to them through lmpqapi
+    without causing staredit to crash
+  - SFileGetBasePath and SFileSetBasePath work more like their
+    Storm equivalents now
+  - Implemented MpqCompactArchive, but it is not finished yet.
+    In its current state, I would recommend against using it
+    on archives that contain files with the MODCRYPTKEY flag,
+    since it will corrupt any files with that flag
+  - Added SFMpqGetVersionString2 which may be used in Visual
+    Basic to get the version string
+
+  07/05/2002 1.02 (<a href="mailto:blakflare@hotmail.com">ShadowFlare</a>)
+  - SFileReadFile no longer passes the lpOverlapped parameter it
+    receives to ReadFile.  This is what was causing the function
+    to fail when used in Visual Basic
+  - Added support for more Storm MPQ functions
+  - GetLastError may now be used to get information about why a
+    function failed
+
+  01/05/2002 1.01 (<a href="mailto:blakflare@hotmail.com">ShadowFlare</a>)
+  - Added ordinals for Storm MPQ functions
+  - Fixed MPQ searching functionality of SFileOpenFileEx
+  - Added a check for whether a valid handle is given when
+    SFileCloseArchive is called
+  - Fixed functionality of SFileSetArchivePriority when multiple
+    files are open
+  - File renaming works for all filenames now
+  - SFileReadFile no longer reallocates the buffer for each block
+    that is decompressed.  This should make SFileReadFile at least
+    a little faster
+
+  30/04/2002 1.00 (<a href="mailto:blakflare@hotmail.com">ShadowFlare</a>)
+  - First version.
+  - Compression not yet supported
+  - Does not use SetLastError yet, so GetLastError will not return any
+    errors that have to do with this library
+  - MpqCompactArchive not implemented
+
+  Any comments or suggestions are accepted at <a href="mailto:blakflare@hotmail.com">blakflare@hotmail.com</a> (ShadowFlare)
+  Download the newest version from ShadowFlare's Realm at <a href="http://sfsrealm.hopto.org/">http://sfsrealm.hopto.org/</a>
+
+  License information:
+
+  Copyright (c) 2002-2008, ShadowFlare &lt;<a href="mailto:blakflare@hotmail.com">blakflare@hotmail.com</a>&gt;
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions
+  are met:
+
+  1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+  2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in the
+     documentation and/or other materials provided with the distribution.
+
+  THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND
+  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+  ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+  OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+  OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+  SUCH DAMAGE.</pre>
+</html>
diff --git a/license.txt b/license.txt
new file mode 100644 (file)
index 0000000..94d5ecb
--- /dev/null
@@ -0,0 +1,24 @@
+Copyright (c) 2002-2008, ShadowFlare <blakflare@hotmail.com>
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
\ No newline at end of file
diff --git a/linux/windows.cpp b/linux/windows.cpp
new file mode 100644 (file)
index 0000000..e9329e2
--- /dev/null
@@ -0,0 +1,198 @@
+/* License information for this code is in license.txt */
+
+#include "windows.h"
+
+DWORD dwAppLastError=0;
+
+void WINAPI SetLastError(DWORD dwLastError)
+{
+       dwAppLastError=dwLastError;
+}
+
+DWORD WINAPI GetLastError()
+{
+       return dwAppLastError;
+}
+
+DWORD WINAPI GetCurrentDirectory(DWORD dwBufferLength, LPSTR lpBuffer)
+{
+       if (lpBuffer==0) return 0;
+       strncpy(lpBuffer,"./",dwBufferLength);
+       return strlen(lpBuffer)+1;
+}
+
+DWORD WINAPI GetDriveType(LPCSTR lpRootPath)
+{
+       return DRIVE_FIXED;
+}
+
+HANDLE WINAPI CreateFile(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile)
+{
+       if (lpFileName==0) return INVALID_HANDLE_VALUE;
+       int nFlags,hFile;
+       if ((dwDesiredAccess&GENERIC_READ && dwDesiredAccess&GENERIC_WRITE) || dwDesiredAccess&GENERIC_ALL) {
+               nFlags = O_RDWR;
+       }
+       else if (dwDesiredAccess&GENERIC_READ) {
+               nFlags = O_RDONLY;
+       }
+       else if (dwDesiredAccess&GENERIC_WRITE) {
+               nFlags = O_WRONLY;
+       }
+       else {
+               nFlags = 0;
+
+       }
+       switch (dwCreationDisposition) {
+               case CREATE_NEW:
+                       hFile = open(lpFileName,0);
+                       if (hFile!=-1) {close(hFile);return INVALID_HANDLE_VALUE;}
+                       nFlags |= O_CREAT;
+                       break;
+               case CREATE_ALWAYS:
+                       nFlags |= O_CREAT|O_TRUNC;
+                       break;
+               case OPEN_EXISTING:
+                       break;
+               case OPEN_ALWAYS:
+                       hFile = open(lpFileName,0);
+                       if (hFile==-1) nFlags |= O_CREAT;
+                       else close(hFile);
+                       break;
+               case TRUNCATE_EXISTING:
+                       nFlags |= O_TRUNC;
+                       break;
+               default:
+                       return INVALID_HANDLE_VALUE;
+       }
+       hFile = open(lpFileName,nFlags);
+       if (hFile!=-1) chmod(lpFileName,0644);
+       return (HANDLE)hFile;
+}
+
+BOOL WINAPI CloseHandle(HANDLE hObject)
+{
+       if (hObject==INVALID_HANDLE_VALUE) return 0;
+       return (BOOL)(close((int)hObject) == 0);
+}
+
+DWORD WINAPI GetFileSize(HANDLE hFile, LPDWORD lpFileSizeHigh)
+{
+       if (hFile==INVALID_HANDLE_VALUE) return (DWORD)-1;
+
+       struct stat fileinfo;
+       fstat((int)hFile, &fileinfo);
+
+       if (lpFileSizeHigh) *lpFileSizeHigh = 0;
+       return (DWORD)fileinfo.st_size;
+}
+
+DWORD WINAPI SetFilePointer(HANDLE hFile, LONG lDistanceToMove, PLONG lpDistanceToMoveHigh, DWORD dwMoveMethod)
+{
+       if (hFile==INVALID_HANDLE_VALUE) return (DWORD)-1;
+
+       switch (dwMoveMethod) {
+               case FILE_BEGIN:
+                       return (DWORD)lseek((int)hFile, lDistanceToMove, SEEK_SET);
+               case FILE_CURRENT:
+                       return (DWORD)lseek((int)hFile, lDistanceToMove, SEEK_CUR);
+               case FILE_END:
+                       return (DWORD)lseek((int)hFile, lDistanceToMove, SEEK_END);
+       }
+       return (DWORD)-1;
+}
+
+BOOL WINAPI SetEndOfFile(HANDLE hFile)
+{
+       if (hFile==INVALID_HANDLE_VALUE) return 0;
+
+       return (BOOL)(ftruncate((int)hFile, lseek((int)hFile, 0, SEEK_CUR)) == 0);
+}
+
+BOOL WINAPI ReadFile(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped)
+{
+       if (hFile==INVALID_HANDLE_VALUE || lpBuffer==0) return 0;
+
+       ssize_t count;
+       if ((count = read((int)hFile, lpBuffer, nNumberOfBytesToRead)) == -1) {
+               if (lpNumberOfBytesRead) *lpNumberOfBytesRead = 0;
+               return FALSE;
+       }
+       if (lpNumberOfBytesRead) *lpNumberOfBytesRead = count;
+       return TRUE;
+}
+
+BOOL WINAPI WriteFile(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped)
+{
+       if (hFile==INVALID_HANDLE_VALUE || lpBuffer==0) return 0;
+
+       ssize_t count;
+       if ((count = write((int)hFile, lpBuffer, nNumberOfBytesToWrite)) == -1) {
+               if (lpNumberOfBytesWritten) *lpNumberOfBytesWritten = 0;
+               return FALSE;
+       }
+       if (lpNumberOfBytesWritten) *lpNumberOfBytesWritten = count;
+       return TRUE;
+}
+
+BOOL WINAPI DeleteFile(LPCSTR lpFileName)
+{
+       if (lpFileName==0) return FALSE;
+       return (BOOL)(unlink(lpFileName) == 0);
+}
+
+char * strlwr(char *lpString)
+{
+       if (lpString==0) return 0;
+       for (char *lpChar=lpString;lpChar[0]==0;lpChar++)
+               lpChar[0] = tolower(lpChar[0]);
+       return lpString;
+}
+
+char * strupr(char *lpString)
+{
+       if (lpString==0) return 0;
+       for (char *lpChar=lpString;lpChar[0]==0;lpChar++)
+               lpChar[0] = toupper(lpChar[0]);
+       return lpString;
+}
+
+char * strdup(const char *lpString)
+{
+       if (lpString==0) return 0;
+       char *lpStrCopy = (char *)malloc(strlen(lpString)+1);
+       if (lpStrCopy==0) return 0;
+       strcpy(lpStrCopy,lpString);
+       return lpStrCopy;
+}
+
+int memicmp(const char *lpString1, const char *lpString2, size_t dwSize)
+{
+       if (lpString1==0) return -1;
+       if (lpString2==0) return 1;
+       if (dwSize==0) return 0;
+       size_t i;
+       char ch1,ch2;
+       for (i=0;i<dwSize;i++) {
+               ch1 = toupper(lpString1[i]);
+               ch2 = toupper(lpString2[i]);
+               if (ch1 > ch2) return 1;
+               else if (ch1 < ch2) return -1;
+       }
+       return 0;
+}
+
+void SlashToBackslash(char *lpPath)
+{
+       if (lpPath==0) return;
+       for (;lpPath[0]!=0;lpPath++)
+               if (lpPath[0]=='/') lpPath[0]='\\';
+}
+
+void BackslashToSlash(char *lpPath)
+{
+       if (lpPath==0) return;
+       for (;lpPath[0]!=0;lpPath++)
+               if (lpPath[0]=='\\') lpPath[0]='/';
+}
+
diff --git a/linux/windows.h b/linux/windows.h
new file mode 100644 (file)
index 0000000..24f53ca
--- /dev/null
@@ -0,0 +1,155 @@
+/* License information for this code is in license.txt */
+
+#ifndef WINDOWS_H_INCLUDED
+#define WINDOWS_H_INCLUDED
+
+#include <malloc.h>
+#include <string.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/stat.h>
+
+#define LINUX_PORT
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Function related defines
+#define __cdecl
+#define __stdcall
+#define WINAPI __stdcall
+#define APIENTRY __stdcall
+#define __declspec(dllimport)
+#define __declspec(dllexport)
+#define __inline inline
+#define __forceinline inline
+
+#define CONST const
+
+// Type defines
+typedef unsigned char BYTE;
+typedef unsigned short int WORD;
+typedef unsigned long int DWORD;
+typedef short int SHORT;
+typedef unsigned short int USHORT;
+typedef DWORD LCID;
+typedef long int LONG;
+typedef LONG * PLONG;
+typedef int BOOL;
+typedef void * LPVOID;
+typedef CONST void *LPCVOID;
+typedef char CHAR;
+typedef char * LPSTR;
+typedef const char * LPCSTR;
+typedef DWORD * LPDWORD;
+typedef BYTE * LPBYTE;
+typedef LPVOID HANDLE;
+typedef HANDLE HINSTANCE;
+
+// Structs
+typedef struct _OVERLAPPED {
+       DWORD  Internal;
+       DWORD  InternalHigh;
+       DWORD  Offset;
+       DWORD  OffsetHigh;
+       HANDLE hEvent;
+} OVERLAPPED, *LPOVERLAPPED;
+typedef struct _SECURITY_ATTRIBUTES {
+       DWORD nLength;
+       LPVOID lpSecurityDescriptor;
+       BOOL bInheritHandle;
+} SECURITY_ATTRIBUTES, *PSECURITY_ATTRIBUTES, *LPSECURITY_ATTRIBUTES;
+
+// Constants
+#define FALSE 0
+#define TRUE 1
+#define MAX_PATH 260
+#define INVALID_HANDLE_VALUE ((HANDLE)-1)
+#define DLL_PROCESS_ATTACH 1
+#define DLL_THREAD_ATTACH  2
+#define DLL_THREAD_DETACH  3
+#define DLL_PROCESS_DETACH 0
+#define PAGE_NOACCESS          0x01
+#define PAGE_READONLY          0x02
+#define PAGE_READWRITE         0x04
+#define PAGE_WRITECOPY         0x08
+#define PAGE_EXECUTE           0x10
+#define PAGE_EXECUTE_READ      0x20
+#define PAGE_EXECUTE_READWRITE 0x40
+#define PAGE_EXECUTE_WRITECOPY 0x80
+#define PAGE_GUARD            0x100
+#define PAGE_NOCACHE          0x200
+#define PAGE_WRITECOMBINE     0x400
+#define MEM_COMMIT           0x1000
+#define MEM_RESERVE          0x2000
+#define MEM_DECOMMIT         0x4000
+#define MEM_RELEASE          0x8000
+#define MEM_FREE            0x10000
+#define MEM_PRIVATE         0x20000
+#define MEM_MAPPED          0x40000
+#define MEM_RESET           0x80000
+#define MEM_TOP_DOWN       0x100000
+#define MEM_4MB_PAGES    0x80000000
+#define DRIVE_UNKNOWN     0
+#define DRIVE_NO_ROOT_DIR 1
+#define DRIVE_REMOVABLE   2
+#define DRIVE_FIXED       3
+#define DRIVE_REMOTE      4
+#define DRIVE_CDROM       5
+#define DRIVE_RAMDISK     6
+#define GENERIC_READ                     (0x80000000L)
+#define GENERIC_WRITE                    (0x40000000L)
+#define GENERIC_EXECUTE                  (0x20000000L)
+#define GENERIC_ALL                      (0x10000000L)
+#define FILE_SHARE_READ                 0x00000001
+#define FILE_SHARE_WRITE                0x00000002
+#define FILE_SHARE_DELETE               0x00000004
+#define CREATE_NEW          1
+#define CREATE_ALWAYS       2
+#define OPEN_EXISTING       3
+#define OPEN_ALWAYS         4
+#define TRUNCATE_EXISTING   5
+#define FILE_BEGIN           0
+#define FILE_CURRENT         1
+#define FILE_END             2
+#define ERROR_FILE_NOT_FOUND             2L
+#define ERROR_ACCESS_DENIED              5L
+#define ERROR_INVALID_PARAMETER          87L    // dderror
+#define ERROR_ALREADY_EXISTS             183L
+#define ERROR_FILE_INVALID               1006L
+#define ERROR_UNKNOWN_PROPERTY           1608L
+
+// Declarations for Windows API functions
+void WINAPI SetLastError(DWORD dwLastError);
+DWORD WINAPI GetLastError();
+DWORD WINAPI GetCurrentDirectory(DWORD dwBufferLength, LPSTR lpBuffer);
+DWORD WINAPI GetDriveType(LPCSTR lpRootPath);
+HANDLE WINAPI CreateFile(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile);
+BOOL WINAPI CloseHandle(HANDLE hObject);
+DWORD WINAPI GetFileSize(HANDLE hFile, LPDWORD lpFileSizeHigh);
+DWORD WINAPI SetFilePointer(HANDLE hFile, LONG lDistanceToMove, PLONG lpDistanceToMoveHigh, DWORD dwMoveMethod);
+BOOL WINAPI SetEndOfFile(HANDLE hFile);
+BOOL WINAPI ReadFile(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped);
+BOOL WINAPI WriteFile(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped);
+BOOL WINAPI DeleteFile(LPCSTR lpFileName);
+
+// Declarations for C runtime functions
+char * strlwr(char *lpString);
+char * strupr(char *lpString);
+char * strdup(const char *lpString);
+#define stricmp strcasecmp
+#define strnicmp strncasecmp
+int memicmp(const char *lpString1, const char *lpString2, size_t dwSize);
+
+// Other functions
+void SlashToBackslash(char *lpPath);
+void BackslashToSlash(char *lpPath);
+
+#ifdef __cplusplus
+};  // extern "C"
+#endif
+
+#endif
+
diff --git a/resource.h b/resource.h
new file mode 100644 (file)
index 0000000..671fd1e
--- /dev/null
@@ -0,0 +1,17 @@
+/* License information for this code is in license.txt */
+
+//{{NO_DEPENDENCIES}}
+// Microsoft Developer Studio generated include file.
+// Used by SFmpqapi.rc
+//
+
+// Next default values for new objects
+// 
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE        105
+#define _APS_NEXT_COMMAND_VALUE         40001
+#define _APS_NEXT_CONTROL_VALUE         1000
+#define _APS_NEXT_SYMED_VALUE           101
+#endif
+#endif