
git-svn-id: https://svn.code.sf.net/p/nsis/code/NSIS/trunk@5917 212acab6-be3b-0410-9dea-997c60f758d6
576 lines
14 KiB
C
576 lines
14 KiB
C
/*
|
|
* fileform.c
|
|
*
|
|
* This file is a part of NSIS.
|
|
*
|
|
* Copyright (C) 1999-2009 Nullsoft and Contributors
|
|
*
|
|
* Licensed under the zlib/libpng license (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
*
|
|
* Licence details can be found in the file COPYING.
|
|
*
|
|
* This software is provided 'as-is', without any express or implied
|
|
* warranty.
|
|
*/
|
|
|
|
#include "../Platform.h"
|
|
#include "fileform.h"
|
|
#include "util.h"
|
|
#include "state.h"
|
|
#include "resource.h"
|
|
#include "lang.h"
|
|
#include "ui.h"
|
|
#include "exec.h"
|
|
#include "../crc32.h"
|
|
|
|
#ifdef NSIS_CONFIG_COMPRESSION_SUPPORT
|
|
#ifdef NSIS_COMPRESS_USE_ZLIB
|
|
#include "../zlib/ZLIB.H"
|
|
#endif
|
|
|
|
#ifdef NSIS_COMPRESS_USE_LZMA
|
|
#include "../7zip/LZMADecode.h"
|
|
#define z_stream lzma_stream
|
|
#define inflateInit(x) lzmaInit(x)
|
|
#define inflateReset(x) lzmaInit(x)
|
|
#define inflate(x) lzmaDecode(x)
|
|
#define Z_OK LZMA_OK
|
|
#define Z_STREAM_END LZMA_STREAM_END
|
|
#endif
|
|
|
|
#ifdef NSIS_COMPRESS_USE_BZIP2
|
|
#include "../bzip2/bzlib.h"
|
|
|
|
#define z_stream DState
|
|
#define inflateInit(x) BZ2_bzDecompressInit(x)
|
|
#define inflateReset(x) BZ2_bzDecompressInit(x)
|
|
|
|
#define inflate(x) BZ2_bzDecompress(x)
|
|
#define Z_OK BZ_OK
|
|
#define Z_STREAM_END BZ_STREAM_END
|
|
#endif//NSIS_COMPRESS_USE_BZIP2
|
|
#endif//NSIS_CONFIG_COMPRESSION_SUPPORT
|
|
|
|
struct block_header g_blocks[BLOCKS_NUM];
|
|
header *g_header;
|
|
int g_flags;
|
|
int g_filehdrsize;
|
|
int g_is_uninstaller;
|
|
|
|
HANDLE g_db_hFile=INVALID_HANDLE_VALUE;
|
|
|
|
#if defined(NSIS_CONFIG_COMPRESSION_SUPPORT) && defined(NSIS_COMPRESS_WHOLE)
|
|
HANDLE dbd_hFile=INVALID_HANDLE_VALUE;
|
|
static int dbd_size, dbd_pos, dbd_srcpos, dbd_fulllen;
|
|
#endif//NSIS_COMPRESS_WHOLE
|
|
|
|
static int m_length;
|
|
static int m_pos;
|
|
|
|
#define _calc_percent() (MulDiv(min(m_pos,m_length),100,m_length))
|
|
#ifdef NSIS_COMPRESS_WHOLE
|
|
static int NSISCALL calc_percent()
|
|
{
|
|
return _calc_percent();
|
|
}
|
|
#else
|
|
#define calc_percent() _calc_percent()
|
|
#endif
|
|
|
|
#ifdef NSIS_CONFIG_VISIBLE_SUPPORT
|
|
#if defined(NSIS_CONFIG_CRC_SUPPORT) || defined(NSIS_COMPRESS_WHOLE)
|
|
BOOL CALLBACK verProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
if (uMsg == WM_INITDIALOG)
|
|
{
|
|
SetTimer(hwndDlg,1,250,NULL);
|
|
uMsg = WM_TIMER;
|
|
}
|
|
if (uMsg == WM_TIMER)
|
|
{
|
|
char bt[64];
|
|
int percent=calc_percent();
|
|
#ifdef NSIS_COMPRESS_WHOLE
|
|
char *msg=g_header?_LANG_UNPACKING:_LANG_VERIFYINGINST;
|
|
#else
|
|
char *msg=_LANG_VERIFYINGINST;
|
|
#endif
|
|
|
|
wsprintf(bt,msg,percent);
|
|
|
|
my_SetWindowText(hwndDlg,bt);
|
|
my_SetDialogItemText(hwndDlg,IDC_STR,bt);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
DWORD verify_time;
|
|
|
|
void handle_ver_dlg(BOOL kill)
|
|
{
|
|
static HWND hwnd;
|
|
|
|
if (kill)
|
|
{
|
|
if (hwnd) DestroyWindow(hwnd);
|
|
hwnd = NULL;
|
|
|
|
return;
|
|
}
|
|
|
|
if (hwnd)
|
|
{
|
|
MessageLoop(0);
|
|
}
|
|
else if (GetTickCount() > verify_time)
|
|
{
|
|
#ifdef NSIS_COMPRESS_WHOLE
|
|
if (g_hwnd)
|
|
{
|
|
if (g_exec_flags.status_update & 1)
|
|
{
|
|
char bt[64];
|
|
wsprintf(bt, "... %d%%", calc_percent());
|
|
update_status_text(0, bt);
|
|
}
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
hwnd = CreateDialog(
|
|
g_hInstance,
|
|
MAKEINTRESOURCE(IDD_VERIFY),
|
|
0,
|
|
verProc
|
|
);
|
|
ShowWindow(hwnd, SW_SHOW);
|
|
}
|
|
}
|
|
}
|
|
#endif//NSIS_CONFIG_CRC_SUPPORT || NSIS_COMPRESS_WHOLE
|
|
#endif//NSIS_CONFIG_VISIBLE_SUPPORT
|
|
|
|
#ifdef NSIS_CONFIG_COMPRESSION_SUPPORT
|
|
static z_stream g_inflate_stream;
|
|
#endif
|
|
|
|
const char * NSISCALL loadHeaders(int cl_flags)
|
|
{
|
|
int left;
|
|
#ifdef NSIS_CONFIG_CRC_SUPPORT
|
|
crc32_t crc = 0;
|
|
int do_crc = 0;
|
|
#endif//NSIS_CONFIG_CRC_SUPPORT
|
|
|
|
void *data;
|
|
firstheader h;
|
|
header *header;
|
|
|
|
HANDLE db_hFile;
|
|
|
|
#ifdef NSIS_CONFIG_CRC_SUPPORT
|
|
#ifdef NSIS_CONFIG_VISIBLE_SUPPORT
|
|
verify_time = GetTickCount() + 1000;
|
|
#endif
|
|
#endif//NSIS_CONFIG_CRC_SUPPORT
|
|
|
|
GetModuleFileName(NULL, state_exe_path, NSIS_MAX_STRLEN);
|
|
|
|
g_db_hFile = db_hFile = myOpenFile(state_exe_path, GENERIC_READ, OPEN_EXISTING);
|
|
if (db_hFile == INVALID_HANDLE_VALUE)
|
|
{
|
|
return _LANG_CANTOPENSELF;
|
|
}
|
|
|
|
mystrcpy(state_exe_directory, state_exe_path);
|
|
mystrcpy(state_exe_file, trimslashtoend(state_exe_directory));
|
|
|
|
left = m_length = GetFileSize(db_hFile,NULL);
|
|
while (left > 0)
|
|
{
|
|
static char temp[32768];
|
|
DWORD l = min(left, (g_filehdrsize ? 32768 : 512));
|
|
if (!ReadSelfFile(temp, l))
|
|
{
|
|
#if defined(NSIS_CONFIG_CRC_SUPPORT) && defined(NSIS_CONFIG_VISIBLE_SUPPORT)
|
|
handle_ver_dlg(TRUE);
|
|
#endif//NSIS_CONFIG_CRC_SUPPORT
|
|
return _LANG_INVALIDCRC;
|
|
}
|
|
|
|
if (!g_filehdrsize)
|
|
{
|
|
mini_memcpy(&h, temp, sizeof(firstheader));
|
|
if (
|
|
(h.flags & (~FH_FLAGS_MASK)) == 0 &&
|
|
h.siginfo == FH_SIG &&
|
|
h.nsinst[2] == FH_INT3 &&
|
|
h.nsinst[1] == FH_INT2 &&
|
|
h.nsinst[0] == FH_INT1
|
|
)
|
|
{
|
|
g_filehdrsize = m_pos;
|
|
|
|
#if defined(NSIS_CONFIG_CRC_SUPPORT) || defined(NSIS_CONFIG_SILENT_SUPPORT)
|
|
cl_flags |= h.flags;
|
|
#endif
|
|
|
|
#ifdef NSIS_CONFIG_SILENT_SUPPORT
|
|
g_exec_flags.silent |= cl_flags & FH_FLAGS_SILENT;
|
|
#endif
|
|
|
|
if (h.length_of_all_following_data > left)
|
|
return _LANG_INVALIDCRC;
|
|
|
|
#ifdef NSIS_CONFIG_CRC_SUPPORT
|
|
if ((cl_flags & FH_FLAGS_FORCE_CRC) == 0)
|
|
{
|
|
if (cl_flags & FH_FLAGS_NO_CRC)
|
|
break;
|
|
}
|
|
|
|
do_crc++;
|
|
|
|
#ifndef NSIS_CONFIG_CRC_ANAL
|
|
left = h.length_of_all_following_data - 4;
|
|
// end crc checking at crc :) this means you can tack shit on the end and it'll still work.
|
|
#else //!NSIS_CONFIG_CRC_ANAL
|
|
left -= 4;
|
|
#endif//NSIS_CONFIG_CRC_ANAL
|
|
// this is in case the end part is < 512 bytes.
|
|
if (l > (DWORD)left) l=(DWORD)left;
|
|
|
|
#else//!NSIS_CONFIG_CRC_SUPPORT
|
|
// no crc support, no need to keep on reading
|
|
break;
|
|
#endif//!NSIS_CONFIG_CRC_SUPPORT
|
|
}
|
|
}
|
|
#ifdef NSIS_CONFIG_CRC_SUPPORT
|
|
|
|
#ifdef NSIS_CONFIG_VISIBLE_SUPPORT
|
|
|
|
#ifdef NSIS_CONFIG_SILENT_SUPPORT
|
|
else if ((cl_flags & FH_FLAGS_SILENT) == 0)
|
|
#endif//NSIS_CONFIG_SILENT_SUPPORT
|
|
{
|
|
handle_ver_dlg(FALSE);
|
|
}
|
|
#endif//NSIS_CONFIG_VISIBLE_SUPPORT
|
|
|
|
#ifndef NSIS_CONFIG_CRC_ANAL
|
|
if (left < m_length)
|
|
#endif//NSIS_CONFIG_CRC_ANAL
|
|
crc = CRC32(crc, temp, l);
|
|
|
|
#endif//NSIS_CONFIG_CRC_SUPPORT
|
|
m_pos += l;
|
|
left -= l;
|
|
}
|
|
#ifdef NSIS_CONFIG_VISIBLE_SUPPORT
|
|
#ifdef NSIS_CONFIG_CRC_SUPPORT
|
|
handle_ver_dlg(TRUE);
|
|
#endif//NSIS_CONFIG_CRC_SUPPORT
|
|
#endif//NSIS_CONFIG_VISIBLE_SUPPORT
|
|
if (!g_filehdrsize)
|
|
return _LANG_INVALIDCRC;
|
|
|
|
#ifdef NSIS_CONFIG_CRC_SUPPORT
|
|
if (do_crc)
|
|
{
|
|
crc32_t fcrc;
|
|
SetSelfFilePointer(m_pos);
|
|
if (!ReadSelfFile(&fcrc, sizeof(crc32_t)) || crc != fcrc)
|
|
return _LANG_INVALIDCRC;
|
|
}
|
|
#endif//NSIS_CONFIG_CRC_SUPPORT
|
|
|
|
data = (void *)GlobalAlloc(GPTR,h.length_of_header);
|
|
|
|
#ifdef NSIS_COMPRESS_WHOLE
|
|
inflateReset(&g_inflate_stream);
|
|
|
|
{
|
|
char fno[MAX_PATH];
|
|
my_GetTempFileName(fno, state_temp_dir);
|
|
dbd_hFile=CreateFile(fno,GENERIC_WRITE|GENERIC_READ,0,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_TEMPORARY|FILE_FLAG_DELETE_ON_CLOSE,NULL);
|
|
if (dbd_hFile == INVALID_HANDLE_VALUE)
|
|
return _LANG_ERRORWRITINGTEMP;
|
|
}
|
|
dbd_srcpos = SetSelfFilePointer(g_filehdrsize + sizeof(firstheader));
|
|
#ifdef NSIS_CONFIG_CRC_SUPPORT
|
|
dbd_fulllen = dbd_srcpos - sizeof(h) + h.length_of_all_following_data - ((h.flags & FH_FLAGS_NO_CRC) ? 0 : sizeof(crc32_t));
|
|
#else
|
|
dbd_fulllen = dbd_srcpos - sizeof(h) + h.length_of_all_following_data;
|
|
#endif//NSIS_CONFIG_CRC_SUPPORT
|
|
#else
|
|
SetSelfFilePointer(g_filehdrsize + sizeof(firstheader));
|
|
#endif//NSIS_COMPRESS_WHOLE
|
|
|
|
if (GetCompressedDataFromDataBlockToMemory(-1, data, h.length_of_header) != h.length_of_header)
|
|
{
|
|
return _LANG_INVALIDCRC;
|
|
}
|
|
|
|
header = g_header = data;
|
|
|
|
g_flags = header->flags;
|
|
|
|
#ifdef NSIS_CONFIG_UNINSTALL_SUPPORT
|
|
if (h.flags & FH_FLAGS_UNINSTALL)
|
|
g_is_uninstaller++;
|
|
#endif
|
|
|
|
// set offsets to real memory offsets rather than installer's header offset
|
|
left = BLOCKS_NUM;
|
|
while (left--)
|
|
header->blocks[left].offset += (int)data;
|
|
|
|
#ifdef NSIS_COMPRESS_WHOLE
|
|
header->blocks[NB_DATA].offset = dbd_pos;
|
|
#else
|
|
header->blocks[NB_DATA].offset = SetFilePointer(db_hFile,0,NULL,FILE_CURRENT);
|
|
#endif
|
|
|
|
mini_memcpy(&g_blocks, &header->blocks, sizeof(g_blocks));
|
|
|
|
return 0;
|
|
}
|
|
|
|
#define IBUFSIZE 16384
|
|
#define OBUFSIZE 32768
|
|
|
|
// returns -3 if compression error/eof/etc
|
|
|
|
#if !defined(NSIS_COMPRESS_WHOLE) || !defined(NSIS_CONFIG_COMPRESSION_SUPPORT)
|
|
|
|
int NSISCALL _dodecomp(int offset, HANDLE hFileOut, char *outbuf, int outbuflen)
|
|
{
|
|
static char inbuffer[IBUFSIZE+OBUFSIZE];
|
|
char *outbuffer;
|
|
int outbuffer_len=outbuf?outbuflen:OBUFSIZE;
|
|
int retval=0;
|
|
int input_len;
|
|
|
|
outbuffer = outbuf?outbuf:(inbuffer+IBUFSIZE);
|
|
|
|
if (offset>=0)
|
|
{
|
|
SetSelfFilePointer(g_blocks[NB_DATA].offset+offset);
|
|
}
|
|
|
|
if (!ReadSelfFile((LPVOID)&input_len,sizeof(int))) return -3;
|
|
|
|
#ifdef NSIS_CONFIG_COMPRESSION_SUPPORT
|
|
if (input_len & 0x80000000) // compressed
|
|
{
|
|
char progress[64];
|
|
int input_len_total;
|
|
DWORD ltc = GetTickCount(), tc;
|
|
|
|
inflateReset(&g_inflate_stream);
|
|
input_len_total = input_len &= 0x7fffffff; // take off top bit.
|
|
|
|
while (input_len > 0)
|
|
{
|
|
int l=min(input_len,IBUFSIZE);
|
|
int err;
|
|
|
|
if (!ReadSelfFile((LPVOID)inbuffer,l))
|
|
return -3;
|
|
|
|
g_inflate_stream.next_in = inbuffer;
|
|
g_inflate_stream.avail_in = l;
|
|
input_len-=l;
|
|
|
|
for (;;)
|
|
{
|
|
int u;
|
|
|
|
g_inflate_stream.next_out = outbuffer;
|
|
g_inflate_stream.avail_out = (unsigned int)outbuffer_len;
|
|
|
|
err=inflate(&g_inflate_stream);
|
|
|
|
if (err<0) return -4;
|
|
|
|
u=(char*)g_inflate_stream.next_out - outbuffer;
|
|
|
|
tc = GetTickCount();
|
|
if (g_exec_flags.status_update & 1 && (tc - ltc > 200 || !input_len))
|
|
{
|
|
wsprintf(progress, "... %d%%", MulDiv(input_len_total - input_len, 100, input_len_total));
|
|
update_status_text(0, progress);
|
|
ltc = tc;
|
|
}
|
|
|
|
// if there's no output, more input is needed
|
|
if (!u)
|
|
break;
|
|
|
|
if (!outbuf)
|
|
{
|
|
DWORD r;
|
|
if (!WriteFile(hFileOut,outbuffer,u,&r,NULL) || (int)r != u) return -2;
|
|
retval+=u;
|
|
}
|
|
else
|
|
{
|
|
retval+=u;
|
|
outbuffer_len-=u;
|
|
outbuffer=g_inflate_stream.next_out;
|
|
}
|
|
if (err==Z_STREAM_END) return retval;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
#endif//NSIS_CONFIG_COMPRESSION_SUPPORT
|
|
{
|
|
if (!outbuf)
|
|
{
|
|
while (input_len > 0)
|
|
{
|
|
DWORD l=min(input_len,outbuffer_len);
|
|
DWORD t;
|
|
if (!ReadSelfFile((LPVOID)inbuffer,l)) return -3;
|
|
if (!WriteFile(hFileOut,inbuffer,l,&t,NULL) || l!=t) return -2;
|
|
retval+=l;
|
|
input_len-=l;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
int l=min(input_len,outbuflen);
|
|
if (!ReadSelfFile((LPVOID)outbuf,l)) return -3;
|
|
retval=l;
|
|
}
|
|
}
|
|
return retval;
|
|
}
|
|
#else//NSIS_COMPRESS_WHOLE
|
|
|
|
static char _inbuffer[IBUFSIZE];
|
|
static char _outbuffer[OBUFSIZE];
|
|
extern int m_length;
|
|
extern int m_pos;
|
|
extern BOOL CALLBACK verProc(HWND, UINT, WPARAM, LPARAM);
|
|
extern BOOL CALLBACK DialogProc(HWND, UINT, WPARAM, LPARAM);
|
|
static int NSISCALL __ensuredata(int amount)
|
|
{
|
|
int needed=amount-(dbd_size-dbd_pos);
|
|
#ifdef NSIS_CONFIG_VISIBLE_SUPPORT
|
|
verify_time=GetTickCount()+500;
|
|
#endif
|
|
if (needed>0)
|
|
{
|
|
SetSelfFilePointer(dbd_srcpos);
|
|
SetFilePointer(dbd_hFile,dbd_size,NULL,FILE_BEGIN);
|
|
m_length=needed;
|
|
m_pos=0;
|
|
for (;;)
|
|
{
|
|
int err;
|
|
int l=min(IBUFSIZE,dbd_fulllen-dbd_srcpos);
|
|
if (!ReadSelfFile((LPVOID)_inbuffer,l)) return -1;
|
|
dbd_srcpos+=l;
|
|
g_inflate_stream.next_in=_inbuffer;
|
|
g_inflate_stream.avail_in=l;
|
|
do
|
|
{
|
|
DWORD r,t;
|
|
#ifdef NSIS_CONFIG_VISIBLE_SUPPORT
|
|
if (g_header)
|
|
#ifdef NSIS_CONFIG_SILENT_SUPPORT
|
|
if (!g_exec_flags.silent)
|
|
#endif
|
|
{
|
|
m_pos=m_length-(amount-(dbd_size-dbd_pos));
|
|
|
|
handle_ver_dlg(FALSE);
|
|
}
|
|
#endif//NSIS_CONFIG_VISIBLE_SUPPORT
|
|
g_inflate_stream.next_out=_outbuffer;
|
|
g_inflate_stream.avail_out=OBUFSIZE;
|
|
err=inflate(&g_inflate_stream);
|
|
if (err<0)
|
|
{
|
|
return -3;
|
|
}
|
|
r=(DWORD)g_inflate_stream.next_out-(DWORD)_outbuffer;
|
|
if (r)
|
|
{
|
|
if (!WriteFile(dbd_hFile,_outbuffer,r,&t,NULL) || r != t)
|
|
{
|
|
return -2;
|
|
}
|
|
dbd_size+=r;
|
|
}
|
|
else if (g_inflate_stream.avail_in || !l) return -3;
|
|
else break;
|
|
}
|
|
while (g_inflate_stream.avail_in);
|
|
if (amount-(dbd_size-dbd_pos) <= 0) break;
|
|
}
|
|
SetFilePointer(dbd_hFile,dbd_pos,NULL,FILE_BEGIN);
|
|
}
|
|
#ifdef NSIS_CONFIG_VISIBLE_SUPPORT
|
|
handle_ver_dlg(TRUE);
|
|
#endif//NSIS_CONFIG_VISIBLE_SUPPORT
|
|
return 0;
|
|
}
|
|
|
|
|
|
int NSISCALL _dodecomp(int offset, HANDLE hFileOut, char *outbuf, int outbuflen)
|
|
{
|
|
DWORD r;
|
|
int input_len;
|
|
int retval;
|
|
if (offset>=0)
|
|
{
|
|
dbd_pos=g_blocks[NB_DATA].offset+offset;
|
|
SetFilePointer(dbd_hFile,dbd_pos,NULL,FILE_BEGIN);
|
|
}
|
|
retval=__ensuredata(sizeof(int));
|
|
if (retval<0) return retval;
|
|
|
|
if (!ReadFile(dbd_hFile,(LPVOID)&input_len,sizeof(int),&r,NULL) || r!=sizeof(int)) return -3;
|
|
dbd_pos+=sizeof(int);
|
|
|
|
retval=__ensuredata(input_len);
|
|
if (retval < 0) return retval;
|
|
|
|
if (!outbuf)
|
|
{
|
|
while (input_len > 0)
|
|
{
|
|
DWORD t;
|
|
DWORD l=min(input_len,IBUFSIZE);
|
|
if (!ReadFile(dbd_hFile,(LPVOID)_inbuffer,l,&r,NULL) || l != r) return -3;
|
|
if (!WriteFile(hFileOut,_inbuffer,r,&t,NULL) || t != l) return -2;
|
|
retval+=r;
|
|
input_len-=r;
|
|
dbd_pos+=r;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!ReadFile(dbd_hFile,(LPVOID)outbuf,min(input_len,outbuflen),&r,NULL)) return -3;
|
|
retval=r;
|
|
dbd_pos+=r;
|
|
}
|
|
return retval;
|
|
}
|
|
#endif//NSIS_COMPRESS_WHOLE
|
|
|
|
BOOL NSISCALL ReadSelfFile(LPVOID lpBuffer, DWORD nNumberOfBytesToRead)
|
|
{
|
|
DWORD rd;
|
|
return ReadFile(g_db_hFile,lpBuffer,nNumberOfBytesToRead,&rd,NULL) && (rd == nNumberOfBytesToRead);
|
|
}
|
|
|
|
DWORD NSISCALL SetSelfFilePointer(LONG lDistanceToMove)
|
|
{
|
|
return SetFilePointer(g_db_hFile,lDistanceToMove,NULL,FILE_BEGIN);
|
|
}
|