• Welcome to Valhalla Legends Archive.
 

Extracting MoPaQs with Storm.dll

Started by brew, March 24, 2008, 08:10 PM

Previous topic - Next topic

brew

The following code works just fine when extracting anything from starcraft maps, but SFileOpenArchive seems to fail when trying to extract anything else (for example, ExtraWork dlls, unless they don't have (listfile)s) and files within internal directories. Can anyone see what seems to be the problem?

void ExtractMPQ(char *filename, char *toget) {
HMODULE hLibStorm = LoadLibrary("Storm.dll");
FILE *file;
char *asdf;
unsigned long hMPQ, hMPQFile, filesize, highdword;
unsigned long SFileDestroy      = (unsigned long)GetProcAddress(hLibStorm, MAKEINTRESOURCE(262));
unsigned long SFileSetLocale    = (unsigned long)GetProcAddress(hLibStorm, MAKEINTRESOURCE(272));
unsigned long SFileOpenArchive  = (unsigned long)GetProcAddress(hLibStorm, MAKEINTRESOURCE(266));
unsigned long SFileOpenFileEx   = (unsigned long)GetProcAddress(hLibStorm, MAKEINTRESOURCE(268));
unsigned long SFileGetFileSize  = (unsigned long)GetProcAddress(hLibStorm, MAKEINTRESOURCE(265));
unsigned long SFileReadFile     = (unsigned long)GetProcAddress(hLibStorm, MAKEINTRESOURCE(269));
unsigned long SFileCloseFile    = (unsigned long)GetProcAddress(hLibStorm, MAKEINTRESOURCE(253));
unsigned long SFileCloseArchive = (unsigned long)GetProcAddress(hLibStorm, MAKEINTRESOURCE(252));
__asm {
push 'enUS'
call SFileSetLocale
test eax, eax
jz errored

call SFileDestroy
test eax, eax
jz errored

lea eax, [hMPQ]
push eax
push 0
push 0
mov eax, filename
push eax
call SFileOpenArchive
test eax, eax
jz errored

lea eax, [hMPQFile]
push eax
push 0
push toget
push hMPQ
call SFileOpenFileEx
test eax, eax
jz errored

lea eax, [highdword]
push eax
push hMPQFile
call SFileGetFileSize
mov filesize, eax
cmp eax, -1
je errored

push eax
call malloc
pop ecx
mov asdf, eax

push 0
push 0
push filesize
push eax
push hMPQFile
call SFileReadFile
test eax, eax
jz errored

push '\\'
push toget
call strchr
add esp, 8
mov ecx, toget
test eax, eax
jz over
mov ecx, eax
inc ecx

over:

mov highdword, 'bw'
lea eax, [highdword]
push eax
push ecx
call fopen
mov file, eax
add esp, 8

push eax
push filesize
push 1
push asdf
call fwrite
add esp, 10h

push file
call fclose
pop ecx

push asdf
call free
pop ecx

push hMPQFile
call SFileCloseFile
test eax, eax
jz errored

push hMPQ
call SFileCloseArchive
test eax, eax
jz errored

push hLibStorm
call dword ptr [FreeLibrary]
}
return;
errored:
AddChat(vbRed, "ExtractMPQ Failed!");
return;
}

...

ExtractMPQ("C:\\Documents and Settings\\Owner\\Desktop\\IX86Mindsight.mpq", "(listfile)");
<3 Zorm
Quote[01:08:05 AM] <@Zorm> haha, me get pussy? don't kid yourself quik
Scio te esse, sed quid sumne? :P

Barabajagal

If it's any help, here's my VB code which seems to work just fine:
Option Explicit
Private Declare Function SFileCloseArchive Lib "Storm.dll" Alias "#252" (ByVal hMPQ As Long) As Boolean
Private Declare Function SFileCloseFile Lib "Storm.dll" Alias "#253" (ByVal hFile As Long) As Boolean
Private Declare Function SFileDestroy Lib "Storm.dll" Alias "#262" () As Boolean
Private Declare Function SFileGetFileSize Lib "Storm.dll" Alias "#265" (ByVal hFile As Long, ByRef lpFileSizeHigh As Long) As Long
Private Declare Function SFileOpenArchive Lib "Storm.dll" Alias "#266" (ByVal lpFileName As String, ByVal dwPriority As Long, ByVal dwFlags As Long, ByRef hMPQ As Long) As Boolean
Private Declare Function SFileOpenFileEx Lib "Storm.dll" Alias "#268" (ByVal hMPQ As Long, ByVal lpFileName As String, ByVal dwSearchScope As Long, ByRef hFile As Long) As Boolean
Private Declare Function SFileReadFile Lib "Storm.dll" Alias "#269" (ByVal hFile As Long, lpBuffer As Byte, ByVal nNumberOfBYTEsToRead As Long, ByRef lpNumberOfBYTEsRead As Long, lpOverlapped As Long) As Boolean
Private Declare Function SFileAuthenticateArchive Lib "Storm.dll" Alias "#251" (ByVal hMPQ As Long, ByRef dwAuthenticationStatus As Long) As Boolean
Private Declare Function WriteFile Lib "kernel32" (ByVal hFile As Long, lpBuffer As Any, ByVal nNumberOfBytesToWrite As Long, lpNumberOfBytesWritten As Long, lpOverlapped As Long) As Long
Public Function ExtractFromMPQ(ByVal strArchive As String, ByVal strFile As String) As String
Dim hMPQ       As Long
Dim hFile      As Long
Dim hOutput    As Long
Dim lngSize    As Long
Dim dwBytes    As Long
Dim szBuffer() As Byte
Dim Status     As Long
  On Error GoTo Erred
  SFileDestroy
  SFileOpenArchive SettingsFolder & "\Tmp\MPQs\" & strArchive, 0, 0, hMPQ
  SFileOpenFileEx hMPQ, strFile, 0, hFile
  If hFile <> 0 Then
    SFileAuthenticateArchive hMPQ, Status
    If Status = &H0 Or Status = &H1 Or Status = &H5 Then
      lngSize = SFileGetFileSize(hFile, 0)
      ReDim szBuffer(0 To lngSize)
      SFileReadFile hFile, szBuffer(0), lngSize, dwBytes, ByVal &H0
      If dwBytes <> lngSize Then
        ExtractFromMPQ = "MPQ Corrupt (" & dwBytes & " / " & lngSize & ")"
        GoTo Failed
      End If
      If LenB(Dir$(SettingsFolder & "\Tmp\MPQs\" & strFile)) > 0 Then Kill SettingsFolder & "\Tmp\MPQs\" & strFile
      hOutput = CreateFileA(SettingsFolder & "\Tmp\MPQs\" & strFile, &H40000000, &H2, ByVal 0&, &H2, ByVal 0&, ByVal 0&)
      WriteFile hOutput, szBuffer(0), lngSize, dwBytes, ByVal &H0
      CloseHandle hOutput
      If dwBytes <> lngSize Then
        ExtractFromMPQ = "DLL Corrupt (" & dwBytes & " / " & lngSize & ")"
        GoTo Failed
      End If
      SFileCloseFile hFile
      SFileCloseArchive hMPQ
      SetFileTimeInfo SettingsFolder & "\Tmp\MPQs\" & strFile, GetFileTimeInfo(SettingsFolder & "\Tmp\MPQs\" & strArchive), GetFileTimeInfo(SettingsFolder & "\Tmp\MPQs\" & strArchive), GetFileTimeInfo(SettingsFolder & "\Tmp\MPQs\" & strArchive)
      ExtractFromMPQ = "OK"
    Else
      ExtractFromMPQ = "MPQ not authentic"
    End If
  Else
    ExtractFromMPQ = "Could not find " & strFile & " in " & strArchive
  End If
  SFileDestroy
  Exit Function
Failed:
  If hFile <> 0 Then SFileCloseFile hFile
  If hMPQ <> 0 Then SFileCloseArchive hMPQ
Exit Function
Erred:
  ExtractFromMPQ = Err.Description
  GoTo Failed
End Function

brew

Actually, now that I look at it today, my own works just fine as well... mmm, idk.
So, better question: How would I get at those files inside of an internal directory? Would I have to call another storm function to change the current directory or something? Passing the raw filename and path to the lib doesn't seem to work.
<3 Zorm
Quote[01:08:05 AM] <@Zorm> haha, me get pussy? don't kid yourself quik
Scio te esse, sed quid sumne? :P

Barabajagal

I... never got that far. But if I had to guess, I'd say SFileSetBasePath.

brew

#4
Hm, I wonder what the params are for that?
I guess i'll check what battle.snp does...

EDIT**
Oops! I just realized, since when would battle.snp need that functionality? Hmm, i guess i'll check starcraft.exe.
EDIT***
Well, starcraft.exe doesn't call it either.
Apparently it passes the filename just like that?


.text:004CC3A4 loc_4CC3A4:                             ; CODE XREF: sub_4CC320+5A
.text:004CC3A4                 push    104h
.text:004CC3A9                 push    offset aStareditScenar ; "staredit\\scenario.chk"
.text:004CC3AE                 lea     ecx, [ebp+var_20C]
.text:004CC3B4                 push    ecx
.text:004CC3B5                 call    SStrNCpy
.text:004CC3BA
.text:004CC3BA loc_4CC3BA:                             ; CODE XREF: sub_4CC320+82
.text:004CC3BA                 push    88Bh
.text:004CC3BF                 push    offset aStarcraftSw_66 ; "Starcraft\\SWAR\\lang\\maphdr.cpp"
.text:004CC3C4                 push    1
.text:004CC3C6                 push    0
.text:004CC3C8                 lea     edx, [ebp+var_20C]
.text:004CC3CE                 push    edx             ; effectively contains staredit\scenario.chk
.text:004CC3CF                 xor     ecx, ecx
.text:004CC3D1                 lea     eax, [ebp+var_4]
.text:004CC3D4                 call    loc_4D2940




.text:004D2940                 push    ebp
.text:004D2941                 mov     ebp, esp
.text:004D2943                 push    ecx
.text:004D2944                 push    ebx
.text:004D2945                 push    esi
.text:004D2946                 mov     esi, [ebp+8]
.text:004D2949                 mov     ebx, eax
.text:004D294B                 lea     eax, [ebp-4]
.text:004D294E                 push    eax             ; phFile
.text:004D294F                 push    ecx             ; "int"
.text:004D2950                 push    esi             ; filename
.text:004D2951                 push    0               ; hArchive
.text:004D2953                 call    SFileOpenFileEx


...and look at that. all of my mpq archive extracting woes are gone.
<3 Zorm
Quote[01:08:05 AM] <@Zorm> haha, me get pussy? don't kid yourself quik
Scio te esse, sed quid sumne? :P

Barabajagal

double backslash ftw. I'll have to make a note of that, just in case...


UserLoser

Quote from: brew on March 25, 2008, 02:56 PM
Actually, now that I look at it today, my own works just fine as well... mmm, idk.
So, better question: How would I get at those files inside of an internal directory? Would I have to call another storm function to change the current directory or something? Passing the raw filename and path to the lib doesn't seem to work.

keep in mind your project in whatever IDE you're using might not have the same running location ('current directory') as your files so you have to include the whole path (or a part of it)

Hex

this program uses Storm Library and SFMPQ Library.
Programmed in VC++ 6.0
Unused Unprotector 2 Source code.
Link: http://sunrub.dothome.co.kr/Unused_Unprotector_2_source.zip