chore: initial commit (extracted from Launchers monorepo)
Plugin: ns7zip v2.0.0 Architectures: x86-ansi, x86-unicode, amd64-unicode License: LGPL-2.1-or-later
This commit is contained in:
@@ -0,0 +1,246 @@
|
||||
// test_nsis7z.cpp
|
||||
// Emula la chiamata NSIS a nsis7z::ExtractWithFileCallback fuori da NSIS
|
||||
// Compila: cl /W3 /EHsc /DUNICODE /D_UNICODE test_nsis7z.cpp /link /OUT:test_nsis7z.exe
|
||||
// Uso: test_nsis7z.exe <archive.exe> <outdir> [skip1] [skip2] ...
|
||||
|
||||
#include <windows.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
// ---- Replica di pluginapi.h ----
|
||||
|
||||
typedef struct _stack_t {
|
||||
struct _stack_t *next;
|
||||
wchar_t text[1];
|
||||
} stack_t;
|
||||
|
||||
enum {
|
||||
INST_0, INST_1, INST_2, INST_3, INST_4,
|
||||
INST_5, INST_6, INST_7, INST_8, INST_9,
|
||||
INST_R0, INST_R1, INST_R2, INST_R3, INST_R4,
|
||||
INST_R5, INST_R6, INST_R7, INST_R8, INST_R9,
|
||||
INST_CMDLINE, INST_INSTDIR, INST_OUTDIR, INST_EXEDIR, INST_LANG,
|
||||
__INST_LAST
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
int exec_flags;
|
||||
int (__cdecl *ExecuteCodeSegment)(int, HWND);
|
||||
void (__cdecl *validate_filename)(wchar_t *);
|
||||
int (__cdecl *RegisterPluginCallback)(HMODULE, LPVOID);
|
||||
} extra_parameters;
|
||||
|
||||
// Tipo della funzione esportata dalla DLL
|
||||
typedef void (__cdecl *NSISPluginFunc)(
|
||||
HWND hwndParent,
|
||||
int string_size,
|
||||
wchar_t *variables,
|
||||
stack_t **stacktop,
|
||||
extra_parameters *extra
|
||||
);
|
||||
|
||||
// ---- Stato globale simulato ----
|
||||
|
||||
#define STRING_SIZE 4096
|
||||
#define NUM_VARS __INST_LAST
|
||||
|
||||
static wchar_t g_variables[NUM_VARS][STRING_SIZE];
|
||||
static stack_t *g_stacktop = NULL;
|
||||
|
||||
// ---- Callback simulato per il progresso ----
|
||||
|
||||
static int __cdecl FakeExecuteCodeSegment(int segment, HWND hwnd)
|
||||
{
|
||||
// La callback NSIS popa 3 valori dallo stack (completedSize, totalSize, fileName)
|
||||
// Li leggiamo e stampiamo
|
||||
if (g_stacktop)
|
||||
{
|
||||
stack_t *s1 = g_stacktop;
|
||||
stack_t *s2 = s1 ? s1->next : NULL;
|
||||
stack_t *s3 = s2 ? s2->next : NULL;
|
||||
|
||||
wprintf(L" [CB] completed=%s total=%s file=%s\n",
|
||||
s1 ? s1->text : L"?",
|
||||
s2 ? s2->text : L"?",
|
||||
s3 ? s3->text : L"?");
|
||||
|
||||
// Popa i 3 item
|
||||
for (int i = 0; i < 3 && g_stacktop; i++)
|
||||
{
|
||||
stack_t *tmp = g_stacktop;
|
||||
g_stacktop = g_stacktop->next;
|
||||
free(tmp);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static extra_parameters g_extra = { 0, FakeExecuteCodeSegment, NULL, NULL };
|
||||
|
||||
// ---- Gestione stack ----
|
||||
|
||||
static void push_str(const wchar_t *str)
|
||||
{
|
||||
size_t len = wcslen(str);
|
||||
stack_t *item = (stack_t*)malloc(sizeof(stack_t) + len * sizeof(wchar_t));
|
||||
if (!item) { wprintf(L"OOM\n"); exit(1); }
|
||||
wcscpy_s(item->text, len + 1, str);
|
||||
item->next = g_stacktop;
|
||||
g_stacktop = item;
|
||||
}
|
||||
|
||||
// Imposta INST_OUTDIR (indice 22) nella variabile array
|
||||
static void set_outdir(const wchar_t *dir)
|
||||
{
|
||||
wcscpy_s(g_variables[INST_OUTDIR], STRING_SIZE, dir);
|
||||
}
|
||||
|
||||
// ---- Flat variables array per la DLL ----
|
||||
// La DLL riceve un puntatore a un array piatto: ogni slot e' STRING_SIZE wchar_t
|
||||
static wchar_t g_flat_vars[NUM_VARS * STRING_SIZE];
|
||||
|
||||
static void build_flat_vars()
|
||||
{
|
||||
memset(g_flat_vars, 0, sizeof(g_flat_vars));
|
||||
for (int i = 0; i < NUM_VARS; i++)
|
||||
wcscpy_s(g_flat_vars + i * STRING_SIZE, STRING_SIZE, g_variables[i]);
|
||||
}
|
||||
|
||||
// ---- main ----
|
||||
|
||||
int wmain(int argc, wchar_t *argv[])
|
||||
{
|
||||
if (argc < 3)
|
||||
{
|
||||
wprintf(L"Uso: test_nsis7z.exe <archive> <outdir> [skip1] [skip2] ...\n");
|
||||
wprintf(L"\nEsempio:\n");
|
||||
wprintf(L" test_nsis7z.exe \"C:\\tmp\\nsis.exe\" \"C:\\tmp\\out\" \"$PLUGINSDIR\" \"$PLUGINSDIR\\*\"\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
const wchar_t *archive = argv[1];
|
||||
const wchar_t *outdir = argv[2];
|
||||
|
||||
/* Cerca la DLL nella directory del tool */
|
||||
wchar_t dllPath[MAX_PATH];
|
||||
GetModuleFileNameW(NULL, dllPath, MAX_PATH);
|
||||
wchar_t *last = wcsrchr(dllPath, L'\\');
|
||||
if (last) *(last+1) = 0;
|
||||
wcscat_s(dllPath, MAX_PATH, L"nsis7z.dll");
|
||||
|
||||
wprintf(L"Carico DLL: %s\n", dllPath);
|
||||
HMODULE hDll = LoadLibraryW(dllPath);
|
||||
if (!hDll)
|
||||
{
|
||||
wprintf(L"ERRORE: LoadLibrary fallito (err=%lu)\n", GetLastError());
|
||||
return 2;
|
||||
}
|
||||
wprintf(L"DLL caricata OK\n");
|
||||
|
||||
NSISPluginFunc fnExtract = (NSISPluginFunc)GetProcAddress(hDll, "ExtractWithFileCallback");
|
||||
if (!fnExtract)
|
||||
{
|
||||
wprintf(L"ERRORE: GetProcAddress(ExtractWithFileCallback) fallito (err=%lu)\n", GetLastError());
|
||||
FreeLibrary(hDll);
|
||||
return 3;
|
||||
}
|
||||
wprintf(L"Funzione trovata OK\n");
|
||||
|
||||
// Prepara OUTDIR
|
||||
set_outdir(outdir);
|
||||
wprintf(L"OutDir = %s\n", outdir);
|
||||
|
||||
// Prepara stack NSIS (push in ordine inverso - l'ultimo pushato e' il primo poppato)
|
||||
// Ordine di pop nella DLL: 1) popint() = callback segment, 2..N) popstring() = skip patterns + ""
|
||||
// Per il callback usiamo segmento 1 (FakeExecuteCodeSegment ricevera' segmento-1 = 0)
|
||||
//
|
||||
// Push ordine (il primo push e' il fondo dello stack):
|
||||
// "" (terminatore skip)
|
||||
// skip[N-1] ... skip[0] (in reverse per avere l'ordine giusto al pop)
|
||||
// callback_int
|
||||
|
||||
// Prima: push terminatore
|
||||
push_str(L"");
|
||||
|
||||
// Push skip patterns in ordine inverso (argv[3..])
|
||||
for (int i = argc - 1; i >= 3; i--)
|
||||
push_str(argv[i]);
|
||||
|
||||
// Push archive path (popstring in EXTRACTFUNC macro)
|
||||
push_str(archive);
|
||||
|
||||
// Il callback viene poppato con popint() DENTRO ExtractWithFileCallback (dopo EXDLL_INIT e popstring(archive))
|
||||
// Dobbiamo quindi mettere sull'apice dello stack il valore int callback
|
||||
// Ma... push_str prima e poi push_str archive: l'archivio e' sul top, poi il callback
|
||||
// Riordino: prima il callback (fondo), poi archive (top)
|
||||
// Svuota e rifai nell'ordine corretto:
|
||||
|
||||
// Libera stack corrente
|
||||
while (g_stacktop) {
|
||||
stack_t *t = g_stacktop;
|
||||
g_stacktop = g_stacktop->next;
|
||||
free(t);
|
||||
}
|
||||
|
||||
// L'EXTRACTFUNC macro fa:
|
||||
// popstring(sArchive) <- primo pop = archive
|
||||
// Poi ExtractWithFileCallback fa:
|
||||
// g_progressCallback = popint() <- secondo pop = callback segment
|
||||
// PopSkipPatterns():
|
||||
// while popstring(buf)==0 && len>0 <- terzo+ pop = skip patterns, fino a ""
|
||||
//
|
||||
// Quindi push in ordine inverso (ultimo push = primo pop):
|
||||
// push "" (terminatore, ultimo da poppare)
|
||||
// push skip[n-1]..skip[0]
|
||||
// push "2" (callback segment: ExecuteCodeSegment(2-1=1,...) ma usiamo 1 -> exec(0))
|
||||
// push archive (primo da poppare)
|
||||
|
||||
// Push "" terminatore
|
||||
push_str(L"");
|
||||
// Push skip patterns
|
||||
for (int i = argc - 1; i >= 3; i--)
|
||||
push_str(argv[i]);
|
||||
// Push callback segment (1 -> FakeExecuteCodeSegment(0, ...))
|
||||
wchar_t segbuf[32];
|
||||
swprintf_s(segbuf, 32, L"%d", 1);
|
||||
push_str(segbuf);
|
||||
// Push archive (top of stack = first to pop)
|
||||
push_str(archive);
|
||||
|
||||
wprintf(L"\nChiamo ExtractWithFileCallback...\n");
|
||||
wprintf(L" archive = %s\n", archive);
|
||||
wprintf(L" outdir = %s\n", outdir);
|
||||
for (int i = 3; i < argc; i++)
|
||||
wprintf(L" skip[%d] = %s\n", i-3, argv[i]);
|
||||
wprintf(L"\n");
|
||||
|
||||
build_flat_vars();
|
||||
|
||||
__try
|
||||
{
|
||||
fnExtract(
|
||||
NULL, // hwndParent (NULL = no progress bar)
|
||||
STRING_SIZE, // string_size
|
||||
g_flat_vars, // variables (flat array)
|
||||
&g_stacktop, // stacktop
|
||||
&g_extra // extra
|
||||
);
|
||||
wprintf(L"\nESTRAZIONE COMPLETATA SENZA CRASH\n");
|
||||
}
|
||||
__except(EXCEPTION_EXECUTE_HANDLER)
|
||||
{
|
||||
DWORD code = GetExceptionCode();
|
||||
wprintf(L"\nSEH EXCEPTION: 0x%08lX\n", code);
|
||||
switch(code)
|
||||
{
|
||||
case EXCEPTION_ACCESS_VIOLATION: wprintf(L" -> ACCESS VIOLATION\n"); break;
|
||||
case EXCEPTION_STACK_OVERFLOW: wprintf(L" -> STACK OVERFLOW\n"); break;
|
||||
case EXCEPTION_ILLEGAL_INSTRUCTION: wprintf(L" -> ILLEGAL INSTRUCTION\n"); break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
FreeLibrary(hDll);
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user