initial: nsUnz plugin 1.0.0
This commit is contained in:
@@ -0,0 +1,593 @@
|
||||
// Unicode NSIS support by Gringoloco023, http://portableapps.com/node/21879, Februari 6 2010
|
||||
/*
|
||||
UnZip Plug-in for NSIS
|
||||
Written by Saivert
|
||||
|
||||
Credits:
|
||||
- Based on code in NSIS Zip2Exe
|
||||
portions Copyright © 1999-2001 Miguel Garrido (mgarrido01@hotmail.com)
|
||||
- Uses ZLIB - Copyright © Mark Adler
|
||||
- ZIP format routines - Copyright (C) 1998 Gilles Vollant
|
||||
|
||||
Even though this project is an NSIS Plug-in, it also
|
||||
exports a function that can be used by any applications.
|
||||
The exported function is "appextract"
|
||||
*/
|
||||
//#include "AggressiveOptimize.h"
|
||||
#include <windows.h>
|
||||
#include <stdio.h>
|
||||
#include <commctrl.h>
|
||||
#include "..\ExDLL\exdll.h"
|
||||
|
||||
//#include "exdll.h"
|
||||
|
||||
extern "C" {
|
||||
#include "zlib/unzip.h"
|
||||
};
|
||||
|
||||
//Strings used all over the place
|
||||
TCHAR szSuccess[] = {_T('s'),_T('u'),_T('c'),_T('c'),_T('e'),_T('s'),_T('s'),_T('\0')};
|
||||
TCHAR szFile[] = {_T('/'),_T('f'),_T('i'),_T('l'),_T('e'),_T('\0')};
|
||||
TCHAR szNoextractpath[] = {_T('/'),_T('n'),_T('o'),_T('e'),_T('x'),_T('t'),_T('r'),_T('a'),_T('c'),_T('t'),_T('p'),_T('a'),_T('t'),_T('h'),_T('\0')};
|
||||
TCHAR szDefExtractText[] = {_T('E'),_T('x'),_T('t'),_T('r'),_T('a'),_T('c'),_T('t'),_T(':'),_T(' '),_T('%'),_T('f'),_T('\0')};
|
||||
|
||||
TCHAR g_extract_text[1024];
|
||||
|
||||
int g_extracting;
|
||||
HWND g_hwndParent;
|
||||
TCHAR tempzip_path[1024];
|
||||
|
||||
void internal_unzip(int);
|
||||
|
||||
CRITICAL_SECTION cs;
|
||||
|
||||
//Log stuff
|
||||
HWND g_hwndList;
|
||||
HWND g_hwndStatus;
|
||||
void LogMessage(HWND, const TCHAR *, int = 0);
|
||||
|
||||
#ifdef UNICODE
|
||||
char * _T2A(wchar_t *str);
|
||||
wchar_t * _A2T(char *str);
|
||||
#define _tfopen_s _wfopen_s
|
||||
#else
|
||||
#define _T2A(x) (x)
|
||||
#define _A2T(x) (x)
|
||||
#define _tfopen_s fopen_s
|
||||
#endif
|
||||
|
||||
extern "C" BOOL WINAPI DllMain(HANDLE hInst, ULONG ul_reason_for_call, LPVOID lpReserved)
|
||||
{
|
||||
switch (ul_reason_for_call)
|
||||
{
|
||||
//case DLL_THREAD_ATTACH:
|
||||
case DLL_PROCESS_ATTACH:
|
||||
InitializeCriticalSection(&cs);
|
||||
break;
|
||||
//case DLL_THREAD_DETACH:
|
||||
case DLL_PROCESS_DETACH:
|
||||
DeleteCriticalSection(&cs);
|
||||
break;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void doMKDir(TCHAR *directory)
|
||||
{
|
||||
TCHAR *p, *p2;
|
||||
TCHAR buf[MAX_PATH];
|
||||
if (!*directory) return;
|
||||
lstrcpy(buf,directory);
|
||||
p=buf; while (*p) p++;
|
||||
while (p >= buf && *p != _T('\\')) p--;
|
||||
p2 = buf;
|
||||
if (p2[1] == _T(':')) p2+=4;
|
||||
else if (p2[0] == _T('\\') && p2[1] == _T('\\'))
|
||||
{
|
||||
p2+=2;
|
||||
while (*p2 && *p2 != _T('\\')) p2++;
|
||||
if (*p2) p2++;
|
||||
while (*p2 && *p2 != _T('\\')) p2++;
|
||||
if (*p2) p2++;
|
||||
}
|
||||
if (p >= p2)
|
||||
{
|
||||
*p=0;
|
||||
doMKDir(buf);
|
||||
}
|
||||
CreateDirectory(directory,NULL);
|
||||
}
|
||||
|
||||
//Based on inttosizestr from NSIS exehead project.
|
||||
//Creates a string representing the size of a file,
|
||||
//choosing the unit that's best suited.
|
||||
static TCHAR * FormatDiskSize(TCHAR *str, unsigned long b)
|
||||
{
|
||||
TCHAR scale=_T('k');
|
||||
TCHAR sh=30;
|
||||
TCHAR s=0;
|
||||
|
||||
if (b <= (1024*1024) ) sh=10, scale=_T('k');
|
||||
else if (b <= (1024*1024*1024)) sh=20, scale=_T('M');
|
||||
else if (GetVersion()&0x80000000) s=_T('+'); //only display '+' on GB shown on Win95
|
||||
|
||||
if (b >= 1000) //represent everything above 1000 bytes as 0,xx kB
|
||||
{
|
||||
wsprintf(str, _T("%d.%d%d %cB%c"),
|
||||
b>>sh, ((b*10)>>sh)%10, ((b*20)>>sh)%10, scale, s);
|
||||
if (b < 1024)
|
||||
wsprintf(str+_tcsclen(str), _T(" (%u byte%c)"), b, b == 1?0:_T('s'));
|
||||
}
|
||||
else
|
||||
wsprintf(str, _T("%u byte%c"), b, b == 1?0:_T('s'));
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
/* A simple format parser
|
||||
* Handles %f, %c and %u
|
||||
* size of out must be twice as large as size of str
|
||||
*/
|
||||
static TCHAR * parse(const TCHAR *str, TCHAR *out, int outlen,
|
||||
TCHAR *filename,
|
||||
unsigned long compressed,
|
||||
unsigned long uncompressed,
|
||||
unsigned int nkb)
|
||||
{
|
||||
TCHAR s[32];
|
||||
const TCHAR *p;
|
||||
UINT i=0;
|
||||
p=str-1;
|
||||
memset(out, 0, outlen);
|
||||
|
||||
while (p++ && (*p != 0))
|
||||
{
|
||||
if (*p == _T('%'))
|
||||
{
|
||||
switch (*(p+1))
|
||||
{
|
||||
case _T('c'):
|
||||
case _T('C'):
|
||||
{
|
||||
FormatDiskSize(s, compressed);
|
||||
lstrcat(out, s);
|
||||
i += lstrlen(s);
|
||||
break;
|
||||
}
|
||||
case _T('u'):
|
||||
case _T('U'):
|
||||
{
|
||||
FormatDiskSize(s, uncompressed);
|
||||
lstrcat(out, s);
|
||||
i += lstrlen(s);
|
||||
break;
|
||||
}
|
||||
case _T('f'):
|
||||
case _T('F'):
|
||||
{
|
||||
lstrcat(out, filename);
|
||||
i += lstrlen(filename);
|
||||
break;
|
||||
}
|
||||
case _T('p'):
|
||||
case _T('P'):
|
||||
{
|
||||
unsigned int j;
|
||||
j = uncompressed;
|
||||
if (!j) j = 1;
|
||||
wsprintf(s, _T("%d%%"), nkb*100/j);
|
||||
lstrcat(out, s);
|
||||
i += lstrlen(s);
|
||||
break;
|
||||
}
|
||||
case _T('b'):
|
||||
case _T('B'):
|
||||
{
|
||||
FormatDiskSize(s, nkb);
|
||||
lstrcat(out, s);
|
||||
i += lstrlen(s);
|
||||
break;
|
||||
}
|
||||
default: out[i++] = *p;
|
||||
}
|
||||
++p;
|
||||
} else {
|
||||
out[i++] = *p;
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
extern "C" __declspec(dllexport)
|
||||
void Unzip(HWND hwndParent, int string_size, TCHAR *variables, stack_t **stacktop)
|
||||
{
|
||||
EXDLL_INIT();
|
||||
g_hwndParent = hwndParent;
|
||||
internal_unzip(0);
|
||||
}
|
||||
|
||||
extern "C" __declspec(dllexport)
|
||||
void UnzipToLog(HWND hwndParent, int string_size, TCHAR *variables, stack_t **stacktop)
|
||||
{
|
||||
EXDLL_INIT();
|
||||
g_hwndParent = hwndParent;
|
||||
internal_unzip(1);
|
||||
}
|
||||
|
||||
extern "C" __declspec(dllexport)
|
||||
void UnzipToStack(HWND hwndParent, int string_size, TCHAR *variables, stack_t **stacktop)
|
||||
{
|
||||
EXDLL_INIT();
|
||||
g_hwndParent = hwndParent;
|
||||
internal_unzip(2);
|
||||
}
|
||||
|
||||
// This function is to be used by rundll32.exe. Call it like this:
|
||||
//
|
||||
// rundll32.exe "c:\a path\nsisunz.dll",extract_RunDLL c:\path\zipfile.zip c:\outdir
|
||||
//
|
||||
// or to extract a single file, use this (concatenate the next two lines):
|
||||
//
|
||||
// rundll32.exe c:\path\nsisunz.dll,extract_RunDLL
|
||||
// /file readme.txt "c:\a path\zipfile.zip" c:\outdir
|
||||
//
|
||||
// "/noextractpath" is implicitly used if "/file" is used.
|
||||
// It mimics NSIS itself by setting up a stack and pushing the
|
||||
// parameters from the function on the stack. I made it like this
|
||||
// so I could directly reuse the code I already had written without modifications.
|
||||
extern "C" __declspec(dllexport)
|
||||
void extract_RunDLL(HINSTANCE hAppInstance, LPVOID unused, TCHAR *params)
|
||||
{
|
||||
TCHAR res[1024];
|
||||
TCHAR temp[256];
|
||||
TCHAR zipfile[MAX_PATH]={0,};
|
||||
TCHAR destdir[MAX_PATH]={0,};
|
||||
TCHAR file[MAX_PATH]={0,};
|
||||
TCHAR *p = params;
|
||||
TCHAR *s;
|
||||
TCHAR q=0;
|
||||
int next=0;
|
||||
#define NEXT_FILE 1
|
||||
#define NEXT_ZIP 2
|
||||
#define NEXT_DEST 3
|
||||
|
||||
stack_t ownstacktop;
|
||||
stack_t *pownstacktop = &ownstacktop;
|
||||
|
||||
ownstacktop.next = NULL;
|
||||
ownstacktop.text[0] = NULL;
|
||||
|
||||
g_stringsize=1024;
|
||||
g_stacktop=&pownstacktop;
|
||||
g_variables=NULL;
|
||||
|
||||
//Parse the parameters
|
||||
//While we do the parsing we use next as a clue to
|
||||
//what comes next. This way I don't have to write a
|
||||
//new function.
|
||||
while (*p)
|
||||
{
|
||||
if (*p==_T('"')) q=_T('"'), p++; else q=_T(' '); //Do we search for a quote or a space?
|
||||
s = temp;
|
||||
while (*p && *p != q) *s++ = *p++; //Copy chars from params to zipfile
|
||||
*s = 0; //Terminate string
|
||||
if (next==NEXT_FILE) lstrcpy(file, temp), next=NEXT_ZIP;
|
||||
else if (next==NEXT_ZIP) lstrcpy(zipfile, temp), next=NEXT_DEST;
|
||||
else if (next==NEXT_DEST) lstrcpy(destdir, temp), next=0;
|
||||
else if (!lstrcmpi(temp, szFile)) next=NEXT_FILE;
|
||||
else lstrcpy(zipfile, temp), next=NEXT_DEST;
|
||||
|
||||
while (*p && *++p == _T(' '));
|
||||
}
|
||||
|
||||
pushstring(destdir);
|
||||
pushstring(zipfile);
|
||||
|
||||
if (file[0])
|
||||
{
|
||||
pushstring(file);
|
||||
pushstring(szFile);
|
||||
pushstring(szNoextractpath);
|
||||
}
|
||||
|
||||
internal_unzip(0);
|
||||
popstring(res);
|
||||
if (lstrcmp(res, szSuccess))
|
||||
MessageBox(0, res, NULL, MB_ICONERROR);
|
||||
}
|
||||
|
||||
void internal_unzip(int uselog)
|
||||
{
|
||||
//All char baby (or should I use int for the non-string stuff??)
|
||||
TCHAR first=0;
|
||||
TCHAR filefound=0;
|
||||
TCHAR usefile=0;
|
||||
TCHAR hastext=0;
|
||||
TCHAR noextractpath=0;
|
||||
TCHAR filetoextract[MAX_PATH+1];
|
||||
TCHAR buf[1024];
|
||||
TCHAR fn[MAX_PATH+1];
|
||||
|
||||
popstring(buf);
|
||||
while (buf[0] == _T('/'))
|
||||
{
|
||||
if (!lstrcmpi(buf+1, _T("text"))) popstring(g_extract_text), hastext++;
|
||||
if (!lstrcmpi(buf+1, _T("noextractpath"))) noextractpath++;
|
||||
if (!lstrcmpi(buf+1, _T("file")))
|
||||
{
|
||||
TCHAR *p;
|
||||
popstring(filetoextract);
|
||||
// Ensure filename uses backslashes
|
||||
p = filetoextract;
|
||||
while (*p)
|
||||
{
|
||||
if (*p == _T('/')) *p=_T('\\');
|
||||
p++;
|
||||
}
|
||||
usefile++;
|
||||
}
|
||||
|
||||
//if stack is empty, bail out
|
||||
if (popstring(buf))
|
||||
*buf = 0;
|
||||
}
|
||||
//check for first required param
|
||||
if (*buf)
|
||||
lstrcpyn(fn, buf, MAX_PATH);
|
||||
else
|
||||
{
|
||||
pushstring(_T("Error reading ZIP filename parameter"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (popstring(tempzip_path))
|
||||
{
|
||||
pushstring(_T("Error reading destination directory parameter"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (uselog==1)
|
||||
{
|
||||
if (!hastext) lstrcpy(g_extract_text, szDefExtractText);
|
||||
}
|
||||
|
||||
unzFile f;
|
||||
f = unzOpen(_T2A(fn));
|
||||
if (!f || unzGoToFirstFile(f) != UNZ_OK)
|
||||
{
|
||||
if (f) unzClose(f);
|
||||
pushstring(_T("Error opening ZIP file"));
|
||||
return;
|
||||
}
|
||||
|
||||
int nf=0, nb=0;
|
||||
unz_file_info fileinfo;
|
||||
g_extracting=1;
|
||||
do {
|
||||
char filenameA[MAX_PATH];
|
||||
TCHAR filename[MAX_PATH];
|
||||
unzGetCurrentFileInfo(f,&fileinfo,filenameA,sizeof(filename),NULL,0,NULL,0);
|
||||
lstrcpyn(filename, _A2T(filenameA), MAX_PATH);
|
||||
|
||||
if (filename[0] &&
|
||||
filename[_tcsclen(filename)-1] != _T('\\') &&
|
||||
filename[_tcsclen(filename)-1] != _T('/'))
|
||||
{
|
||||
TCHAR *pfn=filename;
|
||||
//ensure path uses backslashes
|
||||
while (*pfn)
|
||||
{
|
||||
if (*pfn == _T('/')) *pfn=_T('\\');
|
||||
pfn++;
|
||||
}
|
||||
|
||||
if (usefile)
|
||||
{
|
||||
if (lstrcmpi(filename, filetoextract) != 0) continue;
|
||||
else filefound++;
|
||||
}
|
||||
|
||||
pfn=filename;
|
||||
if (pfn[1] == _T(':') && pfn[2] == _T('\\')) pfn+=3;
|
||||
while (*pfn == _T('\\')) pfn++;
|
||||
|
||||
if (noextractpath)
|
||||
{
|
||||
TCHAR buf[MAX_PATH];
|
||||
lstrcpy(buf,filename);
|
||||
TCHAR *p=buf+_tcsclen(buf);
|
||||
while (p > buf && *p != _T('\\') && *p != _T('/')) p = CharPrev(buf, p);
|
||||
if (p > buf) p++;
|
||||
lstrcpy(filename, p);
|
||||
}
|
||||
|
||||
TCHAR out_filename[1024];
|
||||
lstrcpy(out_filename,tempzip_path);
|
||||
lstrcat(out_filename,_T("\\"));
|
||||
lstrcat(out_filename,pfn);
|
||||
if (_tcsstr(pfn,_T("\\")))
|
||||
{
|
||||
TCHAR buf[1024];
|
||||
lstrcpy(buf,out_filename);
|
||||
TCHAR *p=buf+_tcsclen(buf);
|
||||
while (p > buf && *p != _T('\\')) p--;
|
||||
*p=0;
|
||||
if (buf[0]) doMKDir(buf);
|
||||
}
|
||||
|
||||
if (unzOpenCurrentFile(f) == UNZ_OK)
|
||||
{
|
||||
FILE *fp;
|
||||
int l;
|
||||
fp = _tfopen(out_filename,_T("wb"));
|
||||
if (fp)
|
||||
{
|
||||
if (uselog==1) {
|
||||
TCHAR logtmp[256];
|
||||
parse(g_extract_text, logtmp, sizeof(logtmp),
|
||||
pfn, fileinfo.compressed_size, fileinfo.uncompressed_size, 0);
|
||||
LogMessage(g_hwndParent, logtmp);
|
||||
} else if (uselog == 2) {
|
||||
if (!first)
|
||||
{
|
||||
pushstring(_T("")); //push list terminator (empty string)
|
||||
first++;
|
||||
}
|
||||
pushstring(pfn);
|
||||
}
|
||||
nb=0;
|
||||
do
|
||||
{
|
||||
TCHAR buf[1024];
|
||||
l=unzReadCurrentFile(f,buf,sizeof(buf));
|
||||
if (l > 0)
|
||||
{
|
||||
if (fwrite(buf,1,l,fp) != (unsigned int)l)
|
||||
{
|
||||
unzClose(f);
|
||||
fclose(fp);
|
||||
pushstring(_T("Error writing output file(s)"));
|
||||
g_extracting=0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!g_extracting)
|
||||
{
|
||||
unzClose(f);
|
||||
fclose(fp);
|
||||
g_extracting=0;
|
||||
pushstring(_T("aborted"));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (uselog==1 && (nb % 1024))
|
||||
{
|
||||
TCHAR logtmp[256];
|
||||
parse(g_extract_text, logtmp, sizeof(logtmp),
|
||||
pfn, fileinfo.compressed_size,
|
||||
fileinfo.uncompressed_size, nb);
|
||||
LogMessage(g_hwndParent, logtmp, 1);
|
||||
}
|
||||
nb += l;
|
||||
} while (l > 0);
|
||||
|
||||
fclose(fp);
|
||||
}
|
||||
else
|
||||
{
|
||||
unzClose(f);
|
||||
pushstring(_T("Error opening output file(s)"));
|
||||
g_extracting=0;
|
||||
return;
|
||||
}
|
||||
nf++;
|
||||
|
||||
int quit=0;
|
||||
if (g_hwndParent)
|
||||
{
|
||||
MSG msg;
|
||||
while (PeekMessage(&msg,NULL,0,0,PM_REMOVE))
|
||||
{
|
||||
if (msg.message == WM_DESTROY && msg.hwnd == g_hwndParent)
|
||||
{
|
||||
quit++;
|
||||
break;
|
||||
}
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
}
|
||||
}
|
||||
unzCloseCurrentFile(f);
|
||||
if (quit) break;
|
||||
}
|
||||
else
|
||||
{
|
||||
unzClose(f);
|
||||
pushstring(_T("Error extracting from ZIP file"));
|
||||
g_extracting=0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
} while (unzGoToNextFile(f) == UNZ_OK);
|
||||
|
||||
g_extracting=0;
|
||||
if (usefile && !filefound) {
|
||||
pushstring(_T("File not found in archive"));
|
||||
} else {
|
||||
pushstring(szSuccess);
|
||||
}
|
||||
unzClose(f);
|
||||
return;
|
||||
}
|
||||
|
||||
// Tim Kosse's LogMessage
|
||||
void LogMessage(HWND hwndParent, const TCHAR *pStr, int changelast) {
|
||||
static HWND hwndList=0;
|
||||
static HWND hwndStatus=0;
|
||||
LVITEM item={0};
|
||||
int nItemCount;
|
||||
if (!hwndParent) return;
|
||||
|
||||
EnterCriticalSection(&cs);
|
||||
|
||||
//Get ListView control on instfiles page (the log)
|
||||
if (!hwndList) hwndList = FindWindowEx(
|
||||
FindWindowEx(hwndParent, NULL, _T("#32770"), NULL),
|
||||
NULL, _T("SysListView32"), NULL);
|
||||
|
||||
//Get status "STATIC" control above progressbar
|
||||
if (!hwndStatus) hwndStatus = GetDlgItem(
|
||||
FindWindowEx(hwndParent, NULL, _T("#32770"), NULL),
|
||||
1006);
|
||||
|
||||
if (!hwndList || !hwndStatus) return;
|
||||
|
||||
SendMessage(hwndStatus, WM_SETTEXT, 0, (LPARAM)pStr);//added by Saivert
|
||||
nItemCount=SendMessage(hwndList, LVM_GETITEMCOUNT, 0, 0);
|
||||
|
||||
item.mask=LVIF_TEXT;
|
||||
item.pszText=(TCHAR *)pStr;
|
||||
item.cchTextMax=0;
|
||||
item.iItem=changelast?nItemCount-1:nItemCount;
|
||||
|
||||
if (changelast) {
|
||||
ListView_SetItem(hwndList, &item);
|
||||
} else {
|
||||
ListView_InsertItem(hwndList, &item);
|
||||
}
|
||||
ListView_EnsureVisible(hwndList, item.iItem, 0);
|
||||
|
||||
LeaveCriticalSection(&cs);
|
||||
}
|
||||
|
||||
// EXPERIMENTAL THREAD BASED EXTRACTION
|
||||
/*
|
||||
extern "C" __declspec(dllexport)
|
||||
UnzipToLogUsingThread(HWND hwndParent, int string_size, char *variables, stack_t **stacktop)
|
||||
{
|
||||
MSG msg;
|
||||
DWORD dwTID;
|
||||
|
||||
CreateThread(NULL, 0, UnzipThread, (LPVOID)1, 0, &dwTID);
|
||||
}
|
||||
|
||||
DWORD WINAPI UnzipThread(LPVOID p)
|
||||
{
|
||||
int uselog = 1;
|
||||
return 0;
|
||||
}
|
||||
*/
|
||||
#ifdef UNICODE
|
||||
unsigned char staticCnvBuffer[1024*sizeof(TCHAR)]; /* temp buffer, holds ASCII & UNICODE string after conversion */
|
||||
char * _T2A(wchar_t *wideStr)
|
||||
{
|
||||
WideCharToMultiByte(CP_ACP, 0, wideStr, -1, (LPSTR)staticCnvBuffer, sizeof(staticCnvBuffer), NULL, NULL);
|
||||
return (char *)staticCnvBuffer;
|
||||
}
|
||||
wchar_t * _A2T(char *ansiStr)
|
||||
{
|
||||
MultiByteToWideChar(CP_ACP, 0, ansiStr, -1, (TCHAR *)staticCnvBuffer, sizeof(staticCnvBuffer)/sizeof(TCHAR));
|
||||
return (wchar_t *)staticCnvBuffer;
|
||||
}
|
||||
#endif
|
||||
Reference in New Issue
Block a user