Index: src/OFFile.m ================================================================== --- src/OFFile.m +++ src/OFFile.m @@ -30,10 +30,11 @@ #endif #import "OFFile.h" #import "OFLocale.h" #import "OFString.h" +#import "OFSystemInfo.h" #import "OFURL.h" #import "OFInitializationFailedException.h" #import "OFInvalidArgumentException.h" #import "OFNotOpenException.h" @@ -218,20 +219,27 @@ if ((flags = parseMode(mode.UTF8String)) == -1) @throw [OFInvalidArgumentException exception]; flags |= O_BINARY | O_CLOEXEC; -# if defined(OF_WINDOWS) - if ((handle = _wopen(path.UTF16String, flags, - _S_IREAD | _S_IWRITE)) == -1) -# elif defined(HAVE_OPEN64) - if ((handle = open64([path cStringWithEncoding: - [OFLocale encoding]], flags, 0666)) == -1) +# ifdef OF_WINDOWS + if ([OFSystemInfo isWindowsNT]) + handle = _wopen(path.UTF16String, flags, + _S_IREAD | _S_IWRITE); + else +# endif +# ifdef HAVE_OPEN64 + handle = open64( + [path cStringWithEncoding: [OFLocale encoding]], + flags, 0666); # else - if ((handle = open([path cStringWithEncoding: - [OFLocale encoding]], flags, 0666)) == -1) + handle = open( + [path cStringWithEncoding: [OFLocale encoding]], + flags, 0666); # endif + + if (handle == -1) @throw [OFOpenItemFailedException exceptionWithPath: path mode: mode errNo: errno]; #else Index: src/OFFileManager.m ================================================================== --- src/OFFileManager.m +++ src/OFFileManager.m @@ -162,16 +162,28 @@ #ifdef OF_HAVE_FILES - (OFString *)currentDirectoryPath { # if defined(OF_WINDOWS) OFString *ret; - wchar_t *buffer = _wgetcwd(NULL, 0); - @try { - ret = [OFString stringWithUTF16String: buffer]; - } @finally { - free(buffer); + if ([OFSystemInfo isWindowsNT]) { + wchar_t *buffer = _wgetcwd(NULL, 0); + + @try { + ret = [OFString stringWithUTF16String: buffer]; + } @finally { + free(buffer); + } + } else { + char *buffer = _getcwd(NULL, 0); + + @try { + ret = [OFString stringWithCString: buffer + encoding: [OFLocale encoding]]; + } @finally { + free(buffer); + } } return ret; # elif defined(OF_AMIGAOS) char buffer[512]; @@ -480,16 +492,11 @@ - (void)changeCurrentDirectoryPath: (OFString *)path { if (path == nil) @throw [OFInvalidArgumentException exception]; -# if defined(OF_WINDOWS) - if (_wchdir(path.UTF16String) != 0) - @throw [OFChangeCurrentDirectoryPathFailedException - exceptionWithPath: path - errNo: errno]; -# elif defined(OF_AMIGAOS) +# ifdef OF_AMIGAOS BPTR lock, oldLock; if ((lock = Lock([path cStringWithEncoding: [OFLocale encoding]], SHARED_LOCK)) == 0) { int errNo; @@ -519,11 +526,21 @@ else UnLock(oldLock); dirChanged = true; # else - if (chdir([path cStringWithEncoding: [OFLocale encoding]]) != 0) + int status; + +# ifdef OF_WINDOWS + if ([OFSystemInfo isWindowsNT]) + status = _wchdir(path.UTF16String); + else +# endif + status = chdir( + [path cStringWithEncoding: [OFLocale encoding]]); + + if (status != 0) @throw [OFChangeCurrentDirectoryPathFailedException exceptionWithPath: path errNo: errno]; # endif } Index: src/OFFileURLHandler.m ================================================================== --- src/OFFileURLHandler.m +++ src/OFFileURLHandler.m @@ -40,10 +40,11 @@ #import "OFDate.h" #import "OFFile.h" #import "OFFileManager.h" #import "OFLocale.h" #import "OFNumber.h" +#import "OFSystemInfo.h" #import "OFURL.h" #ifdef OF_HAVE_THREADS # import "OFMutex.h" #endif @@ -148,13 +149,21 @@ static int of_stat(OFString *path, of_stat_t *buffer) { #if defined(OF_WINDOWS) WIN32_FILE_ATTRIBUTE_DATA data; + bool success; - if (!GetFileAttributesExW(path.UTF16String, GetFileExInfoStandard, - &data)) { + if ([OFSystemInfo isWindowsNT]) + success = GetFileAttributesExW(path.UTF16String, + GetFileExInfoStandard, &data); + else + success = GetFileAttributesExA( + [path cStringWithEncoding: [OFLocale encoding]], + GetFileExInfoStandard, &data); + + if (!success) { setErrno(); return -1; } buffer->st_size = (uint64_t)data.nFileSizeHigh << 32 | @@ -161,10 +170,14 @@ data.nFileSizeLow; if (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) buffer->st_mode = S_IFDIR; else if (data.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) { + /* + * No need to use A functions in this branch: This is only + * available on NTFS (and hence Windows NT) anyway. + */ WIN32_FIND_DATAW findData; HANDLE findHandle; if ((findHandle = FindFirstFileW(path.UTF16String, &findData)) == INVALID_HANDLE_VALUE) { @@ -590,16 +603,21 @@ attributes: (of_file_attributes_t)attributes { #ifdef OF_FILE_MANAGER_SUPPORTS_PERMISSIONS uint16_t mode = permissions.uInt16Value & 0777; OFString *path = URL.fileSystemRepresentation; + int status; -# ifndef OF_WINDOWS - if (chmod([path cStringWithEncoding: [OFLocale encoding]], mode) != 0) -# else - if (_wchmod(path.UTF16String, mode) != 0) +# ifdef OF_WINDOWS + if ([OFSystemInfo isWindowsNT]) + status = _wchmod(path.UTF16String, mode); + else # endif + status = chmod( + [path cStringWithEncoding: [OFLocale encoding]], mode); + + if (status != 0) @throw [OFSetItemAttributesFailedException exceptionWithURL: URL attributes: attributes failedAttribute: of_file_attribute_key_posix_permissions errNo: errno]; @@ -778,11 +796,19 @@ @throw [OFInvalidArgumentException exception]; path = URL.fileSystemRepresentation; #if defined(OF_WINDOWS) - if (_wmkdir(path.UTF16String) != 0) + int status; + + if ([OFSystemInfo isWindowsNT]) + status = _wmkdir(path.UTF16String); + else + status = _mkdir( + [path cStringWithEncoding: [OFLocale encoding]]); + + if (status != 0) @throw [OFCreateDirectoryFailedException exceptionWithURL: URL errNo: errno]; #elif defined(OF_AMIGAOS) BPTR lock; @@ -844,49 +870,98 @@ path = URL.fileSystemRepresentation; #if defined(OF_WINDOWS) HANDLE handle; - WIN32_FIND_DATAW fd; path = [path stringByAppendingString: @"\\*"]; - if ((handle = FindFirstFileW(path.UTF16String, - &fd)) == INVALID_HANDLE_VALUE) { - int errNo = 0; - - if (GetLastError() == ERROR_FILE_NOT_FOUND) - errNo = ENOENT; - - @throw [OFOpenItemFailedException exceptionWithURL: URL - mode: nil - errNo: errNo]; - } - - @try { - do { - OFString *file; - - if (!wcscmp(fd.cFileName, L".") || - !wcscmp(fd.cFileName, L"..")) - continue; - - file = [[OFString alloc] - initWithUTF16String: fd.cFileName]; - @try { - [files addObject: file]; - } @finally { - [file release]; - } - } while (FindNextFileW(handle, &fd)); - - if (GetLastError() != ERROR_NO_MORE_FILES) - @throw [OFReadFailedException exceptionWithObject: self - requestedLength: 0 - errNo: EIO]; - } @finally { - FindClose(handle); + if ([OFSystemInfo isWindowsNT]) { + WIN32_FIND_DATAW fd; + + if ((handle = FindFirstFileW(path.UTF16String, + &fd)) == INVALID_HANDLE_VALUE) { + int errNo = 0; + + if (GetLastError() == ERROR_FILE_NOT_FOUND) + errNo = ENOENT; + + @throw [OFOpenItemFailedException + exceptionWithURL: URL + mode: nil + errNo: errNo]; + } + + @try { + do { + OFString *file; + + if (wcscmp(fd.cFileName, L".") == 0 || + wcscmp(fd.cFileName, L"..") == 0) + continue; + + file = [[OFString alloc] + initWithUTF16String: fd.cFileName]; + @try { + [files addObject: file]; + } @finally { + [file release]; + } + } while (FindNextFileW(handle, &fd)); + + if (GetLastError() != ERROR_NO_MORE_FILES) + @throw [OFReadFailedException + exceptionWithObject: self + requestedLength: 0 + errNo: EIO]; + } @finally { + FindClose(handle); + } + } else { + of_string_encoding_t encoding = [OFLocale encoding]; + WIN32_FIND_DATA fd; + + if ((handle = FindFirstFileA( + [path cStringWithEncoding: encoding], &fd)) == + INVALID_HANDLE_VALUE) { + int errNo = 0; + + if (GetLastError() == ERROR_FILE_NOT_FOUND) + errNo = ENOENT; + + @throw [OFOpenItemFailedException + exceptionWithURL: URL + mode: nil + errNo: errNo]; + } + + @try { + do { + OFString *file; + + if (strcmp(fd.cFileName, ".") == 0 || + strcmp(fd.cFileName, "..") == 0) + continue; + + file = [[OFString alloc] + initWithCString: fd.cFileName + encoding: encoding]; + @try { + [files addObject: file]; + } @finally { + [file release]; + } + } while (FindNextFileA(handle, &fd)); + + if (GetLastError() != ERROR_NO_MORE_FILES) + @throw [OFReadFailedException + exceptionWithObject: self + requestedLength: 0 + errNo: EIO]; + } @finally { + FindClose(handle); + } } #elif defined(OF_AMIGAOS) of_string_encoding_t encoding = [OFLocale encoding]; BPTR lock; @@ -1092,25 +1167,36 @@ objc_autoreleasePoolPop(pool2); } #ifndef OF_AMIGAOS -# ifndef OF_WINDOWS - if (rmdir([path cStringWithEncoding: [OFLocale encoding]]) != 0) -# else - if (_wrmdir(path.UTF16String) != 0) + int status; + +# ifdef OF_WINDOWS + if ([OFSystemInfo isWindowsNT]) + status = _wrmdir(path.UTF16String); + else # endif + status = rmdir( + [path cStringWithEncoding: [OFLocale encoding]]); + + if (status != 0) @throw [OFRemoveItemFailedException exceptionWithURL: URL errNo: errno]; } else { -# ifndef OF_WINDOWS - if (unlink([path cStringWithEncoding: - [OFLocale encoding]]) != 0) -# else - if (_wunlink(path.UTF16String) != 0) + int status; + +# ifdef OF_WINDOWS + if ([OFSystemInfo isWindowsNT]) + status = _wunlink(path.UTF16String); + else # endif + status = unlink( + [path cStringWithEncoding: [OFLocale encoding]]); + + if (status != 0) @throw [OFRemoveItemFailedException exceptionWithURL: URL errNo: errno]; #endif } @@ -1244,18 +1330,11 @@ destinationURL: destination errNo: EEXIST]; pool = objc_autoreleasePoolPush(); -#if defined(OF_WINDOWS) - if (_wrename(source.fileSystemRepresentation.UTF16String, - destination.fileSystemRepresentation.UTF16String) != 0) - @throw [OFMoveItemFailedException - exceptionWithSourceURL: source - destinationURL: destination - errNo: errno]; -#elif defined(OF_AMIGAOS) +#ifdef OF_AMIGAOS of_string_encoding_t encoding = [OFLocale encoding]; if (!Rename([source.fileSystemRepresentation cStringWithEncoding: encoding], [destination.fileSystemRepresentation @@ -1288,16 +1367,29 @@ exceptionWithSourceURL: source destinationURL: destination errNo: errNo]; } #else - of_string_encoding_t encoding = [OFLocale encoding]; + int status; + +# ifdef OF_WINDOWS + if ([OFSystemInfo isWindowsNT]) + status = _wrename(source.fileSystemRepresentation.UTF16String, + destination.fileSystemRepresentation.UTF16String); + else { +# endif + of_string_encoding_t encoding = [OFLocale encoding]; + + status = rename([source.fileSystemRepresentation + cStringWithEncoding: encoding], + [destination.fileSystemRepresentation + cStringWithEncoding: encoding]); +# ifdef OF_WINDOWS + } +# endif - if (rename([source.fileSystemRepresentation - cStringWithEncoding: encoding], - [destination.fileSystemRepresentation - cStringWithEncoding: encoding]) != 0) + if (status != 0) @throw [OFMoveItemFailedException exceptionWithSourceURL: source destinationURL: destination errNo: errno]; #endif Index: src/OFPlugin.m ================================================================== --- src/OFPlugin.m +++ src/OFPlugin.m @@ -23,12 +23,13 @@ #ifdef HAVE_DLFCN_H # include #endif #import "OFPlugin.h" -#import "OFString.h" #import "OFLocale.h" +#import "OFString.h" +#import "OFSystemInfo.h" #import "OFInitializationFailedException.h" #import "OFLoadPluginFailedException.h" typedef OFPlugin *(*init_plugin_t)(void); @@ -40,11 +41,15 @@ return dlopen([path cStringWithEncoding: [OFLocale encoding]], flags); #else if (path == nil) return GetModuleHandle(NULL); - return LoadLibraryW(path.UTF16String); + if ([OFSystemInfo isWindowsNT]) + return LoadLibraryW(path.UTF16String); + else + return LoadLibraryA( + [path cStringWithEncoding: [OFLocale encoding]]); #endif } void * of_dlsym(of_plugin_handle_t handle, const char *symbol) Index: src/OFString.m ================================================================== --- src/OFString.m +++ src/OFString.m @@ -39,10 +39,11 @@ # import "OFFile.h" # import "OFFileManager.h" #endif #import "OFLocale.h" #import "OFStream.h" +#import "OFSystemInfo.h" #import "OFURL.h" #import "OFURLHandler.h" #import "OFUTF8String.h" #import "OFUTF8String+Private.h" #import "OFXMLElement.h" @@ -2709,19 +2710,34 @@ #endif #ifdef OF_WINDOWS - (OFString *)stringByExpandingWindowsEnvironmentStrings { - wchar_t buffer[512]; - size_t length; - - if ((length = ExpandEnvironmentStringsW(self.UTF16String, buffer, - sizeof(buffer))) == 0) - return self; - - return [OFString stringWithUTF16String: buffer - length: length - 1]; + if ([OFSystemInfo isWindowsNT]) { + wchar_t buffer[512]; + size_t length; + + if ((length = ExpandEnvironmentStringsW(self.UTF16String, + buffer, sizeof(buffer))) == 0) + return self; + + return [OFString stringWithUTF16String: buffer + length: length - 1]; + } else { + of_string_encoding_t encoding = [OFLocale encoding]; + char buffer[512]; + size_t length; + + if ((length = ExpandEnvironmentStringsA( + [self cStringWithEncoding: encoding], buffer, + sizeof(buffer))) == 0) + return self; + + return [OFString stringWithCString: buffer + encoding: encoding + length: length - 1]; + } } #endif #ifdef OF_HAVE_FILES - (void)writeToFile: (OFString *)path Index: src/OFSystemInfo.m ================================================================== --- src/OFSystemInfo.m +++ src/OFSystemInfo.m @@ -163,41 +163,42 @@ #elif defined(OF_WINDOWS) # ifdef OF_HAVE_FILES void *pool = objc_autoreleasePoolPush(); @try { - wchar_t systemDir[PATH_MAX]; + of_string_encoding_t encoding = [OFLocale encoding]; + char systemDir[PATH_MAX]; UINT systemDirLen; OFString *systemDirString; - const of_char16_t *path; + const char *path; void *buffer; DWORD bufferLen; - systemDirLen = GetSystemDirectoryW(systemDir, PATH_MAX); + systemDirLen = GetSystemDirectoryA(systemDir, PATH_MAX); if (systemDirLen == 0) return; - systemDirString = [OFString - stringWithUTF16String: systemDir - length: systemDirLen]; - path = [systemDirString stringByAppendingPathComponent: - @"kernel32.dll"].UTF16String; + systemDirString = [OFString stringWithCString: systemDir + encoding: encoding + length: systemDirLen]; + path = [[systemDirString stringByAppendingPathComponent: + @"kernel32.dll"] cStringWithEncoding: encoding]; - if ((bufferLen = GetFileVersionInfoSizeW(path, NULL)) == 0) + if ((bufferLen = GetFileVersionInfoSizeA(path, NULL)) == 0) return; if ((buffer = malloc(bufferLen)) == 0) return; @try { void *data; UINT dataLen; VS_FIXEDFILEINFO *info; - if (!GetFileVersionInfoW(path, 0, bufferLen, buffer)) + if (!GetFileVersionInfoA(path, 0, bufferLen, buffer)) return; - if (!VerQueryValueW(buffer, L"\\", &data, &dataLen) || + if (!VerQueryValueA(buffer, "\\", &data, &dataLen) || dataLen < sizeof(info)) return; info = (VS_FIXEDFILEINFO *)data; Index: src/OFWindowsRegistryKey.m ================================================================== --- src/OFWindowsRegistryKey.m +++ src/OFWindowsRegistryKey.m @@ -17,10 +17,12 @@ #include "config.h" #import "OFWindowsRegistryKey.h" #import "OFData.h" +#import "OFLocale.h" +#import "OFSystemInfo.h" #include #import "OFCreateWindowsRegistryKeyFailedException.h" #import "OFDeleteWindowsRegistryKeyFailedException.h" @@ -106,12 +108,19 @@ { void *pool = objc_autoreleasePoolPush(); LSTATUS status; HKEY subKey; - if ((status = RegOpenKeyExW(_hKey, path.UTF16String, options, - securityAndAccessRights, &subKey)) != ERROR_SUCCESS) { + if ([OFSystemInfo isWindowsNT]) + status = RegOpenKeyExW(_hKey, path.UTF16String, options, + securityAndAccessRights, &subKey); + else + status = RegOpenKeyExA(_hKey, + [path cStringWithEncoding: [OFLocale encoding]], options, + securityAndAccessRights, &subKey); + + if (status != ERROR_SUCCESS) { if (status == ERROR_FILE_NOT_FOUND) { objc_autoreleasePoolPop(pool); return nil; } @@ -149,13 +158,21 @@ { void *pool = objc_autoreleasePoolPush(); LSTATUS status; HKEY subKey; - if ((status = RegCreateKeyExW(_hKey, path.UTF16String, 0, - NULL, options, securityAndAccessRights, securityAttributes, - &subKey, NULL)) != ERROR_SUCCESS) + if ([OFSystemInfo isWindowsNT]) + status = RegCreateKeyExW(_hKey, path.UTF16String, 0, + NULL, options, securityAndAccessRights, securityAttributes, + &subKey, NULL); + else + status = RegCreateKeyExA(_hKey, + [path cStringWithEncoding: [OFLocale encoding]], 0, NULL, + options, securityAndAccessRights, securityAttributes, + &subKey, NULL); + + if (status != ERROR_SUCCESS) @throw [OFCreateWindowsRegistryKeyFailedException exceptionWithRegistryKey: self path: path options: options securityAndAccessRights: securityAndAccessRights @@ -174,15 +191,21 @@ { void *pool = objc_autoreleasePoolPush(); BYTE stackBuffer[256], *buffer = stackBuffer; DWORD length = sizeof(stackBuffer); OFMutableData *ret = nil; + bool winNT = [OFSystemInfo isWindowsNT]; LSTATUS status; for (;;) { - status = RegQueryValueExW(_hKey, value.UTF16String, NULL, type, - buffer, &length); + if (winNT) + status = RegQueryValueExW(_hKey, value.UTF16String, + NULL, type, buffer, &length); + else + status = RegQueryValueExA(_hKey, + [value cStringWithEncoding: [OFLocale encoding]], + NULL, type, buffer, &length); switch (status) { case ERROR_SUCCESS: if (buffer == stackBuffer) { objc_autoreleasePoolPop(pool); @@ -227,12 +250,19 @@ LSTATUS status; if (length > UINT32_MAX) @throw [OFOutOfRangeException exception]; - if ((status = RegSetValueExW(_hKey, value.UTF16String, 0, type, - data.items, (DWORD)length)) != ERROR_SUCCESS) + if ([OFSystemInfo isWindowsNT]) + status = RegSetValueExW(_hKey, value.UTF16String, 0, type, + data.items, (DWORD)length); + else + status = RegSetValueExA(_hKey, + [value cStringWithEncoding: [OFLocale encoding]], 0, type, + data.items, (DWORD)length); + + if (status != ERROR_SUCCESS) @throw [OFSetWindowsRegistryValueFailedException exceptionWithRegistryKey: self value: value data: data type: type @@ -250,41 +280,62 @@ { void *pool = objc_autoreleasePoolPush(); DWORD type; OFData *data = [self dataForValue: value type: &type]; - const of_char16_t *UTF16String; - size_t length; OFString *ret; if (data == nil) return nil; if (type != REG_SZ && type != REG_EXPAND_SZ && type != REG_LINK) @throw [OFInvalidEncodingException exception]; - UTF16String = data.items; - length = data.count; - - if (data.itemSize != 1 || length % 2 == 1) + if (data.itemSize != 1) @throw [OFInvalidFormatException exception]; - length /= 2; - - /* - * REG_SZ and REG_EXPAND_SZ contain a \0, but can contain data after it - * that should be ignored. - */ - for (size_t i = 0; i < length; i++) { - if (UTF16String[i] == 0) { - length = i; - break; - } - } - - ret = [[OFString alloc] initWithUTF16String: UTF16String - length: length]; + if ([OFSystemInfo isWindowsNT]) { + const of_char16_t *UTF16String = data.items; + size_t length = data.count; + + if (length % 2 == 1) + @throw [OFInvalidFormatException exception]; + + length /= 2; + + /* + * REG_SZ and REG_EXPAND_SZ contain a \0, but can contain data + * after it that should be ignored. + */ + for (size_t i = 0; i < length; i++) { + if (UTF16String[i] == 0) { + length = i; + break; + } + } + + ret = [[OFString alloc] initWithUTF16String: UTF16String + length: length]; + } else { + const char *cString = data.items; + size_t length = data.count; + + /* + * REG_SZ and REG_EXPAND_SZ contain a \0, but can contain data + * after it that should be ignored. + */ + for (size_t i = 0; i < length; i++) { + if (cString[i] == 0) { + length = i; + break; + } + } + + ret = [[OFString alloc] initWithCString: cString + encoding: [OFLocale encoding] + length: length]; + } if (typeOut != NULL) *typeOut = type; objc_autoreleasePoolPop(pool); @@ -305,13 +356,23 @@ type: (DWORD)type { void *pool = objc_autoreleasePoolPush(); OFData *data; - data = [OFData dataWithItems: string.UTF16String - itemSize: sizeof(of_char16_t) - count: string.UTF16StringLength + 1]; + if ([OFSystemInfo isWindowsNT]) + data = [OFData dataWithItems: string.UTF16String + itemSize: sizeof(of_char16_t) + count: string.UTF16StringLength + 1]; + else { + of_string_encoding_t encoding = [OFLocale encoding]; + const char *cString = [string cStringWithEncoding: encoding]; + size_t length = [string cStringLengthWithEncoding: encoding]; + + data = [OFData dataWithItems: cString + count: length + 1]; + } + [self setData: data forValue: value type: type]; objc_autoreleasePoolPop(pool); @@ -320,12 +381,17 @@ - (void)deleteValue: (OFString *)value { void *pool = objc_autoreleasePoolPush(); LSTATUS status; - if ((status = RegDeleteValueW(_hKey, value.UTF16String)) != - ERROR_SUCCESS) + if ([OFSystemInfo isWindowsNT]) + status = RegDeleteValueW(_hKey, value.UTF16String); + else + status = RegDeleteValueA(_hKey, + [value cStringWithEncoding: [OFLocale encoding]]); + + if (status != ERROR_SUCCESS) @throw [OFDeleteWindowsRegistryValueFailedException exceptionWithRegistryKey: self value: value status: status]; @@ -335,15 +401,20 @@ - (void)deleteSubkeyAtPath: (OFString *)subkeyPath { void *pool = objc_autoreleasePoolPush(); LSTATUS status; - if ((status = RegDeleteKeyW(_hKey, subkeyPath.UTF16String)) != - ERROR_SUCCESS) + if ([OFSystemInfo isWindowsNT]) + status = RegDeleteKeyW(_hKey, subkeyPath.UTF16String); + else + status = RegDeleteKeyA(_hKey, + [subkeyPath cStringWithEncoding: [OFLocale encoding]]); + + if (status != ERROR_SUCCESS) @throw [OFDeleteWindowsRegistryKeyFailedException exceptionWithRegistryKey: self subkeyPath: subkeyPath status: status]; objc_autoreleasePoolPop(pool); } @end Index: src/exceptions/OFException.m ================================================================== --- src/exceptions/OFException.m +++ src/exceptions/OFException.m @@ -25,13 +25,14 @@ #ifdef HAVE_DLFCN_H # include #endif #import "OFException.h" -#import "OFString.h" #import "OFArray.h" #import "OFLocale.h" +#import "OFString.h" +#import "OFSystemInfo.h" #import "OFInitializationFailedException.h" #import "OFLockFailedException.h" #import "OFUnlockFailedException.h" @@ -209,23 +210,43 @@ #ifdef OF_WINDOWS OFString * of_windows_status_to_string(LSTATUS status) { + OFString *string = nil; void *buffer; - OFString *string; - - if (FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS | - FORMAT_MESSAGE_MAX_WIDTH_MASK, NULL, status, 0, (LPWSTR)&buffer, 0, - NULL) != 0) { - @try { - string = [OFString stringWithUTF16String: buffer]; - } @finally { - LocalFree(buffer); - } - } else + + if ([OFSystemInfo isWindowsNT]) { + if (FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_IGNORE_INSERTS | + FORMAT_MESSAGE_MAX_WIDTH_MASK, NULL, status, 0, + (LPWSTR)&buffer, 0, NULL) != 0) { + @try { + string = [OFString + stringWithUTF16String: buffer]; + } @finally { + LocalFree(buffer); + } + } + } else { + if (FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_IGNORE_INSERTS | + FORMAT_MESSAGE_MAX_WIDTH_MASK, NULL, status, 0, + (LPSTR)&buffer, 0, NULL) != 0) { + @try { + string = [OFString + stringWithCString: buffer + encoding: [OFLocale encoding]]; + } @finally { + LocalFree(buffer); + } + } + } + + if (string == nil) string = [OFString stringWithFormat: @"Status code %u", status]; return string; } #endif Index: src/platform/windows/OFProcess.m ================================================================== --- src/platform/windows/OFProcess.m +++ src/platform/windows/OFProcess.m @@ -19,14 +19,16 @@ #include #include #import "OFProcess.h" -#import "OFString.h" #import "OFArray.h" +#import "OFData.h" #import "OFDictionary.h" -#import "OFData.h" +#import "OFLocale.h" +#import "OFString.h" +#import "OFSystemInfo.h" #import "OFInitializationFailedException.h" #import "OFNotOpenException.h" #import "OFOutOfRangeException.h" #import "OFReadFailedException.h" @@ -33,11 +35,12 @@ #import "OFWriteFailedException.h" #include @interface OFProcess () -- (of_char16_t *)of_environmentForDictionary: (OFDictionary *)dictionary; +- (of_char16_t *)of_wideEnvironmentForDictionary: (OFDictionary *)dictionary; +- (char *)of_environmentForDictionary: (OFDictionary *)environment; @end @implementation OFProcess + (instancetype)processWithProgram: (OFString *)program { @@ -111,15 +114,12 @@ self = [super init]; @try { SECURITY_ATTRIBUTES sa; PROCESS_INFORMATION pi; - STARTUPINFOW si; void *pool; OFMutableString *argumentsString; - of_char16_t *argumentsCopy; - size_t length; _process = INVALID_HANDLE_VALUE; _readPipe[0] = _writePipe[1] = NULL; sa.nLength = sizeof(sa); @@ -129,30 +129,25 @@ if (!CreatePipe(&_readPipe[0], &_readPipe[1], &sa, 0)) @throw [OFInitializationFailedException exceptionWithClass: self.class]; if (!SetHandleInformation(_readPipe[0], HANDLE_FLAG_INHERIT, 0)) - @throw [OFInitializationFailedException - exceptionWithClass: self.class]; + if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED) + @throw [OFInitializationFailedException + exceptionWithClass: self.class]; if (!CreatePipe(&_writePipe[0], &_writePipe[1], &sa, 0)) @throw [OFInitializationFailedException exceptionWithClass: self.class]; if (!SetHandleInformation(_writePipe[1], HANDLE_FLAG_INHERIT, 0)) - @throw [OFInitializationFailedException - exceptionWithClass: self.class]; + if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED) + @throw [OFInitializationFailedException + exceptionWithClass: self.class]; memset(&pi, 0, sizeof(pi)); - memset(&si, 0, sizeof(si)); - - si.cb = sizeof(si); - si.hStdInput = _writePipe[0]; - si.hStdOutput = _readPipe[1]; - si.hStdError = GetStdHandle(STD_ERROR_HANDLE); - si.dwFlags |= STARTF_USESTDHANDLES; pool = objc_autoreleasePoolPush(); argumentsString = [OFMutableString stringWithString: programName]; @@ -185,25 +180,57 @@ if (containsSpaces) [argumentsString appendString: @"\""]; } - length = argumentsString.UTF16StringLength; - argumentsCopy = [self allocMemoryWithSize: sizeof(of_char16_t) - count: length + 1]; - memcpy(argumentsCopy, argumentsString.UTF16String, - (argumentsString.UTF16StringLength + 1) * 2); - @try { - if (!CreateProcessW(program.UTF16String, - argumentsCopy, NULL, NULL, TRUE, - CREATE_UNICODE_ENVIRONMENT, + if ([OFSystemInfo isWindowsNT]) { + size_t length; + of_char16_t *argumentsCopy; + STARTUPINFOW si; + + memset(&si, 0, sizeof(si)); + si.cb = sizeof(si); + si.hStdInput = _writePipe[0]; + si.hStdOutput = _readPipe[1]; + si.hStdError = GetStdHandle(STD_ERROR_HANDLE); + si.dwFlags |= STARTF_USESTDHANDLES; + + length = argumentsString.UTF16StringLength; + argumentsCopy = [self + allocMemoryWithSize: sizeof(of_char16_t) + count: length + 1]; + memcpy(argumentsCopy, argumentsString.UTF16String, + (length + 1) * 2); + @try { + if (!CreateProcessW(program.UTF16String, + argumentsCopy, NULL, NULL, TRUE, + CREATE_UNICODE_ENVIRONMENT, + [self of_wideEnvironmentForDictionary: + environment], NULL, &si, &pi)) + @throw [OFInitializationFailedException + exceptionWithClass: self.class]; + } @finally { + [self freeMemory: argumentsCopy]; + } + } else { + of_string_encoding_t encoding = [OFLocale encoding]; + STARTUPINFO si; + + memset(&si, 0, sizeof(si)); + si.cb = sizeof(si); + si.hStdInput = _writePipe[0]; + si.hStdOutput = _readPipe[1]; + si.hStdError = GetStdHandle(STD_ERROR_HANDLE); + si.dwFlags |= STARTF_USESTDHANDLES; + + if (!CreateProcessA([program cStringWithEncoding: + encoding], (char *)[argumentsString + cStringWithEncoding: encoding], NULL, NULL, TRUE, 0, [self of_environmentForDictionary: environment], NULL, &si, &pi)) @throw [OFInitializationFailedException exceptionWithClass: self.class]; - } @finally { - [self freeMemory: argumentsCopy]; } objc_autoreleasePoolPop(pool); _process = pi.hProcess; @@ -225,11 +252,11 @@ [self close]; [super dealloc]; } -- (of_char16_t *)of_environmentForDictionary: (OFDictionary *)environment +- (of_char16_t *)of_wideEnvironmentForDictionary: (OFDictionary *)environment { OFMutableData *env; OFEnumerator *keyEnumerator, *objectEnumerator; OFString *key, *object; const of_char16_t equal = '='; @@ -253,10 +280,41 @@ [env addItems: &zero count: 1]; } [env addItems: zero count: 2]; + + return env.mutableItems; +} + +- (char *)of_environmentForDictionary: (OFDictionary *)environment +{ + of_string_encoding_t encoding = [OFLocale encoding]; + OFMutableData *env; + OFEnumerator *keyEnumerator, *objectEnumerator; + OFString *key, *object; + + if (environment == nil) + return NULL; + + env = [OFMutableData data]; + + keyEnumerator = [environment keyEnumerator]; + objectEnumerator = [environment objectEnumerator]; + while ((key = [keyEnumerator nextObject]) != nil && + (object = [objectEnumerator nextObject]) != nil) { + [env addItems: [key cStringWithEncoding: encoding] + count: [key cStringLengthWithEncoding: encoding]]; + [env addItems: "=" + count: 1]; + [env addItems: [object cStringWithEncoding: encoding] + count: [object cStringLengthWithEncoding: encoding]]; + [env addItems: "" + count: 1]; + } + [env addItems: "\0" + count: 2]; return env.mutableItems; } - (bool)lowlevelIsAtEndOfStream