Files
nsis-plugin-ns7zip/tools/TestTool/test_nsis7z.cpp
T
Simone d074cc7c07 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
2026-04-29 14:07:51 +02:00

247 lines
7.6 KiB
C++

// 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;
}