diff --git a/SCons/Config/ms b/SCons/Config/ms index 87b24aa5..63164e76 100644 --- a/SCons/Config/ms +++ b/SCons/Config/ms @@ -122,6 +122,8 @@ makensis_env.Append(CCFLAGS = ['/Fa${TARGET}.lst']) # listing file name makensis_env.Append(LINKFLAGS = ['/opt:nowin98']) # 512 bytes align makensis_env.Append(LINKFLAGS = ['$MAP_FLAG']) # generate map file +if defenv['UNICODE']: + makensis_env.Append(LINKFLAGS = ['/stack:2097152']) # need 2 MB of stack in Unicode (default is 1 MB) ### plugin environment diff --git a/Source/ResourceVersionInfo.cpp b/Source/ResourceVersionInfo.cpp index 713a6d6d..68fed4d8 100644 --- a/Source/ResourceVersionInfo.cpp +++ b/Source/ResourceVersionInfo.cpp @@ -60,9 +60,11 @@ int CVersionStrigList::add(LANGID langid, int codepage) _stprintf(Buff, _T("%04x"), langid); int pos = SortedStringListND::add(Buff); if (pos == -1) return false; - ((struct version_string_list*)m_gr.get())[pos].pChildStrings = new DefineList; - ((struct version_string_list*)m_gr.get())[pos].codepage = codepage; - ((struct version_string_list*)m_gr.get())[pos].lang_id = langid; + + version_string_list *data = ((version_string_list *)m_gr.get())+ pos; + data->pChildStrings = new DefineList; + data->codepage = codepage; + data->lang_id = langid; return pos; } diff --git a/Source/ShConstants.cpp b/Source/ShConstants.cpp index 358f166a..1a0fd1df 100644 --- a/Source/ShConstants.cpp +++ b/Source/ShConstants.cpp @@ -28,10 +28,11 @@ int ConstantsStringList::add(const TCHAR *name, int value1, int value2) int pos=SortedStringListND::add(name); if (pos == -1) return -1; - ((struct constantstring*)m_gr.get())[pos].index = m_index; - ((struct constantstring*)m_gr.get())[pos].pos = pos; - ((struct constantstring*)m_gr.get())[pos].value1 = value1; - ((struct constantstring*)m_gr.get())[pos].value2 = value2; + constantstring *ptr = ((constantstring*) m_gr.get()) + pos; + ptr->index = m_index; + ptr->pos = pos; + ptr->value1 = value1; + ptr->value2 = value2; int temp = m_index; m_index++; diff --git a/Source/build.cpp b/Source/build.cpp index f61ed55f..d47a812b 100644 --- a/Source/build.cpp +++ b/Source/build.cpp @@ -2219,7 +2219,7 @@ void CEXEBuild::PrepareHeaders(IGrowBuf *hdrbuf) entry_writer::write_block(cur_entries, &sink); cur_header->blocks[NB_STRINGS].offset = sizeof(header) + blocks_buf.getlen(); - blocks_buf.add(cur_strlist->get(), cur_strlist->getlen()); + blocks_buf.add(cur_strlist->get(), cur_strlist->getcount()*sizeof(TCHAR)); cur_header->blocks[NB_LANGTABLES].offset = sizeof(header) + blocks_buf.getlen(); lang_table_writer::write_block(cur_langtables, &sink, cur_header->langtable_size); @@ -2653,7 +2653,7 @@ int CEXEBuild::write_output(void) int ne=build_header.blocks[NB_ENTRIES].num; INFO_MSG(_T("%d instruction%s (%d bytes), "),ne,ne==1?_T(""):_T("s"),ne*sizeof(entry)); int ns=build_strlist.getnum(); - INFO_MSG(_T("%d string%s (%d bytes), "),ns,ns==1?_T(""):_T("s"),build_strlist.getlen()); + INFO_MSG(_T("%d string%s (%d bytes), "),ns,ns==1?_T(""):_T("s"),build_strlist.getcount()*sizeof(TCHAR)); int nlt=build_header.blocks[NB_LANGTABLES].num; INFO_MSG(_T("%d language table%s (%d bytes).\n"),nlt,nlt==1?_T(""):_T("s"),build_langtables.getlen()); if (ubuild_entries.getlen()) @@ -2682,7 +2682,7 @@ int CEXEBuild::write_output(void) ne=build_uninst.blocks[NB_ENTRIES].num; INFO_MSG(_T("%d instruction%s (%d bytes), "),ne,ne==1?_T(""):_T("s"),ubuild_entries.getlen()); ns=ubuild_strlist.getnum(); - INFO_MSG(_T("%d string%s (%d bytes), "),ns,ns==1?_T(""):_T("s"),ubuild_strlist.getlen()); + INFO_MSG(_T("%d string%s (%d bytes), "),ns,ns==1?_T(""):_T("s"),ubuild_strlist.getcount()*sizeof(TCHAR)); nlt=build_uninst.blocks[NB_LANGTABLES].num; INFO_MSG(_T("%d language table%s (%d bytes).\n"),nlt,nlt==1?_T(""):_T("s"),ubuild_langtables.getlen()); } @@ -3287,7 +3287,7 @@ void CEXEBuild::INFO_MSG(const TCHAR *s, ...) const void CEXEBuild::print_warnings() { - int nw=0,x=m_warnings.getlen(); + int nw=0,x=m_warnings.getcount(); if (!x || !display_warnings) return; TCHAR *p=m_warnings.get(); while (x>0) if (!p[--x]) nw++; diff --git a/Source/exehead/fileform.h b/Source/exehead/fileform.h index e4a05bec..75d810a6 100644 --- a/Source/exehead/fileform.h +++ b/Source/exehead/fileform.h @@ -488,6 +488,8 @@ typedef struct { // don't want false end of string values so we shift then OR with 0x8080 #define CODE_SHORT(x) (WORD)((((WORD)(x) & 0x7F) | (((WORD)(x) & 0x3F80) << 1) | 0x8080)) #define MAX_CODED 16383 // 0x3FFF +// This macro takes a pointer to char +#define DECODE_SHORT(c) (((c[1] & 0x7F) << 7) | (c[0] & 0x7F)) #define NSIS_INSTDIR_INVALID 1 #define NSIS_INSTDIR_NOT_ENOUGH_SPACE 2 diff --git a/Source/exehead/util.c b/Source/exehead/util.c index 714a74ca..cc1b98f7 100644 --- a/Source/exehead/util.c +++ b/Source/exehead/util.c @@ -1,1055 +1,1057 @@ -/* - * util.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. - * - * Unicode support by Jim Park -- 08/11/2007 - */ - -#include "../Platform.h" -#include -#include "util.h" -#include "state.h" -#include "config.h" -#include "lang.h" -#include "fileform.h" -#include "exec.h" -#include "ui.h" -#include "resource.h" -#include "../tchar.h" - -#ifdef NSIS_CONFIG_LOG -#if !defined(NSIS_CONFIG_LOG_ODS) && !defined(NSIS_CONFIG_LOG_STDOUT) -TCHAR g_log_file[1024]; -#endif -#endif - -// *** DO NOT DECLARE MORE VARIABLES INSIDE THIS PRAGMAS *** -// This will produce a special section called ".ndata" (stands for nsis data) -// this way makensis during build time, can search for this section by name -// and change the virtual size of this section -// which result in extra memory for extra variables without code to do allocation :) -// nsis then removes the "DISCARDABLE" style from section (for safe) -#ifdef _MSC_VER -# pragma bss_seg(NSIS_VARS_SECTION) -NSIS_STRING g_usrvars[1]; -# pragma bss_seg() -# pragma comment(linker, "/section:" NSIS_VARS_SECTION ",rwd") -#else -# ifdef __GNUC__ -NSIS_STRING g_usrvars[1] __attribute__((section (NSIS_VARS_SECTION))); -# else -# error Unknown compiler. You must implement the seperate PE section yourself. -# endif -#endif - -HANDLE NSISCALL myCreateProcess(TCHAR *cmd) -{ - PROCESS_INFORMATION ProcInfo; - static STARTUPINFO StartUp; - StartUp.cb=sizeof(StartUp); - if (!CreateProcess(NULL, cmd, NULL, NULL, FALSE, 0, NULL, NULL, &StartUp, &ProcInfo)) - return NULL; - CloseHandle(ProcInfo.hThread); - return ProcInfo.hProcess; -} - -/*BOOL NSISCALL my_SetWindowText(HWND hWnd, const TCHAR *val) -{ - return SendMessage(hWnd,WM_SETTEXT,0,(LPARAM)val); -}*/ - -BOOL NSISCALL my_SetDialogItemText(HWND dlg, UINT idx, const TCHAR *val) -{ - return SetDlgItemText(dlg,idx,val); -// return my_SetWindowText(GetDlgItem(dlg, idx), val); -} - -int NSISCALL my_GetDialogItemText(UINT idx, TCHAR *val) -{ - extern HWND m_curwnd; - return GetDlgItemText(m_curwnd, idx, val, NSIS_MAX_STRLEN); -// return my_GetWindowText(GetDlgItem(m_curwnd, idx), val, NSIS_MAX_STRLEN); -} - -int NSISCALL my_MessageBox(const TCHAR *text, UINT type) { - int _type = type & 0x001FFFFF; - static MSGBOXPARAMS mbp = { - sizeof(MSGBOXPARAMS), - 0, - 0, - 0, - 0, - 0, - MAKEINTRESOURCE(IDI_ICON2), - 0, - 0, - 0 - }; - -#ifdef NSIS_CONFIG_SILENT_SUPPORT - // default for silent installers - if (g_exec_flags.silent && type >> 21) - return type >> 21; -#endif - // no silent or no default, just show - if (g_exec_flags.rtl) - _type ^= MB_RIGHT | MB_RTLREADING; - - mbp.hwndOwner = g_hwnd; - mbp.hInstance = g_hInstance; - mbp.lpszText = text; - mbp.lpszCaption = g_caption; - mbp.dwStyle = _type; - - return MessageBoxIndirect(&mbp); -} - -void NSISCALL myDelete(TCHAR *buf, int flags) -{ - static TCHAR lbuf[NSIS_MAX_STRLEN]; - - HANDLE h; - WIN32_FIND_DATA fd; - TCHAR *fn; - int valid_dir=is_valid_instpath(buf); - - if ((flags & DEL_SIMPLE)) - { - g_exec_flags.exec_error += !DeleteFile(buf); - return; - } - -#ifdef NSIS_SUPPORT_RMDIR - if (!(flags & DEL_DIR) || (valid_dir && (flags & DEL_RECURSE))) -#endif//NSIS_SUPPORT_RMDIR - { - mystrcpy(lbuf,buf); -#ifdef NSIS_SUPPORT_RMDIR - if (flags & DEL_DIR) - mystrcat(lbuf,_T("\\*.*")); - else -#endif//NSIS_SUPPORT_RMDIR - trimslashtoend(buf); - - // only append backslash if the path isn't relative to the working directory [bug #1851273] - if (*buf || *lbuf == _T('\\')) - mystrcat(buf,_T("\\")); - - fn=buf+mystrlen(buf); - - h = FindFirstFile(lbuf,&fd); - if (h != INVALID_HANDLE_VALUE) - { - do - { - TCHAR *fdfn = fd.cFileName; - if (*findchar(fdfn, _T('?')) && *fd.cAlternateFileName) - // name contains unicode, use short name - fdfn = fd.cAlternateFileName; - -#ifdef NSIS_SUPPORT_RMDIR - if (fdfn[0] == _T('.') && !fdfn[1]) continue; - if (fdfn[0] == _T('.') && fdfn[1] == _T('.') && !fdfn[2]) continue; -#endif//NSIS_SUPPORT_RMDIR - { - mystrcpy(fn,fdfn); - if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) - { -#ifdef NSIS_SUPPORT_RMDIR - if ((flags & (DEL_DIR | DEL_RECURSE)) == (DEL_DIR | DEL_RECURSE)) - { - myDelete(buf,flags); - } -#endif//NSIS_SUPPORT_RMDIR - } - else - { - log_printf2(_T("Delete: DeleteFile(\"%s\")"),buf); - remove_ro_attr(buf); - if (!DeleteFile(buf)) - { -#ifdef NSIS_SUPPORT_MOVEONREBOOT - if (flags & DEL_REBOOT) - { - log_printf2(_T("Delete: DeleteFile on Reboot(\"%s\")"),buf); - update_status_text(LANG_DELETEONREBOOT,buf); - MoveFileOnReboot(buf,NULL); - } - else -#endif//NSIS_SUPPORT_MOVEONREBOOT - { - log_printf2(_T("Delete: DeleteFile failed(\"%s\")"),buf); - g_exec_flags.exec_error++; - } - } - else - update_status_text(LANG_DELETEFILE,buf); - } - } - } while (FindNextFile(h,&fd)); - FindClose(h); - } - -#ifdef NSIS_SUPPORT_RMDIR - if (flags & DEL_DIR) - fn[-1]=0; -#endif//NSIS_SUPPORT_RMDIR - } - -#ifdef NSIS_SUPPORT_RMDIR - if ((flags & DEL_DIR)) - { - if (!valid_dir) - { - log_printf2(_T("RMDir: RemoveDirectory invalid input(\"%s\")"),buf); - g_exec_flags.exec_error++; - } - else if (file_exists(buf)) - { - addtrailingslash(buf); - log_printf2(_T("RMDir: RemoveDirectory(\"%s\")"),buf); - remove_ro_attr(buf); - if (!RemoveDirectory(buf)) - { -#ifdef NSIS_SUPPORT_MOVEONREBOOT - if (flags & DEL_REBOOT) - { - log_printf2(_T("RMDir: RemoveDirectory on Reboot(\"%s\")"),buf); - update_status_text(LANG_DELETEONREBOOT,buf); - MoveFileOnReboot(buf,NULL); - } - else -#endif//NSIS_SUPPORT_MOVEONREBOOT - { - log_printf2(_T("RMDir: RemoveDirectory failed(\"%s\")"),buf); - g_exec_flags.exec_error++; - } - } - else - { - update_status_text(LANG_REMOVEDIR,buf); - } - } - } -#endif//NSIS_SUPPORT_RMDIR -} - -TCHAR *NSISCALL addtrailingslash(TCHAR *str) -{ - if (lastchar(str)!=_T('\\')) mystrcat(str,_T("\\")); - return str; -} - -/*char NSISCALL lastchar(const char *str) -{ - return *CharPrev(str,str+mystrlen(str)); -}*/ - -TCHAR * NSISCALL findchar(TCHAR *str, TCHAR c) -{ - while (*str && *str != c) - { - str = CharNext(str); - } - return str; -} - -// Separates a full path to the directory portion and file name portion -// and returns the pointer to the filename portion. -TCHAR * NSISCALL trimslashtoend(TCHAR *buf) -{ - TCHAR *p = buf + mystrlen(buf); - do - { - if (*p == _T('\\')) - break; - p = CharPrev(buf, p); - } while (p > buf); - - *p = 0; - - return p + 1; -} - -int NSISCALL validpathspec(TCHAR *ubuf) -{ - TCHAR dl = ubuf[0] | 0x20; // convert alleged drive letter to lower case - return ((ubuf[0] == _T('\\') && ubuf[1] == _T('\\')) || - (dl >= _T('a') && dl <= _T('z') && ubuf[1] == _T(':'))); -} - -TCHAR * NSISCALL skip_root(TCHAR *path) -{ - TCHAR *p = CharNext(path); - TCHAR *p2 = CharNext(p); - - if (*path && p[0] == _T(':') && p[1] == _T('\\')) - { - return CharNext(p2); - } - else if (path[0] == _T('\\') && path[1] == _T('\\')) - { - // skip host and share name - int x = 2; - while (x--) - { - p2 = findchar(p2, _T('\\')); - if (!*p2) - return NULL; - p2++; // skip backslash - } - - return p2; - } - else - return NULL; -} - -int NSISCALL is_valid_instpath(TCHAR *s) -{ - static TCHAR tmp[NSIS_MAX_STRLEN]; - TCHAR *root; - - mystrcpy(tmp, s); - - root = skip_root(tmp); - - if (!root) - return 0; - - // must be called after skip_root or AllowRootDirInstall won't work. - // validate_filename removes trailing blackslashes and so converts - // "C:\" to "C:" which is not a valid directory. skip_root returns - // NULL for "C:" so the above test returns 0. - // validate_filename is called so directories such as "C:\ " will - // not pass as a valid non-root directory. - validate_filename(root); - - if ((g_flags & CH_FLAGS_NO_ROOT_DIR) && (!*root || *root == _T('\\'))) - return 0; - - while (mystrlen(tmp) > root - tmp) - { - WIN32_FIND_DATA *fd = file_exists(tmp); - // if the directory bit not set then it's a file, which is not a valid inst dir... - // GetFileAttributes is not used because it doesn't work with certain files (error 32) - // as for concerns of the user using * or ?, that's invalid anyway... - if (fd && !(fd->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) - return 0; - trimslashtoend(tmp); - } - - // if the root drive exists - addtrailingslash(tmp); // don't check the current directory, check the root directory - if (GetFileAttributes(tmp) == INVALID_FILE_ATTRIBUTES) - return 0; - - return 1; -} - -// Used strictly for the wininit.ini file which is an ASCII file. -char * NSISCALL mystrstriA(char *a, const char *b) -{ - int l = lstrlenA(b); - while (lstrlenA(a) >= l) - { - char c = a[l]; - a[l] = 0; - if (!lstrcmpiA(a, b)) - { - a[l] = c; - return a; - } - a[l] = c; - a = CharNextA(a); - } - return NULL; -} - - -// mini_memcpy takes the number of bytes to copy. -void NSISCALL mini_memcpy(void *out, const void *in, int len) -{ - char *c_out=(char*)out; - char *c_in=(char *)in; - while (len-- > 0) - { - *c_out++=*c_in++; - } -} - -void NSISCALL remove_ro_attr(TCHAR *file) -{ - int attr = GetFileAttributes(file); - if (attr != INVALID_FILE_ATTRIBUTES) - SetFileAttributes(file,attr&(~FILE_ATTRIBUTE_READONLY)); -} - -HANDLE NSISCALL myOpenFile(const TCHAR *fn, DWORD da, DWORD cd) -{ - int attr = GetFileAttributes(fn); - return CreateFile( - fn, - da, - FILE_SHARE_READ, - NULL, - cd, - attr == INVALID_FILE_ATTRIBUTES ? 0 : attr, - NULL - ); -} - -TCHAR * NSISCALL my_GetTempFileName(TCHAR *buf, const TCHAR *dir) -{ - int n = 100; - while (n--) - { - TCHAR prefix[4] = _T("nsa"); - prefix[2] += (TCHAR)(GetTickCount() % 26); - if (GetTempFileName(dir, prefix, 0, buf)) - return buf; - } - *buf = 0; - return 0; -} - -#ifdef NSIS_SUPPORT_MOVEONREBOOT -/** Modifies the wininit.ini file to rename / delete a file. - * - * @param prevName The previous / current name of the file. - * @param newName The new name to move the file to. If NULL, the current file - * will be deleted. - */ -void RenameViaWininit(const TCHAR* prevName, const TCHAR* newName) -{ - static char szRenameLine[1024]; - static TCHAR wininit[1024]; - static TCHAR tmpbuf[1024]; - - int cchRenameLine; - LPCSTR szRenameSec = "[Rename]\r\n"; // rename section marker - HANDLE hfile; - DWORD dwFileSize; - DWORD dwBytes; - DWORD dwRenameLinePos; - char *pszWinInit; // Contains the file contents of wininit.ini - - int spn; // length of the short path name in TCHARs. - - lstrcpy(tmpbuf, _T("NUL")); - - if (newName) { - // create the file if it's not already there to prevent GetShortPathName from failing - CloseHandle(myOpenFile(newName,0,CREATE_NEW)); - spn = GetShortPathName(newName,tmpbuf,1024); - if (!spn || spn > 1024) - return; - } - // wininit is used as a temporary here - spn = GetShortPathName(prevName,wininit,1024); - if (!spn || spn > 1024) - return; - cchRenameLine = wsprintfA(szRenameLine, "%s=%s\r\n", tmpbuf, wininit); - // Get the path to the wininit.ini file. - GetNSISString(wininit, g_header->str_wininit); - - hfile = myOpenFile(wininit, GENERIC_READ | GENERIC_WRITE, OPEN_ALWAYS); - - if (hfile != INVALID_HANDLE_VALUE) - { - // We are now working on the Windows wininit file - dwFileSize = GetFileSize(hfile, NULL); - pszWinInit = (char*) GlobalAlloc(GPTR, dwFileSize + cchRenameLine + 10); - - if (pszWinInit != NULL) - { - if (ReadFile(hfile, pszWinInit, dwFileSize, &dwBytes, NULL) && dwFileSize == dwBytes) - { - // Look for the rename section in the current file. - LPSTR pszRenameSecInFile = mystrstriA(pszWinInit, szRenameSec); - if (pszRenameSecInFile == NULL) - { - // No rename section. So we add it to the end of file. - lstrcpyA(pszWinInit+dwFileSize, szRenameSec); - dwFileSize += 10; - dwRenameLinePos = dwFileSize; - } - else - { - // There is a rename section, but is there another section after it? - char *pszFirstRenameLine = pszRenameSecInFile+10; - char *pszNextSec = mystrstriA(pszFirstRenameLine,"\n["); - if (pszNextSec) - { - char *p = ++pszNextSec; - while (p < pszWinInit + dwFileSize) { - p[cchRenameLine] = *p; - p++; - } - - dwRenameLinePos = pszNextSec - pszWinInit; - } - // rename section is last, stick item at end of file - else dwRenameLinePos = dwFileSize; - } - - mini_memcpy(&pszWinInit[dwRenameLinePos], szRenameLine, cchRenameLine); - dwFileSize += cchRenameLine; - - SetFilePointer(hfile, 0, NULL, FILE_BEGIN); - WriteFile(hfile, pszWinInit, dwFileSize, &dwBytes, NULL); - - GlobalFree(pszWinInit); - } - } - - CloseHandle(hfile); - } -} - -/** - * MoveFileOnReboot tries to move a file by the name of pszExisting to the - * name pszNew. - * - * @param pszExisting The old name of the file. - * @param pszNew The new name of the file. - */ -void NSISCALL MoveFileOnReboot(LPCTSTR pszExisting, LPCTSTR pszNew) -{ - BOOL fOk = 0; - typedef BOOL (WINAPI *mfea_t)(LPCTSTR lpExistingFileName,LPCTSTR lpNewFileName,DWORD dwFlags); - mfea_t mfea; - mfea=(mfea_t) myGetProcAddress(MGA_MoveFileEx); - if (mfea) - { - fOk=mfea(pszExisting, pszNew, MOVEFILE_DELAY_UNTIL_REBOOT|MOVEFILE_REPLACE_EXISTING); - } - - if (!fOk) - { - RenameViaWininit(pszExisting, pszNew); - } - -#ifdef NSIS_SUPPORT_REBOOT - g_exec_flags.exec_reboot++; -#endif -} -#endif - -// The value of registry->sub->name is stored in out. If failure, then out becomes -// an empty string "". -void NSISCALL myRegGetStr(HKEY root, const TCHAR *sub, const TCHAR *name, TCHAR *out, int x64) -{ - HKEY hKey; - *out=0; - if (RegOpenKeyEx(root,sub,0,KEY_READ|(x64?KEY_WOW64_64KEY:0),&hKey) == ERROR_SUCCESS) - { - DWORD l = NSIS_MAX_STRLEN*sizeof(TCHAR); - DWORD t; - // Note that RegQueryValueEx returns Unicode strings if _UNICODE is defined for the - // REG_SZ type. - if (RegQueryValueEx(hKey,name,NULL,&t,(LPBYTE)out,&l ) != ERROR_SUCCESS || (t != REG_SZ && t != REG_EXPAND_SZ)) *out=0; - out[NSIS_MAX_STRLEN-1]=0; - RegCloseKey(hKey); - } -} - -void NSISCALL myitoa(TCHAR *s, int d) -{ - static const TCHAR c[] = _T("%d"); - wsprintf(s,c,d); -} - -int NSISCALL myatoi(TCHAR *s) -{ - unsigned int v=0; - int sign=1; // sign of positive - TCHAR m=10; // base of 10 - TCHAR t=_T('9'); // cap top of numbers at 9 - - if (*s == _T('-')) - { - s++; //skip over - - sign=-1; // sign flip - } - - if (*s == _T('0')) - { - s++; // skip over 0 - if (s[0] >= _T('0') && s[0] <= _T('7')) - { - m=8; // base of 8 - t=_T('7'); // cap top at 7 - } - if ((s[0] & ~0x20) == _T('X')) - { - m=16; // base of 16 - s++; // advance over 'x' - } - } - - for (;;) - { - int c=*s++; - if (c >= _T('0') && c <= t) c-=_T('0'); - // clever little trick to do both upper and lowercase A-F. - else if (m==16 && (c & ~0x20) >= _T('A') && (c & ~0x20) <= _T('F')) c = (c & 7) + 9; - else break; - v*=m; - v+=c; - } - return ((int)v)*sign; -} - -// Straight copies of selected shell functions. Calling local functions -// requires less code than DLL functions. For the savings to outweigh the cost -// of a new function there should be about a couple of dozen or so calls. -TCHAR * NSISCALL mystrcpy(TCHAR *out, const TCHAR *in) -{ - return lstrcpyn(out, in, NSIS_MAX_STRLEN); -} - -int NSISCALL mystrlen(const TCHAR *in) -{ - return lstrlen(in); -} - -TCHAR * NSISCALL mystrcat(TCHAR *out, const TCHAR *concat) -{ - return lstrcat(out, concat); -} - -TCHAR ps_tmpbuf[NSIS_MAX_STRLEN*2]; - -const TCHAR SYSREGKEY[] = _T("Software\\Microsoft\\Windows\\CurrentVersion"); -const TCHAR QUICKLAUNCH[] = _T("\\Microsoft\\Internet Explorer\\Quick Launch"); - -typedef HRESULT (__stdcall * PFNSHGETFOLDERPATH)(HWND, int, HANDLE, DWORD, LPTSTR); -extern void *g_SHGetFolderPath; - -// Based on Dave Laundon's simplified process_string -// The string actually has a lot of different data encoded into it. This -// function extracts the special data out and puts it into outbuf. -TCHAR * NSISCALL GetNSISString(TCHAR *outbuf, int strtab) -{ - // This looks at the g_block (copied from header->blocks) and - // indexes into the language - TCHAR *in = (TCHAR*)GetNSISStringNP(GetNSISTab(strtab)); - TCHAR *out = ps_tmpbuf; - - // Still working within ps_tmpbuf, so set out to the - // current position that is passed in. - if (outbuf >= ps_tmpbuf && - (size_t) (outbuf - ps_tmpbuf) < COUNTOF(ps_tmpbuf)) - { - out = outbuf; - outbuf = 0; - } - - while (*in && out - ps_tmpbuf < NSIS_MAX_STRLEN) - { - _TUCHAR nVarIdx = (_TUCHAR)*in++; - int nData; - int fldrs[4]; - if (nVarIdx > NS_CODES_START) - { - nData = ((in[1] & 0x7F) << 7) | (in[0] & 0x7F); - fldrs[0] = in[0] | CSIDL_FLAG_CREATE; // current user - fldrs[1] = in[0]; - fldrs[2] = in[1] | CSIDL_FLAG_CREATE; // all users - fldrs[3] = in[1]; - in += sizeof(SHORT)/sizeof(TCHAR); - - if (nVarIdx == NS_SHELL_CODE) - { - LPITEMIDLIST idl; - - int x = 2; - DWORD ver = GetVersion(); - - /* - - SHGetFolderPath as provided by shfolder.dll is used to get special folders - unless the installer is running on Windows 95/98. For 95/98 shfolder.dll is - only used for the Application Data and Documents folder (if the DLL exists). - Otherwise, the old SHGetSpecialFolderLocation API is called. - - The reason for not using shfolder.dll for all folders on 95/98 is that some - unsupported folders (such as the Start Menu folder for all users) are - simulated instead of returning an error so we can fall back on the current - user folder. - - SHGetFolderPath in shell32.dll could be called directly for Windows versions - later than 95/98 but there is no need to do so, because shfolder.dll is still - provided and calls shell32.dll. - - */ - - BOOL use_shfolder = - // Use shfolder if not on 95/98 - !((ver & 0x80000000) && (LOWORD(ver) != 0x5A04)) || - - // Unless the Application Data or Documents folder is requested - ( - (fldrs[3] == CSIDL_COMMON_APPDATA) || - (fldrs[3] == CSIDL_COMMON_DOCUMENTS) - ); - - /* Carry on... shfolder stuff is over. */ - - if (g_exec_flags.all_user_var) - { - x = 4; - } - - if (fldrs[1] & 0x80) - { - myRegGetStr(HKEY_LOCAL_MACHINE, SYSREGKEY, GetNSISStringNP(fldrs[1] & 0x3F), out, fldrs[1] & 0x40); - if (!*out) - GetNSISString(out, fldrs[3]); - x = 0; - } - else if (fldrs[1] == CSIDL_SYSTEM) - { - GetSystemDirectory(out, NSIS_MAX_STRLEN); - x = 0; - } - else if (fldrs[1] == CSIDL_WINDOWS) - { - GetWindowsDirectory(out, NSIS_MAX_STRLEN); - x = 0; - } - - while (x--) - { - if (g_SHGetFolderPath && use_shfolder) - { - PFNSHGETFOLDERPATH SHGetFolderPathFunc = (PFNSHGETFOLDERPATH) g_SHGetFolderPath; - if (!SHGetFolderPathFunc(g_hwnd, fldrs[x], NULL, SHGFP_TYPE_CURRENT, out)) - { - break; - } - } - - if (!SHGetSpecialFolderLocation(g_hwnd, fldrs[x], &idl)) - { - BOOL res = SHGetPathFromIDList(idl, out); - CoTaskMemFree(idl); - if (res) break; - } - - *out=0; - } - - if (*out) - { - // all users' version is CSIDL_APPDATA only for $QUICKLAUNCH - // for normal $APPDATA, it'd be CSIDL_APPDATA_COMMON - if (fldrs[3] == CSIDL_APPDATA) - { - mystrcat(out, QUICKLAUNCH); - } - } - validate_filename(out); - } - else if (nVarIdx == NS_VAR_CODE) - { - if (nData == 29) // $HWNDPARENT - myitoa(out, (unsigned int) g_hwnd); - else - mystrcpy(out, g_usrvars[nData]); - // validate the directory name - if ((unsigned int)(nData - 21) < 7) { - // validate paths for $INSTDIR, $OUTDIR, $EXEDIR, $LANGUAGE, $TEMP, $PLUGINSDIR and $EXEPATH - // $LANGUAGE is just a number anyway... - validate_filename(out); - } - } // == VAR_CODES_START - else if (nVarIdx == NS_LANG_CODE) - { - GetNSISString(out, -nData-1); - } - out += mystrlen(out); - } - else if (nVarIdx == NS_SKIP_CODE) - { - *out++ = *in++; - } - else // Normal char - { - *out++ = nVarIdx; - } - } // while - *out = 0; - if (outbuf) - return mystrcpy(outbuf, ps_tmpbuf); - return ps_tmpbuf; -} - -void NSISCALL validate_filename(TCHAR *in) { - TCHAR *nono = _T("*?|<>/\":"); - TCHAR *out; - TCHAR *out_save; - - // ignoring spaces is wrong, _T(" C:\blah") is invalid - //while (*in == _T(' ')) in = CharNext(in); - - if (in[0] == _T('\\') && in[1] == _T('\\') && in[2] == _T('?') && in[3] == _T('\\')) - { - // at least four bytes - in += 4; - } - if (*in) - { - // at least two bytes - if (validpathspec(in)) in += 2; - } - out = out_save = in; - while (*in) - { - if ((_TUCHAR)*in > 31 && !*findchar(nono, *in)) - { - mini_memcpy(out, in, CharNext(in) - in); - out = CharNext(out); - } - in = CharNext(in); - } - *out = 0; - do - { - out = CharPrev(out_save, out); - if (*out == _T(' ') || *out == _T('\\')) - *out = 0; - else - break; - } while (out_save < out); -} - -#ifdef NSIS_CONFIG_LOG -int log_dolog; -TCHAR log_text[2048]; // 1024 for each wsprintf - -#if !defined(NSIS_CONFIG_LOG_ODS) && !defined(NSIS_CONFIG_LOG_STDOUT) -void NSISCALL log_write(int close) -{ - static HANDLE fp=INVALID_HANDLE_VALUE; - if (close) - { - if (fp!=INVALID_HANDLE_VALUE) - { - CloseHandle(fp); - } - fp=INVALID_HANDLE_VALUE; - return; - } - if (log_dolog) - { - if (g_log_file[0] && fp==INVALID_HANDLE_VALUE) - { - fp = myOpenFile(g_log_file,GENERIC_WRITE,OPEN_ALWAYS); - if (fp!=INVALID_HANDLE_VALUE) - SetFilePointer(fp,0,NULL,FILE_END); - } - if (fp!=INVALID_HANDLE_VALUE) - { - DWORD d; - mystrcat(log_text,_T("\r\n")); - WriteFile(fp,log_text,mystrlen(log_text)*sizeof(TCHAR),&d,NULL); - } - } -} -#endif//!NSIS_CONFIG_LOG_ODS && !NSIS_CONFIG_LOG_STDOUT - -const TCHAR * _RegKeyHandleToName(HKEY hKey) -{ - if (hKey == HKEY_CLASSES_ROOT) - return _T("HKEY_CLASSES_ROOT"); - else if (hKey == HKEY_CURRENT_USER) - return _T("HKEY_CURRENT_USER"); - else if (hKey == HKEY_LOCAL_MACHINE) - return _T("HKEY_LOCAL_MACHINE"); - else if (hKey == HKEY_USERS) - return _T("HKEY_USERS"); - else if (hKey == HKEY_PERFORMANCE_DATA) - return _T("HKEY_PERFORMANCE_DATA"); - else if (hKey == HKEY_CURRENT_CONFIG) - return _T("HKEY_CURRENT_CONFIG"); - else if (hKey == HKEY_DYN_DATA) - return _T("HKEY_DYN_DATA"); - else - return _T("invalid registry key"); -} - -void _LogData2Hex(TCHAR *buf, size_t buflen, BYTE *data, size_t datalen) -{ - TCHAR *p = buf; - - size_t i; - - int dots = 0; - size_t bufbytes = buflen / 3; // 2 hex digits, one space/null - - if (datalen > bufbytes) - { - bufbytes--; - dots = 1; - } - else - bufbytes = datalen; - - for (i = 0; i < bufbytes; i++) - { - wsprintf(p, _T("%02x%c"), data[i], (i == bufbytes - 1) ? _T('\0') : _T(' ')); - p += 3; - } - - if (dots) - mystrcat(buf, _T("...")); -} - -#ifdef NSIS_CONFIG_LOG_TIMESTAMP -void log_timestamp(TCHAR *buf) -{ - SYSTEMTIME st; - GetLocalTime(&st); - wsprintf(buf,_T("[%04hu/%02hu/%02hu %02hu:%02hu:%02hu] "), st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond); -} -#else -# define log_timestamp(x) -#endif//NSIS_CONFIG_LOG_TIMESTAMP - -void log_printf(TCHAR *format, ...) -{ - va_list val; - va_start(val,format); - - log_text[0] = _T('\0'); - log_timestamp(log_text); - wvsprintf(log_text+mystrlen(log_text),format,val); - - va_end(val); -#ifdef NSIS_CONFIG_LOG_ODS - if (log_dolog) - OutputDebugString(log_text); -#endif -#ifdef NSIS_CONFIG_LOG_STDOUT - if (log_dolog && GetStdHandle(STD_OUTPUT_HANDLE) != INVALID_HANDLE_VALUE) - { - DWORD dwBytes; - WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), log_text, lstrlen(log_text), &dwBytes, NULL); - WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), _T("\n"), 1, &dwBytes, NULL); - } -#endif -#if !defined(NSIS_CONFIG_LOG_ODS) && !defined(NSIS_CONFIG_LOG_STDOUT) - log_write(0); -#endif -} -#endif//NSIS_CONFIG_LOG - -// Jim Park: This function is non-reentrant because of the static. -WIN32_FIND_DATA * NSISCALL file_exists(TCHAR *buf) -{ - HANDLE h; - static WIN32_FIND_DATA fd; - h = FindFirstFile(buf,&fd); - if (h != INVALID_HANDLE_VALUE) - { - FindClose(h); - return &fd; - } - return NULL; -} - -// Jim Park: Keep these as chars since there's only ANSI version of -// GetProcAddress. -struct MGA_FUNC -{ - const char *dll; - const char *func; -}; - -#ifdef _UNICODE -struct MGA_FUNC MGA_FUNCS[] = { - {"KERNEL32", "GetDiskFreeSpaceExW"}, - {"KERNEL32", "MoveFileExW"}, - {"ADVAPI32", "RegDeleteKeyExW"}, - {"ADVAPI32", "OpenProcessToken"}, - {"ADVAPI32", "LookupPrivilegeValueW"}, - {"ADVAPI32", "AdjustTokenPrivileges"}, - {"KERNEL32", "GetUserDefaultUILanguage"}, - {"SHLWAPI", "SHAutoComplete"}, - {"SHFOLDER", "SHGetFolderPathW"} -}; -#else -struct MGA_FUNC MGA_FUNCS[] = { - {"KERNEL32", "GetDiskFreeSpaceExA"}, - {"KERNEL32", "MoveFileExA"}, - {"ADVAPI32", "RegDeleteKeyExA"}, - {"ADVAPI32", "OpenProcessToken"}, - {"ADVAPI32", "LookupPrivilegeValueA"}, - {"ADVAPI32", "AdjustTokenPrivileges"}, - {"KERNEL32", "GetUserDefaultUILanguage"}, - {"SHLWAPI", "SHAutoComplete"}, - {"SHFOLDER", "SHGetFolderPathA"} -}; -#endif - -/** - * Given a function enum, it will load the appropriate DLL and get the - * process address of the function and return the pointer. It's up to - * the caller to know how to call that function, however. - * - * @param func Enum value that indexes the MGA_FUNCS array. - * @return Pointer to the function identified by the enum value. - */ -void * NSISCALL myGetProcAddress(const enum myGetProcAddressFunctions func) -{ - const char *dll = MGA_FUNCS[func].dll; - HMODULE hModule = GetModuleHandleA(dll); - if (!hModule) - hModule = LoadLibraryA(dll); - if (!hModule) - return NULL; - - return GetProcAddress(hModule, MGA_FUNCS[func].func); -} - -void NSISCALL MessageLoop(UINT uCheckedMsg) -{ - MSG msg; - while (PeekMessage(&msg, NULL, uCheckedMsg, uCheckedMsg, PM_REMOVE)) - DispatchMessage(&msg); -} - -/** - * This function is useful for Unicode support. Since the Windows - * GetProcAddress function always takes a char*, this function wraps - * the windows call and does the appropriate translation when - * appropriate. - * - * @param dllHandle Handle to the DLL loaded by LoadLibraryEx. - * @param funcName The name of the function to get the address of. - * @return The pointer to the function. Null if failure. - */ -void * NSISCALL NSISGetProcAddress(HANDLE dllHandle, TCHAR* funcName) -{ -#ifdef _UNICODE - char ansiName[NSIS_MAX_STRLEN]; - if (WideCharToMultiByte(CP_ACP, 0, funcName, -1, ansiName, NSIS_MAX_STRLEN, NULL, NULL) != 0) - return GetProcAddress(dllHandle, ansiName); - return NULL; -#else - return GetProcAddress(dllHandle, funcName); -#endif -} +/* + * util.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. + * + * Unicode support by Jim Park -- 08/11/2007 + */ + +#include "../Platform.h" +#include +#include "util.h" +#include "state.h" +#include "config.h" +#include "lang.h" +#include "fileform.h" +#include "exec.h" +#include "ui.h" +#include "resource.h" +#include "../tchar.h" + +#ifdef NSIS_CONFIG_LOG +#if !defined(NSIS_CONFIG_LOG_ODS) && !defined(NSIS_CONFIG_LOG_STDOUT) +TCHAR g_log_file[1024]; +#endif +#endif + +// *** DO NOT DECLARE MORE VARIABLES INSIDE THIS PRAGMAS *** +// This will produce a special section called ".ndata" (stands for nsis data) +// this way makensis during build time, can search for this section by name +// and change the virtual size of this section +// which result in extra memory for extra variables without code to do allocation :) +// nsis then removes the "DISCARDABLE" style from section (for safe) +#ifdef _MSC_VER +# pragma bss_seg(NSIS_VARS_SECTION) +NSIS_STRING g_usrvars[1]; +# pragma bss_seg() +# pragma comment(linker, "/section:" NSIS_VARS_SECTION ",rwd") +#else +# ifdef __GNUC__ +NSIS_STRING g_usrvars[1] __attribute__((section (NSIS_VARS_SECTION))); +# else +# error Unknown compiler. You must implement the seperate PE section yourself. +# endif +#endif + +HANDLE NSISCALL myCreateProcess(TCHAR *cmd) +{ + PROCESS_INFORMATION ProcInfo; + static STARTUPINFO StartUp; + StartUp.cb=sizeof(StartUp); + if (!CreateProcess(NULL, cmd, NULL, NULL, FALSE, 0, NULL, NULL, &StartUp, &ProcInfo)) + return NULL; + CloseHandle(ProcInfo.hThread); + return ProcInfo.hProcess; +} + +/*BOOL NSISCALL my_SetWindowText(HWND hWnd, const TCHAR *val) +{ + return SendMessage(hWnd,WM_SETTEXT,0,(LPARAM)val); +}*/ + +BOOL NSISCALL my_SetDialogItemText(HWND dlg, UINT idx, const TCHAR *val) +{ + return SetDlgItemText(dlg,idx,val); +// return my_SetWindowText(GetDlgItem(dlg, idx), val); +} + +int NSISCALL my_GetDialogItemText(UINT idx, TCHAR *val) +{ + extern HWND m_curwnd; + return GetDlgItemText(m_curwnd, idx, val, NSIS_MAX_STRLEN); +// return my_GetWindowText(GetDlgItem(m_curwnd, idx), val, NSIS_MAX_STRLEN); +} + +int NSISCALL my_MessageBox(const TCHAR *text, UINT type) { + int _type = type & 0x001FFFFF; + static MSGBOXPARAMS mbp = { + sizeof(MSGBOXPARAMS), + 0, + 0, + 0, + 0, + 0, + MAKEINTRESOURCE(IDI_ICON2), + 0, + 0, + 0 + }; + +#ifdef NSIS_CONFIG_SILENT_SUPPORT + // default for silent installers + if (g_exec_flags.silent && type >> 21) + return type >> 21; +#endif + // no silent or no default, just show + if (g_exec_flags.rtl) + _type ^= MB_RIGHT | MB_RTLREADING; + + mbp.hwndOwner = g_hwnd; + mbp.hInstance = g_hInstance; + mbp.lpszText = text; + mbp.lpszCaption = g_caption; + mbp.dwStyle = _type; + + return MessageBoxIndirect(&mbp); +} + +void NSISCALL myDelete(TCHAR *buf, int flags) +{ + static TCHAR lbuf[NSIS_MAX_STRLEN]; + + HANDLE h; + WIN32_FIND_DATA fd; + TCHAR *fn; + int valid_dir=is_valid_instpath(buf); + + if ((flags & DEL_SIMPLE)) + { + g_exec_flags.exec_error += !DeleteFile(buf); + return; + } + +#ifdef NSIS_SUPPORT_RMDIR + if (!(flags & DEL_DIR) || (valid_dir && (flags & DEL_RECURSE))) +#endif//NSIS_SUPPORT_RMDIR + { + mystrcpy(lbuf,buf); +#ifdef NSIS_SUPPORT_RMDIR + if (flags & DEL_DIR) + mystrcat(lbuf,_T("\\*.*")); + else +#endif//NSIS_SUPPORT_RMDIR + trimslashtoend(buf); + + // only append backslash if the path isn't relative to the working directory [bug #1851273] + if (*buf || *lbuf == _T('\\')) + mystrcat(buf,_T("\\")); + + fn=buf+mystrlen(buf); + + h = FindFirstFile(lbuf,&fd); + if (h != INVALID_HANDLE_VALUE) + { + do + { + TCHAR *fdfn = fd.cFileName; + if (*findchar(fdfn, _T('?')) && *fd.cAlternateFileName) + // name contains unicode, use short name + fdfn = fd.cAlternateFileName; + +#ifdef NSIS_SUPPORT_RMDIR + if (fdfn[0] == _T('.') && !fdfn[1]) continue; + if (fdfn[0] == _T('.') && fdfn[1] == _T('.') && !fdfn[2]) continue; +#endif//NSIS_SUPPORT_RMDIR + { + mystrcpy(fn,fdfn); + if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + { +#ifdef NSIS_SUPPORT_RMDIR + if ((flags & (DEL_DIR | DEL_RECURSE)) == (DEL_DIR | DEL_RECURSE)) + { + myDelete(buf,flags); + } +#endif//NSIS_SUPPORT_RMDIR + } + else + { + log_printf2(_T("Delete: DeleteFile(\"%s\")"),buf); + remove_ro_attr(buf); + if (!DeleteFile(buf)) + { +#ifdef NSIS_SUPPORT_MOVEONREBOOT + if (flags & DEL_REBOOT) + { + log_printf2(_T("Delete: DeleteFile on Reboot(\"%s\")"),buf); + update_status_text(LANG_DELETEONREBOOT,buf); + MoveFileOnReboot(buf,NULL); + } + else +#endif//NSIS_SUPPORT_MOVEONREBOOT + { + log_printf2(_T("Delete: DeleteFile failed(\"%s\")"),buf); + g_exec_flags.exec_error++; + } + } + else + update_status_text(LANG_DELETEFILE,buf); + } + } + } while (FindNextFile(h,&fd)); + FindClose(h); + } + +#ifdef NSIS_SUPPORT_RMDIR + if (flags & DEL_DIR) + fn[-1]=0; +#endif//NSIS_SUPPORT_RMDIR + } + +#ifdef NSIS_SUPPORT_RMDIR + if ((flags & DEL_DIR)) + { + if (!valid_dir) + { + log_printf2(_T("RMDir: RemoveDirectory invalid input(\"%s\")"),buf); + g_exec_flags.exec_error++; + } + else if (file_exists(buf)) + { + addtrailingslash(buf); + log_printf2(_T("RMDir: RemoveDirectory(\"%s\")"),buf); + remove_ro_attr(buf); + if (!RemoveDirectory(buf)) + { +#ifdef NSIS_SUPPORT_MOVEONREBOOT + if (flags & DEL_REBOOT) + { + log_printf2(_T("RMDir: RemoveDirectory on Reboot(\"%s\")"),buf); + update_status_text(LANG_DELETEONREBOOT,buf); + MoveFileOnReboot(buf,NULL); + } + else +#endif//NSIS_SUPPORT_MOVEONREBOOT + { + log_printf2(_T("RMDir: RemoveDirectory failed(\"%s\")"),buf); + g_exec_flags.exec_error++; + } + } + else + { + update_status_text(LANG_REMOVEDIR,buf); + } + } + } +#endif//NSIS_SUPPORT_RMDIR +} + +TCHAR *NSISCALL addtrailingslash(TCHAR *str) +{ + if (lastchar(str)!=_T('\\')) mystrcat(str,_T("\\")); + return str; +} + +/*char NSISCALL lastchar(const char *str) +{ + return *CharPrev(str,str+mystrlen(str)); +}*/ + +TCHAR * NSISCALL findchar(TCHAR *str, TCHAR c) +{ + while (*str && *str != c) + { + str = CharNext(str); + } + return str; +} + +// Separates a full path to the directory portion and file name portion +// and returns the pointer to the filename portion. +TCHAR * NSISCALL trimslashtoend(TCHAR *buf) +{ + TCHAR *p = buf + mystrlen(buf); + do + { + if (*p == _T('\\')) + break; + p = CharPrev(buf, p); + } while (p > buf); + + *p = 0; + + return p + 1; +} + +int NSISCALL validpathspec(TCHAR *ubuf) +{ + TCHAR dl = ubuf[0] | 0x20; // convert alleged drive letter to lower case + return ((ubuf[0] == _T('\\') && ubuf[1] == _T('\\')) || + (dl >= _T('a') && dl <= _T('z') && ubuf[1] == _T(':'))); +} + +TCHAR * NSISCALL skip_root(TCHAR *path) +{ + TCHAR *p = CharNext(path); + TCHAR *p2 = CharNext(p); + + if (*path && p[0] == _T(':') && p[1] == _T('\\')) + { + return CharNext(p2); + } + else if (path[0] == _T('\\') && path[1] == _T('\\')) + { + // skip host and share name + int x = 2; + while (x--) + { + p2 = findchar(p2, _T('\\')); + if (!*p2) + return NULL; + p2++; // skip backslash + } + + return p2; + } + else + return NULL; +} + +int NSISCALL is_valid_instpath(TCHAR *s) +{ + static TCHAR tmp[NSIS_MAX_STRLEN]; + TCHAR *root; + + mystrcpy(tmp, s); + + root = skip_root(tmp); + + if (!root) + return 0; + + // must be called after skip_root or AllowRootDirInstall won't work. + // validate_filename removes trailing blackslashes and so converts + // "C:\" to "C:" which is not a valid directory. skip_root returns + // NULL for "C:" so the above test returns 0. + // validate_filename is called so directories such as "C:\ " will + // not pass as a valid non-root directory. + validate_filename(root); + + if ((g_flags & CH_FLAGS_NO_ROOT_DIR) && (!*root || *root == _T('\\'))) + return 0; + + while (mystrlen(tmp) > root - tmp) + { + WIN32_FIND_DATA *fd = file_exists(tmp); + // if the directory bit not set then it's a file, which is not a valid inst dir... + // GetFileAttributes is not used because it doesn't work with certain files (error 32) + // as for concerns of the user using * or ?, that's invalid anyway... + if (fd && !(fd->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) + return 0; + trimslashtoend(tmp); + } + + // if the root drive exists + addtrailingslash(tmp); // don't check the current directory, check the root directory + if (GetFileAttributes(tmp) == INVALID_FILE_ATTRIBUTES) + return 0; + + return 1; +} + +// Used strictly for the wininit.ini file which is an ASCII file. +char * NSISCALL mystrstriA(char *a, const char *b) +{ + int l = lstrlenA(b); + while (lstrlenA(a) >= l) + { + char c = a[l]; + a[l] = 0; + if (!lstrcmpiA(a, b)) + { + a[l] = c; + return a; + } + a[l] = c; + a = CharNextA(a); + } + return NULL; +} + + +// mini_memcpy takes the number of bytes to copy. +void NSISCALL mini_memcpy(void *out, const void *in, int len) +{ + char *c_out=(char*)out; + char *c_in=(char *)in; + while (len-- > 0) + { + *c_out++=*c_in++; + } +} + +void NSISCALL remove_ro_attr(TCHAR *file) +{ + int attr = GetFileAttributes(file); + if (attr != INVALID_FILE_ATTRIBUTES) + SetFileAttributes(file,attr&(~FILE_ATTRIBUTE_READONLY)); +} + +HANDLE NSISCALL myOpenFile(const TCHAR *fn, DWORD da, DWORD cd) +{ + int attr = GetFileAttributes(fn); + return CreateFile( + fn, + da, + FILE_SHARE_READ, + NULL, + cd, + attr == INVALID_FILE_ATTRIBUTES ? 0 : attr, + NULL + ); +} + +TCHAR * NSISCALL my_GetTempFileName(TCHAR *buf, const TCHAR *dir) +{ + int n = 100; + while (n--) + { + TCHAR prefix[4] = _T("nsa"); + prefix[2] += (TCHAR)(GetTickCount() % 26); + if (GetTempFileName(dir, prefix, 0, buf)) + return buf; + } + *buf = 0; + return 0; +} + +#ifdef NSIS_SUPPORT_MOVEONREBOOT +/** Modifies the wininit.ini file to rename / delete a file. + * + * @param prevName The previous / current name of the file. + * @param newName The new name to move the file to. If NULL, the current file + * will be deleted. + */ +void RenameViaWininit(const TCHAR* prevName, const TCHAR* newName) +{ + static char szRenameLine[1024]; + static TCHAR wininit[1024]; + static TCHAR tmpbuf[1024]; + + int cchRenameLine; + LPCSTR szRenameSec = "[Rename]\r\n"; // rename section marker + HANDLE hfile; + DWORD dwFileSize; + DWORD dwBytes; + DWORD dwRenameLinePos; + char *pszWinInit; // Contains the file contents of wininit.ini + + int spn; // length of the short path name in TCHARs. + + lstrcpy(tmpbuf, _T("NUL")); + + if (newName) { + // create the file if it's not already there to prevent GetShortPathName from failing + CloseHandle(myOpenFile(newName,0,CREATE_NEW)); + spn = GetShortPathName(newName,tmpbuf,1024); + if (!spn || spn > 1024) + return; + } + // wininit is used as a temporary here + spn = GetShortPathName(prevName,wininit,1024); + if (!spn || spn > 1024) + return; + cchRenameLine = wsprintfA(szRenameLine, "%s=%s\r\n", tmpbuf, wininit); + // Get the path to the wininit.ini file. + GetNSISString(wininit, g_header->str_wininit); + + hfile = myOpenFile(wininit, GENERIC_READ | GENERIC_WRITE, OPEN_ALWAYS); + + if (hfile != INVALID_HANDLE_VALUE) + { + // We are now working on the Windows wininit file + dwFileSize = GetFileSize(hfile, NULL); + pszWinInit = (char*) GlobalAlloc(GPTR, dwFileSize + cchRenameLine + 10); + + if (pszWinInit != NULL) + { + if (ReadFile(hfile, pszWinInit, dwFileSize, &dwBytes, NULL) && dwFileSize == dwBytes) + { + // Look for the rename section in the current file. + LPSTR pszRenameSecInFile = mystrstriA(pszWinInit, szRenameSec); + if (pszRenameSecInFile == NULL) + { + // No rename section. So we add it to the end of file. + lstrcpyA(pszWinInit+dwFileSize, szRenameSec); + dwFileSize += 10; + dwRenameLinePos = dwFileSize; + } + else + { + // There is a rename section, but is there another section after it? + char *pszFirstRenameLine = pszRenameSecInFile+10; + char *pszNextSec = mystrstriA(pszFirstRenameLine,"\n["); + if (pszNextSec) + { + char *p = ++pszNextSec; + while (p < pszWinInit + dwFileSize) { + p[cchRenameLine] = *p; + p++; + } + + dwRenameLinePos = pszNextSec - pszWinInit; + } + // rename section is last, stick item at end of file + else dwRenameLinePos = dwFileSize; + } + + mini_memcpy(&pszWinInit[dwRenameLinePos], szRenameLine, cchRenameLine); + dwFileSize += cchRenameLine; + + SetFilePointer(hfile, 0, NULL, FILE_BEGIN); + WriteFile(hfile, pszWinInit, dwFileSize, &dwBytes, NULL); + + GlobalFree(pszWinInit); + } + } + + CloseHandle(hfile); + } +} + +/** + * MoveFileOnReboot tries to move a file by the name of pszExisting to the + * name pszNew. + * + * @param pszExisting The old name of the file. + * @param pszNew The new name of the file. + */ +void NSISCALL MoveFileOnReboot(LPCTSTR pszExisting, LPCTSTR pszNew) +{ + BOOL fOk = 0; + typedef BOOL (WINAPI *mfea_t)(LPCTSTR lpExistingFileName,LPCTSTR lpNewFileName,DWORD dwFlags); + mfea_t mfea; + mfea=(mfea_t) myGetProcAddress(MGA_MoveFileEx); + if (mfea) + { + fOk=mfea(pszExisting, pszNew, MOVEFILE_DELAY_UNTIL_REBOOT|MOVEFILE_REPLACE_EXISTING); + } + + if (!fOk) + { + RenameViaWininit(pszExisting, pszNew); + } + +#ifdef NSIS_SUPPORT_REBOOT + g_exec_flags.exec_reboot++; +#endif +} +#endif + +// The value of registry->sub->name is stored in out. If failure, then out becomes +// an empty string "". +void NSISCALL myRegGetStr(HKEY root, const TCHAR *sub, const TCHAR *name, TCHAR *out, int x64) +{ + HKEY hKey; + *out=0; + if (RegOpenKeyEx(root,sub,0,KEY_READ|(x64?KEY_WOW64_64KEY:0),&hKey) == ERROR_SUCCESS) + { + DWORD l = NSIS_MAX_STRLEN*sizeof(TCHAR); + DWORD t; + // Note that RegQueryValueEx returns Unicode strings if _UNICODE is defined for the + // REG_SZ type. + if (RegQueryValueEx(hKey,name,NULL,&t,(LPBYTE)out,&l ) != ERROR_SUCCESS || (t != REG_SZ && t != REG_EXPAND_SZ)) *out=0; + out[NSIS_MAX_STRLEN-1]=0; + RegCloseKey(hKey); + } +} + +void NSISCALL myitoa(TCHAR *s, int d) +{ + static const TCHAR c[] = _T("%d"); + wsprintf(s,c,d); +} + +int NSISCALL myatoi(TCHAR *s) +{ + unsigned int v=0; + int sign=1; // sign of positive + TCHAR m=10; // base of 10 + TCHAR t=_T('9'); // cap top of numbers at 9 + + if (*s == _T('-')) + { + s++; //skip over - + sign=-1; // sign flip + } + + if (*s == _T('0')) + { + s++; // skip over 0 + if (s[0] >= _T('0') && s[0] <= _T('7')) + { + m=8; // base of 8 + t=_T('7'); // cap top at 7 + } + if ((s[0] & ~0x20) == _T('X')) + { + m=16; // base of 16 + s++; // advance over 'x' + } + } + + for (;;) + { + int c=*s++; + if (c >= _T('0') && c <= t) c-=_T('0'); + // clever little trick to do both upper and lowercase A-F. + else if (m==16 && (c & ~0x20) >= _T('A') && (c & ~0x20) <= _T('F')) c = (c & 7) + 9; + else break; + v*=m; + v+=c; + } + return ((int)v)*sign; +} + +// Straight copies of selected shell functions. Calling local functions +// requires less code than DLL functions. For the savings to outweigh the cost +// of a new function there should be about a couple of dozen or so calls. +TCHAR * NSISCALL mystrcpy(TCHAR *out, const TCHAR *in) +{ + return lstrcpyn(out, in, NSIS_MAX_STRLEN); +} + +int NSISCALL mystrlen(const TCHAR *in) +{ + return lstrlen(in); +} + +TCHAR * NSISCALL mystrcat(TCHAR *out, const TCHAR *concat) +{ + return lstrcat(out, concat); +} + +TCHAR ps_tmpbuf[NSIS_MAX_STRLEN*2]; + +const TCHAR SYSREGKEY[] = _T("Software\\Microsoft\\Windows\\CurrentVersion"); +const TCHAR QUICKLAUNCH[] = _T("\\Microsoft\\Internet Explorer\\Quick Launch"); + +typedef HRESULT (__stdcall * PFNSHGETFOLDERPATH)(HWND, int, HANDLE, DWORD, LPTSTR); +extern void *g_SHGetFolderPath; + +// Based on Dave Laundon's simplified process_string +// The string actually has a lot of different data encoded into it. This +// function extracts the special data out and puts it into outbuf. +TCHAR * NSISCALL GetNSISString(TCHAR *outbuf, int strtab) +{ + // This looks at the g_block (copied from header->blocks) and + // indexes into the language + TCHAR *in = (TCHAR*)GetNSISStringNP(GetNSISTab(strtab)); + TCHAR *out = ps_tmpbuf; + + // Still working within ps_tmpbuf, so set out to the + // current position that is passed in. + if (outbuf >= ps_tmpbuf && + (size_t) (outbuf - ps_tmpbuf) < COUNTOF(ps_tmpbuf)) + { + out = outbuf; + outbuf = 0; + } + + while (*in && out - ps_tmpbuf < NSIS_MAX_STRLEN) + { + _TUCHAR nVarIdx = (_TUCHAR)*in++; + int nData; + int fldrs[4]; + if (nVarIdx > NS_CODES_START) + { + // the next 2 BYTEs in the string might be coding either a value 0..MAX_CODED (nData), or 2 CSIDL of Special folders (for NS_SHELL_CODE) + nData = DECODE_SHORT(in); + fldrs[0] = in[0] | CSIDL_FLAG_CREATE; // current user + fldrs[1] = in[0]; + fldrs[2] = in[1] | CSIDL_FLAG_CREATE; // all users + fldrs[3] = in[1]; + //TODO: are fldrs[1] and fldrs[3] really useful? why not force folder creation directly? + in += sizeof(SHORT)/sizeof(TCHAR); + + if (nVarIdx == NS_SHELL_CODE) + { + LPITEMIDLIST idl; + + int x = 2; + DWORD ver = GetVersion(); + + /* + + SHGetFolderPath as provided by shfolder.dll is used to get special folders + unless the installer is running on Windows 95/98. For 95/98 shfolder.dll is + only used for the Application Data and Documents folder (if the DLL exists). + Otherwise, the old SHGetSpecialFolderLocation API is called. + + The reason for not using shfolder.dll for all folders on 95/98 is that some + unsupported folders (such as the Start Menu folder for all users) are + simulated instead of returning an error so we can fall back on the current + user folder. + + SHGetFolderPath in shell32.dll could be called directly for Windows versions + later than 95/98 but there is no need to do so, because shfolder.dll is still + provided and calls shell32.dll. + + */ + + BOOL use_shfolder = + // Use shfolder if not on 95/98 + !((ver & 0x80000000) && (LOWORD(ver) != 0x5A04)) || + + // Unless the Application Data or Documents folder is requested + ( + (fldrs[3] == CSIDL_COMMON_APPDATA) || + (fldrs[3] == CSIDL_COMMON_DOCUMENTS) + ); + + /* Carry on... shfolder stuff is over. */ + + if (g_exec_flags.all_user_var) + { + x = 4; + } + + if (fldrs[1] & 0x80) + { + myRegGetStr(HKEY_LOCAL_MACHINE, SYSREGKEY, GetNSISStringNP(fldrs[1] & 0x3F), out, fldrs[1] & 0x40); + if (!*out) + GetNSISString(out, fldrs[3]); + x = 0; + } + else if (fldrs[1] == CSIDL_SYSTEM) + { + GetSystemDirectory(out, NSIS_MAX_STRLEN); + x = 0; + } + else if (fldrs[1] == CSIDL_WINDOWS) + { + GetWindowsDirectory(out, NSIS_MAX_STRLEN); + x = 0; + } + + while (x--) + { + if (g_SHGetFolderPath && use_shfolder) + { + PFNSHGETFOLDERPATH SHGetFolderPathFunc = (PFNSHGETFOLDERPATH) g_SHGetFolderPath; + if (!SHGetFolderPathFunc(g_hwnd, fldrs[x], NULL, SHGFP_TYPE_CURRENT, out)) + { + break; + } + } + + if (!SHGetSpecialFolderLocation(g_hwnd, fldrs[x], &idl)) + { + BOOL res = SHGetPathFromIDList(idl, out); + CoTaskMemFree(idl); + if (res) break; + } + + *out=0; + } + + if (*out) + { + // all users' version is CSIDL_APPDATA only for $QUICKLAUNCH + // for normal $APPDATA, it'd be CSIDL_APPDATA_COMMON + if (fldrs[3] == CSIDL_APPDATA) + { + mystrcat(out, QUICKLAUNCH); // append suffix path for $QUICKLAUNCH + } + } + validate_filename(out); + } + else if (nVarIdx == NS_VAR_CODE) + { + if (nData == 29) // $HWNDPARENT + myitoa(out, (unsigned int) g_hwnd); + else + mystrcpy(out, g_usrvars[nData]); + // validate the directory name + if ((unsigned int)(nData - 21) < 7) { + // validate paths for $INSTDIR, $OUTDIR, $EXEDIR, $LANGUAGE, $TEMP, $PLUGINSDIR and $EXEPATH + // $LANGUAGE is just a number anyway... + validate_filename(out); + } + } // == VAR_CODES_START + else if (nVarIdx == NS_LANG_CODE) + { + GetNSISString(out, -nData-1); + } + out += mystrlen(out); + } + else if (nVarIdx == NS_SKIP_CODE) + { + *out++ = *in++; + } + else // Normal char + { + *out++ = nVarIdx; + } + } // while + *out = 0; + if (outbuf) + return mystrcpy(outbuf, ps_tmpbuf); + return ps_tmpbuf; +} + +void NSISCALL validate_filename(TCHAR *in) { + TCHAR *nono = _T("*?|<>/\":"); + TCHAR *out; + TCHAR *out_save; + + // ignoring spaces is wrong, _T(" C:\blah") is invalid + //while (*in == _T(' ')) in = CharNext(in); + + if (in[0] == _T('\\') && in[1] == _T('\\') && in[2] == _T('?') && in[3] == _T('\\')) + { + // at least four bytes + in += 4; + } + if (*in) + { + // at least two bytes + if (validpathspec(in)) in += 2; + } + out = out_save = in; + while (*in) + { + if ((_TUCHAR)*in > 31 && !*findchar(nono, *in)) + { + mini_memcpy(out, in, CharNext(in) - in); + out = CharNext(out); + } + in = CharNext(in); + } + *out = 0; + do + { + out = CharPrev(out_save, out); + if (*out == _T(' ') || *out == _T('\\')) + *out = 0; + else + break; + } while (out_save < out); +} + +#ifdef NSIS_CONFIG_LOG +int log_dolog; +TCHAR log_text[2048]; // 1024 for each wsprintf + +#if !defined(NSIS_CONFIG_LOG_ODS) && !defined(NSIS_CONFIG_LOG_STDOUT) +void NSISCALL log_write(int close) +{ + static HANDLE fp=INVALID_HANDLE_VALUE; + if (close) + { + if (fp!=INVALID_HANDLE_VALUE) + { + CloseHandle(fp); + } + fp=INVALID_HANDLE_VALUE; + return; + } + if (log_dolog) + { + if (g_log_file[0] && fp==INVALID_HANDLE_VALUE) + { + fp = myOpenFile(g_log_file,GENERIC_WRITE,OPEN_ALWAYS); + if (fp!=INVALID_HANDLE_VALUE) + SetFilePointer(fp,0,NULL,FILE_END); + } + if (fp!=INVALID_HANDLE_VALUE) + { + DWORD d; + mystrcat(log_text,_T("\r\n")); + WriteFile(fp,log_text,mystrlen(log_text)*sizeof(TCHAR),&d,NULL); + } + } +} +#endif//!NSIS_CONFIG_LOG_ODS && !NSIS_CONFIG_LOG_STDOUT + +const TCHAR * _RegKeyHandleToName(HKEY hKey) +{ + if (hKey == HKEY_CLASSES_ROOT) + return _T("HKEY_CLASSES_ROOT"); + else if (hKey == HKEY_CURRENT_USER) + return _T("HKEY_CURRENT_USER"); + else if (hKey == HKEY_LOCAL_MACHINE) + return _T("HKEY_LOCAL_MACHINE"); + else if (hKey == HKEY_USERS) + return _T("HKEY_USERS"); + else if (hKey == HKEY_PERFORMANCE_DATA) + return _T("HKEY_PERFORMANCE_DATA"); + else if (hKey == HKEY_CURRENT_CONFIG) + return _T("HKEY_CURRENT_CONFIG"); + else if (hKey == HKEY_DYN_DATA) + return _T("HKEY_DYN_DATA"); + else + return _T("invalid registry key"); +} + +void _LogData2Hex(TCHAR *buf, size_t buflen, BYTE *data, size_t datalen) +{ + TCHAR *p = buf; + + size_t i; + + int dots = 0; + size_t bufbytes = buflen / 3; // 2 hex digits, one space/null + + if (datalen > bufbytes) + { + bufbytes--; + dots = 1; + } + else + bufbytes = datalen; + + for (i = 0; i < bufbytes; i++) + { + wsprintf(p, _T("%02x%c"), data[i], (i == bufbytes - 1) ? _T('\0') : _T(' ')); + p += 3; + } + + if (dots) + mystrcat(buf, _T("...")); +} + +#ifdef NSIS_CONFIG_LOG_TIMESTAMP +void log_timestamp(TCHAR *buf) +{ + SYSTEMTIME st; + GetLocalTime(&st); + wsprintf(buf,_T("[%04hu/%02hu/%02hu %02hu:%02hu:%02hu] "), st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond); +} +#else +# define log_timestamp(x) +#endif//NSIS_CONFIG_LOG_TIMESTAMP + +void log_printf(TCHAR *format, ...) +{ + va_list val; + va_start(val,format); + + log_text[0] = _T('\0'); + log_timestamp(log_text); + wvsprintf(log_text+mystrlen(log_text),format,val); + + va_end(val); +#ifdef NSIS_CONFIG_LOG_ODS + if (log_dolog) + OutputDebugString(log_text); +#endif +#ifdef NSIS_CONFIG_LOG_STDOUT + if (log_dolog && GetStdHandle(STD_OUTPUT_HANDLE) != INVALID_HANDLE_VALUE) + { + DWORD dwBytes; + WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), log_text, lstrlen(log_text), &dwBytes, NULL); + WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), _T("\n"), 1, &dwBytes, NULL); + } +#endif +#if !defined(NSIS_CONFIG_LOG_ODS) && !defined(NSIS_CONFIG_LOG_STDOUT) + log_write(0); +#endif +} +#endif//NSIS_CONFIG_LOG + +// Jim Park: This function is non-reentrant because of the static. +WIN32_FIND_DATA * NSISCALL file_exists(TCHAR *buf) +{ + HANDLE h; + static WIN32_FIND_DATA fd; + h = FindFirstFile(buf,&fd); + if (h != INVALID_HANDLE_VALUE) + { + FindClose(h); + return &fd; + } + return NULL; +} + +// Jim Park: Keep these as chars since there's only ANSI version of +// GetProcAddress. +struct MGA_FUNC +{ + const char *dll; + const char *func; +}; + +#ifdef _UNICODE +struct MGA_FUNC MGA_FUNCS[] = { + {"KERNEL32", "GetDiskFreeSpaceExW"}, + {"KERNEL32", "MoveFileExW"}, + {"ADVAPI32", "RegDeleteKeyExW"}, + {"ADVAPI32", "OpenProcessToken"}, + {"ADVAPI32", "LookupPrivilegeValueW"}, + {"ADVAPI32", "AdjustTokenPrivileges"}, + {"KERNEL32", "GetUserDefaultUILanguage"}, + {"SHLWAPI", "SHAutoComplete"}, + {"SHFOLDER", "SHGetFolderPathW"} +}; +#else +struct MGA_FUNC MGA_FUNCS[] = { + {"KERNEL32", "GetDiskFreeSpaceExA"}, + {"KERNEL32", "MoveFileExA"}, + {"ADVAPI32", "RegDeleteKeyExA"}, + {"ADVAPI32", "OpenProcessToken"}, + {"ADVAPI32", "LookupPrivilegeValueA"}, + {"ADVAPI32", "AdjustTokenPrivileges"}, + {"KERNEL32", "GetUserDefaultUILanguage"}, + {"SHLWAPI", "SHAutoComplete"}, + {"SHFOLDER", "SHGetFolderPathA"} +}; +#endif + +/** + * Given a function enum, it will load the appropriate DLL and get the + * process address of the function and return the pointer. It's up to + * the caller to know how to call that function, however. + * + * @param func Enum value that indexes the MGA_FUNCS array. + * @return Pointer to the function identified by the enum value. + */ +void * NSISCALL myGetProcAddress(const enum myGetProcAddressFunctions func) +{ + const char *dll = MGA_FUNCS[func].dll; + HMODULE hModule = GetModuleHandleA(dll); + if (!hModule) + hModule = LoadLibraryA(dll); + if (!hModule) + return NULL; + + return GetProcAddress(hModule, MGA_FUNCS[func].func); +} + +void NSISCALL MessageLoop(UINT uCheckedMsg) +{ + MSG msg; + while (PeekMessage(&msg, NULL, uCheckedMsg, uCheckedMsg, PM_REMOVE)) + DispatchMessage(&msg); +} + +/** + * This function is useful for Unicode support. Since the Windows + * GetProcAddress function always takes a char*, this function wraps + * the windows call and does the appropriate translation when + * appropriate. + * + * @param dllHandle Handle to the DLL loaded by LoadLibraryEx. + * @param funcName The name of the function to get the address of. + * @return The pointer to the function. Null if failure. + */ +void * NSISCALL NSISGetProcAddress(HANDLE dllHandle, TCHAR* funcName) +{ +#ifdef _UNICODE + char ansiName[NSIS_MAX_STRLEN]; + if (WideCharToMultiByte(CP_ACP, 0, funcName, -1, ansiName, NSIS_MAX_STRLEN, NULL, NULL) != 0) + return GetProcAddress(dllHandle, ansiName); + return NULL; +#else + return GetProcAddress(dllHandle, funcName); +#endif +} diff --git a/Source/lang.cpp b/Source/lang.cpp index 6ee23de5..3bea8065 100644 --- a/Source/lang.cpp +++ b/Source/lang.cpp @@ -148,21 +148,19 @@ NLFString NLFStrings[NLF_STRINGS] = { // LangStringList // ============== -LangStringList::LangStringList() { - m_count = 0; -} int LangStringList::add(const TCHAR *name, int *sn/*=0*/) { int pos = SortedStringListND::add(name); if (pos == -1) return -1; - ((struct langstring*)m_gr.get())[pos].sn = m_count; + langstring* lstrPtr = (langstring*)(m_gr.get()) + pos; + lstrPtr->sn = m_count; if (sn) *sn = m_count; m_count++; - ((struct langstring*)m_gr.get())[pos].index = -1; - ((struct langstring*)m_gr.get())[pos].uindex = -1; - ((struct langstring*)m_gr.get())[pos].process = 1; + lstrPtr->index = -1; + lstrPtr->uindex = -1; + lstrPtr->process = 1; return pos; } @@ -174,10 +172,11 @@ int LangStringList::get(const TCHAR *name, int *sn/*=0*/, int *index/*=0*/, int if (sn) *sn = -1; int v=find(name); if (v==-1) return -1; - if (index) *index = ((struct langstring*)m_gr.get())[v].index; - if (uindex) *uindex = ((struct langstring*)m_gr.get())[v].uindex; - if (sn) *sn = ((struct langstring*)m_gr.get())[v].sn; - if (process) *process = ((struct langstring*)m_gr.get())[v].process; + langstring* lstrPtr = (langstring*)(m_gr.get()) + v; + if (index) *index = lstrPtr->index; + if (uindex) *uindex = lstrPtr->uindex; + if (sn) *sn = lstrPtr->sn; + if (process) *process = lstrPtr->process; return v; } @@ -186,14 +185,11 @@ void LangStringList::set(int pos, int index/*=-1*/, int uindex/*=-1*/, int proce if ((unsigned int)pos > (m_gr.getlen() / sizeof(struct langstring))) return; - struct langstring *data=(struct langstring *)m_gr.get(); + struct langstring *data=((struct langstring *) m_gr.get()) + pos; - if (index >= 0) - data[pos].index = index; - if (uindex >= 0) - data[pos].uindex = uindex; - if (process >= 0) - data[pos].process = process; + if (index >= 0) data->index = index; + if (uindex >= 0) data->uindex = uindex; + if (process >= 0) data->process = process; } void LangStringList::set(const TCHAR *name, int index, int uindex/*=-1*/, int process/*=-1*/) @@ -213,7 +209,7 @@ const TCHAR* LangStringList::pos2name(int pos) const TCHAR* LangStringList::offset2name(int name) { - if ((unsigned int)name > (unsigned int)m_strings.getlen()) + if ((unsigned int)name > m_strings.getlen()/sizeof(TCHAR)) return 0; return (const TCHAR*) m_strings.get() + name; diff --git a/Source/lang.h b/Source/lang.h index ec320cb3..8c680c43 100644 --- a/Source/lang.h +++ b/Source/lang.h @@ -40,7 +40,7 @@ class LangStringList : public SortedStringListND { public: /* Default constructor */ - LangStringList(); + LangStringList() : m_count(0) {} /** * Adds a langstring struct with the string name of 'name' into this diff --git a/Source/strlist.cpp b/Source/strlist.cpp index a7e58e27..81484f41 100644 --- a/Source/strlist.cpp +++ b/Source/strlist.cpp @@ -13,7 +13,7 @@ * This software is provided 'as-is', without any express or implied * warranty. * - * Doxygen comments by Jim Park -- 08/01/2007 + * Unicode support and Doxygen comments by Jim Park -- 08/01/2007 */ #include "strlist.h" @@ -29,9 +29,12 @@ int StringList::add(const TCHAR *str, int case_sensitive) int StringList::find(const TCHAR *str, int case_sensitive, int *idx/*=NULL*/) const // returns -1 if not found { const TCHAR *s=get(); - int ml=getlen(); + int ml=getcount(); int offs=0; + size_t str_slen = _tcslen(str); + size_t offs_slen; + if (idx) *idx=0; while (offs < ml) { @@ -42,14 +45,16 @@ int StringList::find(const TCHAR *str, int case_sensitive, int *idx/*=NULL*/) co return offs; } + offs_slen = _tcslen(s+offs); + // Check if just the end of the string matches str. if (case_sensitive==2 && - _tcslen(str) < _tcslen(s+offs) && // check for end of string - !_tcscmp(s+offs+_tcslen(s+offs)-_tcslen(str),str)) + str_slen < offs_slen && // check for end of string + !_tcscmp(s + offs + offs_slen - str_slen,str)) { - return offs+_tcslen(s+offs)-_tcslen(str); + return offs + offs_slen - str_slen; } - offs+=_tcslen(s+offs)+1; + offs += offs_slen + 1; if (idx) (*idx)++; } @@ -62,12 +67,12 @@ void StringList::delbypos(int pos) TCHAR *s=(TCHAR*) m_gr.get(); int len=_tcslen(s+pos)+1; - if (pos+len < m_gr.getlen()) + if (pos+len < getcount()) { // Move everything after the string position to the current position. - memcpy(s+pos,s+pos+len,m_gr.getlen()-(pos+len)); + memcpy(s+pos,s+pos+len, (getcount()-pos+len)*sizeof(TCHAR)); } - m_gr.resize(m_gr.getlen()-len); + m_gr.resize(m_gr.getlen()-len*sizeof(TCHAR)); } // idx corresponds to the nth string in the list. @@ -75,8 +80,8 @@ int StringList::idx2pos(int idx) const { TCHAR *s=(TCHAR*) m_gr.get(); int offs=0; - int cnt=0; - if (idx>=0) while (offs < m_gr.getlen()) + size_t cnt=0; + if (idx>=0) while (offs < getcount()) { if (cnt++ == idx) return offs; offs+=_tcslen(s+offs)+1; @@ -87,7 +92,7 @@ int StringList::idx2pos(int idx) const int StringList::getnum() const { TCHAR *s=(TCHAR*) m_gr.get(); - int ml=m_gr.getlen(); + int ml=getcount(); int offs=0; int idx=0; while (offs < ml) @@ -103,9 +108,9 @@ const TCHAR *StringList::get() const return (const TCHAR*) m_gr.get(); } -int StringList::getlen() const +int StringList::getcount() const { - return m_gr.getlen(); + return m_gr.getlen() / sizeof(TCHAR); } // ========== @@ -213,9 +218,9 @@ TCHAR *FastStringList::get() const return (TCHAR*)m_strings.get(); } -int FastStringList::getlen() const +int FastStringList::getcount() const { - return m_strings.getlen(); + return m_strings.getlen()/sizeof(TCHAR); } int FastStringList::getnum() const diff --git a/Source/strlist.h b/Source/strlist.h index 7e2526ab..f8d46ef1 100644 --- a/Source/strlist.h +++ b/Source/strlist.h @@ -107,10 +107,10 @@ public: const TCHAR *get() const; /** - * Get the buffer size in bytes. - * @return The buffer size in bytes. + * Get the buffer size (number of TCHARs). + * @return The buffer size (number of TCHARs). */ - int getlen() const; + int getcount() const; private: GrowBuf m_gr; @@ -538,11 +538,11 @@ class FastStringList : public SortedStringListND TCHAR *get() const; /** - * The size of the collection of m_strings as bytes. + * The size of the collection of m_strings as a count of TCHARs. * - * @return The size of m_strings in bytes. + * @return the size of m_strings as count of TCHARs. */ - int getlen() const; + int getcount() const; /** * The number of strings stored in the sorted array. diff --git a/Source/uservars.h b/Source/uservars.h index 9d4e130b..18ecceac 100644 --- a/Source/uservars.h +++ b/Source/uservars.h @@ -32,12 +32,10 @@ class UserVarsStringList : public SortedStringListND { public: /* Default constructor */ - UserVarsStringList() - { - m_index = 0; - } + UserVarsStringList() : m_index(0) {} + /* Destructor */ - ~UserVarsStringList() { } + virtual ~UserVarsStringList() {} /** * Adds a name to the UserVarsStringList. Sets reference count to @@ -52,9 +50,10 @@ class UserVarsStringList : public SortedStringListND int pos=SortedStringListND::add(name); if (pos == -1) return -1; - ((struct uservarstring*)m_gr.get())[pos].index = m_index; - ((struct uservarstring*)m_gr.get())[pos].pos = pos; - ((struct uservarstring*)m_gr.get())[pos].reference = ref_count; + uservarstring* ustr = ((uservarstring*) m_gr.get()) + pos; + ustr->index = m_index; + ustr->pos = pos; + ustr->reference = ref_count; int temp = m_index; m_index++; @@ -110,8 +109,7 @@ class UserVarsStringList : public SortedStringListND int inc_reference(int idx) { int pos=get_internal_idx(idx); - ((struct uservarstring*)m_gr.get())[pos].reference++; - return (((struct uservarstring*)m_gr.get())[pos].reference)-1; + return ((struct uservarstring*) m_gr.get())[pos].reference++; } /**