Index: src/OFWin32ConsoleStdIOStream.m ================================================================== --- src/OFWin32ConsoleStdIOStream.m +++ src/OFWin32ConsoleStdIOStream.m @@ -57,10 +57,29 @@ #import "OFOutOfRangeException.h" #import "OFReadFailedException.h" #import "OFWriteFailedException.h" #include + +static of_string_encoding_t +codepageToEncoding(UINT codepage) +{ + switch (codepage) { + case 437: + return OF_STRING_ENCODING_CODEPAGE_437; + case 850: + return OF_STRING_ENCODING_CODEPAGE_850; + case 858: + return OF_STRING_ENCODING_CODEPAGE_858; + case 1251: + return OF_STRING_ENCODING_WINDOWS_1251; + case 1252: + return OF_STRING_ENCODING_WINDOWS_1252; + default: + @throw [OFInvalidEncodingException exception]; + } +} @implementation OFWin32ConsoleStdIOStream + (void)load { int fd; @@ -107,11 +126,11 @@ void *pool = objc_autoreleasePoolPush(); char *buffer = buffer_; of_char16_t *UTF16; size_t j = 0; - if (length > sizeof(UINT32_MAX)) + if (length > UINT32_MAX) @throw [OFOutOfRangeException exception]; UTF16 = [self allocMemoryWithSize: sizeof(of_char16_t) count: length]; @try { @@ -118,15 +137,40 @@ DWORD UTF16Len; OFMutableData *rest = nil; size_t i = 0; if (!ReadConsoleW(_handle, UTF16, (DWORD)length, &UTF16Len, - NULL)) - @throw [OFReadFailedException - exceptionWithObject: self - requestedLength: length * 2 - errNo: EIO]; + NULL)) { + of_string_encoding_t encoding; + OFString *string; + size_t stringLen; + + if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED) + @throw [OFReadFailedException + exceptionWithObject: self + requestedLength: length * 2 + errNo: EIO]; + + if (!ReadConsoleA(_handle, (char *)UTF16, (DWORD)length, + &UTF16Len, NULL)) + @throw [OFReadFailedException + exceptionWithObject: self + requestedLength: length + errNo: EIO]; + + encoding = codepageToEncoding(GetConsoleCP()); + string = [OFString stringWithCString: (char *)UTF16 + encoding: encoding + length: UTF16Len]; + stringLen = string.UTF16StringLength; + + if (stringLen > length) + @throw [OFOutOfRangeException exception]; + + UTF16Len = (DWORD)stringLen; + memcpy(UTF16, string.UTF16String, stringLen); + } if (UTF16Len > 0 && _incompleteUTF16Surrogate != 0) { of_unichar_t c = (((_incompleteUTF16Surrogate & 0x3FF) << 10) | (UTF16[0] & 0x3FF)) + 0x10000; @@ -270,16 +314,44 @@ UTF16Len = 1; } } if (!WriteConsoleW(_handle, UTF16, UTF16Len, &bytesWritten, - NULL)) - @throw [OFWriteFailedException - exceptionWithObject: self - requestedLength: UTF16Len * 2 - bytesWritten: 0 - errNo: EIO]; + NULL)) { + void *pool; + OFString *string; + of_string_encoding_t encoding; + size_t nativeLen; + + if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED) + @throw [OFWriteFailedException + exceptionWithObject: self + requestedLength: UTF16Len * 2 + bytesWritten: bytesWritten * 2 + errNo: EIO]; + + pool = objc_autoreleasePoolPush(); + string = [OFString stringWithUTF16String: UTF16 + length: UTF16Len]; + encoding = codepageToEncoding(GetConsoleOutputCP()); + nativeLen = [string + cStringLengthWithEncoding: encoding]; + + if (nativeLen > UINT32_MAX) + @throw [OFOutOfRangeException exception]; + + if (!WriteConsoleA(_handle, + [string cStringWithEncoding: encoding], + (DWORD)nativeLen, &bytesWritten, NULL)) + @throw [OFWriteFailedException + exceptionWithObject: self + requestedLength: nativeLen + bytesWritten: bytesWritten + errNo: EIO]; + + objc_autoreleasePoolPop(pool); + } if (bytesWritten != UTF16Len) @throw [OFWriteFailedException exceptionWithObject: self requestedLength: UTF16Len * 2 @@ -329,16 +401,45 @@ } if (j > UINT32_MAX) @throw [OFOutOfRangeException exception]; - if (!WriteConsoleW(_handle, tmp, (DWORD)j, &bytesWritten, NULL)) - @throw [OFWriteFailedException - exceptionWithObject: self - requestedLength: j * 2 - bytesWritten: 0 - errNo: EIO]; + if (!WriteConsoleW(_handle, tmp, (DWORD)j, &bytesWritten, + NULL)) { + void *pool; + OFString *string; + of_string_encoding_t encoding; + size_t nativeLen; + + if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED) + @throw [OFWriteFailedException + exceptionWithObject: self + requestedLength: j * 2 + bytesWritten: bytesWritten * 2 + errNo: EIO]; + + pool = objc_autoreleasePoolPush(); + string = [OFString stringWithUTF16String: tmp + length: j]; + encoding = codepageToEncoding(GetConsoleOutputCP()); + nativeLen = [string + cStringLengthWithEncoding: encoding]; + + if (nativeLen > UINT32_MAX) + @throw [OFOutOfRangeException exception]; + + if (!WriteConsoleA(_handle, + [string cStringWithEncoding: encoding], + (DWORD)nativeLen, &bytesWritten, NULL)) + @throw [OFWriteFailedException + exceptionWithObject: self + requestedLength: nativeLen + bytesWritten: bytesWritten + errNo: EIO]; + + objc_autoreleasePoolPop(pool); + } if (bytesWritten != j) @throw [OFWriteFailedException exceptionWithObject: self requestedLength: j * 2