diff --git a/platforms/win32/vm/sqWin32.h b/platforms/win32/vm/sqWin32.h index e48fcfd04d..2a657699f1 100644 --- a/platforms/win32/vm/sqWin32.h +++ b/platforms/win32/vm/sqWin32.h @@ -259,21 +259,46 @@ int reverse_image_words(unsigned int *dst, unsigned int *src,int depth, int widt /********************************************************/ /* Declarations we may need by other modules */ /********************************************************/ -extern char imageName[]; /* full path and name to image */ -extern TCHAR imagePath[]; /* full path to image */ -extern TCHAR vmPath[]; /* full path to interpreter's directory */ -extern TCHAR vmName[]; /* name of the interpreter's executable */ -extern char windowTitle[]; /* window title string */ -extern char vmBuildString[]; /* the vm build string */ -extern TCHAR windowClassName[]; /* class name for the window */ + +/* Note: a character can require up to 4 bytes in UTF8 encoding + But the expansion from UTF16 -> UTF8 is never more than 3 bytes for 1 short + U+ 0000-U+ 007F - 1byte in utf8, 1 short in utf16. + U+ 0080-U+ 07FF - 2byte in utf8, 1 short in utf16. + U+ 0800-U+ FFFF - 3byte in utf8, 1 short in utf16. + U+10000-U+10FFFF - 4byte in utf8, 2 short in utf16. +*/ +#define MAX_PATH_UTF8 (MAX_PATH*3) + +extern char imageName []; /* full path and name to image - UTF8 */ +extern WCHAR imageNameW[]; /* full path and name to image - UTF16 */ +extern char imagePathA[]; /* full path to image - UTF8 */ +extern WCHAR imagePathW[]; /* full path to image - UTF16 */ +extern char vmPathA[]; /* full path to interpreter's directory - UTF8 */ +extern WCHAR vmPathW[]; /* full path to interpreter's directory - UTF16 */ +extern char vmNameA[]; /* name of the interpreter's executable - UTF8 */ +extern WCHAR vmNameW[]; /* name of the interpreter's executable - UTF16 */ +extern char windowTitle[]; /* window title string - UTF8 */ +extern char vmBuildString[]; /* the vm build string */ +extern TCHAR windowClassName[]; /* class name for the window */ + +#ifdef UNICODE +#define imageNameT imageNameW /* define the generic TCHAR* version */ +#define imagePath imagePathW +#define vmName vmNameW +#define vmPath vmPathW +#else +#define imageNameT imageNameA +#define imagePath imagePathA +#define vmName vmNameA +#define vmPath vmPathA +#endif extern UINT SQ_LAUNCH_DROP; extern const TCHAR U_ON[]; extern const TCHAR U_OFF[]; extern const TCHAR U_GLOBAL[]; -extern const TCHAR U_SLASH[]; -extern const TCHAR U_BACKSLASH[]; +extern const WCHAR W_BACKSLASH[]; #ifndef NO_PREFERENCES extern HMENU vmPrefsMenu; /* preferences menu */ @@ -380,7 +405,7 @@ void vprintLastError(TCHAR *fmt, ...); /******************************************************/ /* Misc functions */ /******************************************************/ -DWORD SqueakImageLength(TCHAR *fileName); +DWORD SqueakImageLength(WCHAR *fileName); int isLocalFileName(TCHAR *fileName); #ifndef NO_PLUGIN_SUPPORT diff --git a/platforms/win32/vm/sqWin32Main.c b/platforms/win32/vm/sqWin32Main.c index 7f292669eb..31266e1211 100644 --- a/platforms/win32/vm/sqWin32Main.c +++ b/platforms/win32/vm/sqWin32Main.c @@ -130,7 +130,7 @@ TCHAR consoleBuffer[4096]; char stderrName[MAX_PATH+1]; char stdoutName[MAX_PATH+1]; -static char vmLogDirA[MAX_PATH]; +static char vmLogDirA[MAX_PATH_UTF8]; static WCHAR vmLogDirW[MAX_PATH]; TCHAR *logName = TEXT(""); /* full path and name to log file */ @@ -462,7 +462,7 @@ char *ioGetLogDirectory(void) { } sqInt ioSetLogDirectoryOfSize(void* lblIndex, sqInt sz) { - if (sz >= MAX_PATH) return 0; + if (sz >= MAX_PATH_UTF8) return 0; strncpy(vmLogDirA, lblIndex, sz); vmLogDirA[sz] = 0; MultiByteToWideChar(CP_UTF8, 0, vmLogDirA, -1, vmLogDirW, MAX_PATH); @@ -1405,7 +1405,7 @@ sqImageFile findEmbeddedImage(void) { int start; int length; - f = sqImageFileOpen(vmName, "rb"); + f = sqImageFileOpen(vmNameA, "rb"); if(!f) { MessageBox(0,"Error opening VM",VM_NAME,MB_OK); return 0; @@ -1441,6 +1441,7 @@ sqImageFile findEmbeddedImage(void) { /* Gotcha! */ sqImageFileSeek(f, sqImageFilePosition(f) - 4); strcpy(imageName, name); + MultiByteToWideChar(CP_UTF8,0,imageName,-1,imageNameW,MAX_PATH,NULL,NULL); imageSize = endMarker - sqImageFilePosition(f); return f; } @@ -1577,7 +1578,7 @@ sqMain(int argc, char *argv[]) } SetupFilesAndPath(); - ioSetLogDirectoryOfSize(vmPath, strlen(vmPath)); + ioSetLogDirectoryOfSize(vmPathA, strlen(vmPathA)); /* release resources on exit */ atexit(Cleanup); @@ -1620,7 +1621,7 @@ sqMain(int argc, char *argv[]) if(!imageFile) { - imageSize = SqueakImageLength(toUnicode(imageName)); + imageSize = SqueakImageLength(imageNameW); if(imageSize == 0) printUsage(2); } @@ -1650,13 +1651,13 @@ sqMain(int argc, char *argv[]) #if !NewspeakVM /* set the CWD to the image location */ - if(*imageName) { - char path[MAX_PATH+1], *ptr; - strcpy(path,imageName); - ptr = strrchr(path, '\\'); + if(*imageNameW) { + WCHAR path[MAX_PATH+1], *ptr; + wcsncpy(path,imageNameW,MAX_PATH); + ptr = wcsrchr(path, '\\'); if(ptr) { - *ptr = 0; - SetCurrentDirectory(path); + *ptr = 0; + SetCurrentDirectoryW(path); } } #endif /* !NewspeakVM */ @@ -1723,9 +1724,8 @@ WinMain(HINSTANCE hInst, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) /* fetch us the name of the executable */ { - WCHAR vmNameW[MAX_PATH]; GetModuleFileNameW(hInst, vmNameW, MAX_PATH); - WideCharToMultiByte(CP_UTF8, 0, vmNameW, -1, vmName, MAX_PATH, NULL, NULL); + WideCharToMultiByte(CP_UTF8, 0, vmNameW, -1, vmNameA, MAX_PATH_UTF8, NULL, NULL); } /* parse the command line into the unix-style argc, argv, converting to * UTF-8 on the way. */ @@ -2086,7 +2086,7 @@ SubsystemType() IMAGE_OPTIONAL_HEADER image_optional_header; /* Open the reference file. */ - hImage = CreateFile(vmName, + hImage = CreateFileW(vmNameW, GENERIC_READ, FILE_SHARE_READ, NULL, @@ -2150,7 +2150,8 @@ parseGenericArgs(int argc, char *argv[]) if (*imageName == 0) { /* only try to use image name if none is provided */ if (*argv[0] && IsImage(argv[0])) { - strcpy(imageName, argv[0]); + strncpy(imageName, argv[0],MAX_PATH_UTF8); + MultiByteToWideChar(CP_UTF8, 0, imageName, -1, imageNameW, MAX_PATH); /* if provided, the image is a vm argument. */ vmOptions[numOptionsVM++] = argv[0]; } diff --git a/platforms/win32/vm/sqWin32Prefs.c b/platforms/win32/vm/sqWin32Prefs.c index b6339803a4..dd2ceb917c 100644 --- a/platforms/win32/vm/sqWin32Prefs.c +++ b/platforms/win32/vm/sqWin32Prefs.c @@ -194,15 +194,17 @@ void LoadPreferences() /* get image file name from ini file */ size = GetPrivateProfileString(U_GLOBAL, TEXT("ImageFile"), - TEXT(""), imageName, MAX_PATH, squeakIniName); + TEXT(""), imageNameT, MAX_PATH, squeakIniName); if(size > 0) { if( !(imageName[0] == '\\' && imageName[1] == '\\') && !(imageName[1] == ':' && imageName[2] == '\\')) { /* make the path relative to VM directory */ - lstrcpy(imageName, vmName); - (lstrrchr(imageName,U_BACKSLASH[0]))[1] = 0; - size = lstrlen(imageName); + strcpy(imageName , vmNameA); + wcscpy(imageNameW, vmNameW); + (strrchr(imageName ,'\\' ))[1] = 0; + (wcsrchr(imageNameW, W_BACKSLASH[0]))[1] = 0; + size = lstrlen(imageNameT); size = GetPrivateProfileString(U_GLOBAL, TEXT("ImageFile"), - TEXT(""), imageName + size, MAX_PATH - size, squeakIniName); + TEXT(""), imageNameT + size, MAX_PATH - size, squeakIniName); } } diff --git a/platforms/win32/vm/sqWin32Service.c b/platforms/win32/vm/sqWin32Service.c index 95470d8ae5..5ba48464bc 100644 --- a/platforms/win32/vm/sqWin32Service.c +++ b/platforms/win32/vm/sqWin32Service.c @@ -413,12 +413,12 @@ void sqServiceInstall(void) return; } /* Add the image name to the subkey. */ - ok = RegSetValueEx(hk, /* subkey handle */ - TEXT("Image"), /* value name */ - 0, /* must be zero */ - REG_EXPAND_SZ, /* value type */ - (LPBYTE) imageName, /* address of value data */ - strlen(imageName) + 1); /* length of value data */ + ok = RegSetValueExW(hk, /* subkey handle */ + L"Image", /* value name */ + 0, /* must be zero */ + REG_EXPAND_SZ, /* value type */ + (LPBYTE) imageNameW, /* address of value data */ + (wcslen(imageNameW)+1)*sizeof(WCHAR)); /* length of value data */ if(ok != ERROR_SUCCESS) { printLastError(TEXT("RegSetValueEX failed")); @@ -517,14 +517,15 @@ DWORD WINAPI sqThreadMain(DWORD ignored) TerminateThread(GetCurrentThread(), 0); } /* Read the image name from the subkey. */ - dwSize = MAX_PATH; - ok = RegQueryValueEx(hk,TEXT("Image"),NULL, &dwType, (LPBYTE) imageName, &dwSize); + dwSize = MAX_PATH*sizeof(WCHAR); + ok = RegQueryValueExW(hk,L"Image",NULL, &dwType, (LPBYTE) imageNameW, &dwSize); if(ok != ERROR_SUCCESS || dwType != REG_EXPAND_SZ) { sqStopService(TEXT("Failed to read the image name from registry")); TerminateThread(GetCurrentThread(), 0); } - imageName[dwSize] = 0; + imageNameW[(dwSize+1)/2] = 0; + WideCharToMultiByte(CP_UTF8, 0, imageNameW, -1, imageName, MAX_PATH_UTF8, NULL, NULL); /* Read the log file name from the subkey. */ dwSize = MAX_PATH; ok = RegQueryValueEx(hk,TEXT("Log"),NULL, &dwType, (LPBYTE) &tmpString, &dwSize); diff --git a/platforms/win32/vm/sqWin32Window.c b/platforms/win32/vm/sqWin32Window.c index fc5f9084e0..8d5d46dadb 100644 --- a/platforms/win32/vm/sqWin32Window.c +++ b/platforms/win32/vm/sqWin32Window.c @@ -56,21 +56,30 @@ extern sqInt deferDisplayUpdates; /*** Variables -- image and path names ***/ -#define IMAGE_NAME_SIZE MAX_PATH +#define IMAGE_NAME_SIZE MAX_PATH_UTF8 -char imageName[MAX_PATH+1]; /* full path and name to image */ -TCHAR imagePath[MAX_PATH+1]; /* full path to image */ -TCHAR vmPath[MAX_PATH+1]; /* full path to interpreter's directory */ -TCHAR vmName[MAX_PATH+1]; /* name of the interpreter's executable */ -char windowTitle[MAX_PATH]; /* what should we display in the title? */ -TCHAR squeakIniName[MAX_PATH+1]; /* full path and name to ini file */ -TCHAR windowClassName[MAX_PATH+1]; /* Window class name */ +/* IMPLEMENTATION NOTE: +- both UTF8 and UTF16 versions are maintained in parallel +- UTF8 version is for interaction with image +- UTF16 version is for interaction with WIN32 API +whichever code modifies one version is responsible for updating the other +*/ +char imageName [MAX_PATH_UTF8 + 1]; /* full path and name to image */ +WCHAR imageNameW[MAX_PATH + 1]; /* full path and name to image */ +char imagePathA[MAX_PATH_UTF8 + 1]; /* full path to image */ +WCHAR imagePathW[MAX_PATH + 1]; /* full path to image */ +char vmPathA[MAX_PATH_UTF8 + 1]; /* full path to interpreter's directory */ +WCHAR vmPathW[MAX_PATH + 1]; /* full path to interpreter's directory */ +char vmNameA[MAX_PATH_UTF8 + 1]; /* name of the interpreter's executable UTF8 */ +WCHAR vmNameW[MAX_PATH + 1]; /* name of the interpreter's executable UTF16 */ +char windowTitle[MAX_PATH]; /* what should we display in the title? */ +TCHAR squeakIniName[MAX_PATH+1]; /* full path and name to ini file */ +TCHAR windowClassName[MAX_PATH+1]; /* Window class name */ const TCHAR U_ON[] = TEXT("1"); const TCHAR U_OFF[] = TEXT("0"); const TCHAR U_GLOBAL[] = TEXT("Global"); -const TCHAR U_SLASH[] = TEXT("/"); -const TCHAR U_BACKSLASH[] = TEXT("\\"); +const WCHAR W_BACKSLASH[] = L"\\"; /*** Variables -- Event Recording ***/ int inputSemaphoreIndex = 0;/* if non-zero the event semaphore index */ @@ -195,7 +204,7 @@ extern int sqAskSecurityYesNoQuestion(const char *question) extern const char *sqGetCurrentImagePath(void) { - return imagePath; + return imagePathA; } /****************************************************************************/ @@ -2753,7 +2762,7 @@ sqInt clipboardReadIntoAt(sqInt count, sqInt byteArrayIndex, sqInt startIndex) { sqInt vmPathSize(void) { - return lstrlen(vmPath); + return strlen(vmPathA); } sqInt vmPathGetLength(sqInt sqVMPathIndex, sqInt length) @@ -2761,12 +2770,12 @@ sqInt vmPathGetLength(sqInt sqVMPathIndex, sqInt length) char *stVMPath= (char *)sqVMPathIndex; int count, i; - count= lstrlen(vmPath); + count= strlen(vmPathA); count= (length < count) ? length : count; /* copy the file name into the Squeak string */ for (i= 0; i < count; i++) - stVMPath[i]= (char) vmPath[i]; /* will remove leading zeros from unicode */ + stVMPath[i]= vmPathA[i]; return count; } @@ -2799,7 +2808,7 @@ sqInt imageNameGetLength(sqInt sqImageNameIndex, sqInt length) sqInt imageNamePutLength(sqInt sqImageNameIndex, sqInt length) { char *sqImageName= (char *)sqImageNameIndex; - char tmpImageName[MAX_PATH+1]; + char tmpImageName[IMAGE_NAME_SIZE +1]; char *tmp; int count, i; @@ -2831,6 +2840,7 @@ sqInt imageNamePutLength(sqInt sqImageNameIndex, sqInt length) strcat(imageName,tmpImageName); } } + MultiByteToWideChar(CP_UTF8, 0, imageName, -1, imageNameW, MAX_PATH); SetWindowTitle(); return 1; } @@ -2856,7 +2866,7 @@ char * GetAttributeString(sqInt id) { could be reported this way as well. */ /* id == 0 : return the full name of the VM */ - if(id == 0) return fromUnicode(vmName); + if(id == 0) return vmNameA; /* 0 < id <= 1000 : return options of the image (e.g. given *after* the image name) */ if(id > 0 && id <= 1000) return GetImageOption(id-1); @@ -3001,34 +3011,45 @@ int isLocalFileName(TCHAR *fileName) void SetupFilesAndPath(){ char *tmp; - lstrcpy(imagePath, imageName); - tmp = lstrrchr(imagePath,'\\'); + WCHAR *wtmp; + strcpy(imagePathA, imageNameA); + wcscpy(imagePathW, imageNameW); + tmp = strrchr(imagePathA,'\\'); if(tmp) tmp[1] = 0; + wtmp = wcsrchr(imagePathW, '\\'); + if (wtmp) wtmp[1] = 0; } #else /* defined(_WIN32_WCE) */ void SetupFilesAndPath() { char *tmp; - WCHAR tmpName[MAX_PATH]; - WCHAR imageNameW[MAX_PATH]; + WCHAR *wtmp; + WCHAR tmpName[MAX_PATH+1]; /* get the full path for the image */ - MultiByteToWideChar(CP_UTF8, 0, imageName, -1, tmpName, MAX_PATH); + MultiByteToWideChar(CP_UTF8, 0, imageName , -1, tmpName, MAX_PATH); GetFullPathNameW(tmpName, MAX_PATH, imageNameW, NULL); /* and copy back to a UTF-8 string */ - WideCharToMultiByte(CP_UTF8, 0, imageNameW,-1,imageName,MAX_PATH,NULL,NULL); + WideCharToMultiByte(CP_UTF8, 0, imageNameW,-1,imageName ,MAX_PATH_UTF8,NULL,NULL); /* get the VM directory */ - lstrcpy(vmPath, vmName); - tmp = lstrrchr(vmPath,U_BACKSLASH[0]); + strcpy(vmPathA, vmNameA); + wcscpy(vmPathW, vmNameW); + tmp = strrchr(vmPathA, '\\'); + wtmp = wcsrchr(vmPathW, W_BACKSLASH[0]); if(tmp) *tmp = 0; - lstrcat(vmPath,U_BACKSLASH); - - lstrcpy(imagePath, imageName); - tmp = lstrrchr(imagePath,U_BACKSLASH[0]); + if (wtmp) *wtmp = 0; + strcat(vmPathA,"\\"); + wcscat(vmPathW, W_BACKSLASH); + + strcpy(imagePathA, imageName ); + wcscpy(imagePathW, imageNameW); + tmp = strrchr(imagePathA,'\\'); + wtmp = wcsrchr(imagePathW, W_BACKSLASH[0]); if(tmp) tmp[1] = 0; + if (wtmp) wtmp[1] = 0; } #endif /* !defined(_WIN32_WCE) */ @@ -3056,20 +3077,13 @@ DWORD SqueakImageLengthFromHandle(HANDLE hFile) { return 0; } -DWORD SqueakImageLength(TCHAR *fileName) { +DWORD SqueakImageLength(WCHAR *fileName) { DWORD dwSize; HANDLE hFile; /* open image file */ -#ifdef UNICODE hFile = CreateFileW(fileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); -#else - WCHAR wideName[MAX_PATH]; - MultiByteToWideChar(CP_UTF8, 0, fileName, -1, wideName, MAX_PATH); - hFile = CreateFileW(wideName, GENERIC_READ, FILE_SHARE_READ, - NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); -#endif if (hFile == INVALID_HANDLE_VALUE) return 0; dwSize = SqueakImageLengthFromHandle(hFile); CloseHandle(hFile); @@ -3094,8 +3108,9 @@ int findImageFile(void) { nextFound = FindNextFileW(findHandle,&findData); FindClose(findHandle); if(nextFound) return 0; /* more than one entry */ - WideCharToMultiByte(CP_UTF8, 0, findData.cFileName, -1, - imageName, MAX_PATH, NULL, NULL); + wcsncpy(imageNameW,findData.cFileName,MAX_PATH); + WideCharToMultiByte(CP_UTF8, 0, imageNameW, -1, + imageName, MAX_PATH*4, NULL, NULL); return 1; } @@ -3121,7 +3136,8 @@ int openImageFile(void) { ofn.Flags = OFN_EXPLORER | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY; ofn.lpstrDefExt = L"image"; if (!GetOpenFileNameW(&ofn)) return 0; - WideCharToMultiByte(CP_UTF8, 0, path, -1, + wcsncpy(imageNameW,path, MAX_PATH); + WideCharToMultiByte(CP_UTF8, 0, imageNameW, -1, imageName, MAX_PATH, NULL, NULL); return 1; } @@ -3317,7 +3333,7 @@ int printUsage(int level) TEXT("There are several ways to open an image file. You can:\n") TEXT(" 1. Double-click on the desired image file.\n") TEXT(" 2. Drop the image file onto the application.\n") - TEXT("Aborting...\n"), toUnicode(imageName)); + TEXT("Aborting...\n"), imageNameT); } return -1; }