diff options
Diffstat (limited to 'winpr/libwinpr/crt/unicode_apple.m')
-rw-r--r-- | winpr/libwinpr/crt/unicode_apple.m | 146 |
1 files changed, 146 insertions, 0 deletions
diff --git a/winpr/libwinpr/crt/unicode_apple.m b/winpr/libwinpr/crt/unicode_apple.m new file mode 100644 index 0000000..159252b --- /dev/null +++ b/winpr/libwinpr/crt/unicode_apple.m @@ -0,0 +1,146 @@ +/** + * WinPR: Windows Portable Runtime + * Unicode Conversion (CRT) + * + * Copyright 2022 Armin Novak <anovak@thincast.com> + * Copyright 2022 Thincast Technologies GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import <Foundation/Foundation.h> + +#include <winpr/config.h> +#include <winpr/assert.h> + +#include <errno.h> +#include <wctype.h> + +#include <winpr/crt.h> +#include <winpr/error.h> +#include <winpr/print.h> + +#ifndef MIN +#define MIN(a, b) (a) < (b) ? (a) : (b) +#endif + +#include "../log.h" +#define TAG WINPR_TAG("unicode") + +int int_MultiByteToWideChar(UINT CodePage, DWORD dwFlags, LPCSTR lpMultiByteStr, int cbMultiByte, + LPWSTR lpWideCharStr, int cchWideChar) +{ + const BOOL isNullTerminated = cbMultiByte < 0; + + /* If cbMultiByte is 0, the function fails */ + if ((cbMultiByte == 0) || (cbMultiByte < -1)) + return 0; + + /* If cbMultiByte is -1, the string is null-terminated */ + if (isNullTerminated) + { + size_t len = strnlen(lpMultiByteStr, INT32_MAX); + if (len >= INT32_MAX) + return 0; + cbMultiByte = (int)len + 1; + } + + NSString *utf = [[NSString alloc] initWithBytes:lpMultiByteStr + length:cbMultiByte + encoding:NSUTF8StringEncoding]; + if (!utf) + { + WLog_WARN(TAG, "[NSString alloc] NSUTF8StringEncoding failed [%d] '%s'", cbMultiByte, + lpMultiByteStr); + return -1; + } + + const WCHAR *utf16 = + (const WCHAR *)[utf cStringUsingEncoding:NSUTF16LittleEndianStringEncoding]; + const size_t utf16ByteLen = [utf lengthOfBytesUsingEncoding:NSUTF16LittleEndianStringEncoding]; + const size_t utf16CharLen = utf16ByteLen / sizeof(WCHAR); + if (!utf16) + { + WLog_WARN(TAG, "[utf cStringUsingEncoding:NSUTF16LittleEndianStringEncoding] failed"); + return -1; + } + + if (cchWideChar == 0) + return utf16CharLen; + else if (cchWideChar < utf16CharLen) + { + SetLastError(ERROR_INSUFFICIENT_BUFFER); + return 0; + } + else + { + const size_t mlen = MIN((size_t)utf16CharLen, cchWideChar); + const size_t len = _wcsnlen(utf16, mlen); + memcpy(lpWideCharStr, utf16, len * sizeof(WCHAR)); + if ((len < (size_t)cchWideChar) && (len > 0) && (lpWideCharStr[len - 1] != '\0')) + lpWideCharStr[len] = '\0'; + return utf16CharLen; + } +} + +int int_WideCharToMultiByte(UINT CodePage, DWORD dwFlags, LPCWSTR lpWideCharStr, int cchWideChar, + LPSTR lpMultiByteStr, int cbMultiByte, LPCSTR lpDefaultChar, + LPBOOL lpUsedDefaultChar) +{ + const BOOL isNullTerminated = cchWideChar < 0; + + /* If cchWideChar is 0, the function fails */ + if ((cchWideChar == 0) || (cchWideChar < -1)) + return 0; + + /* If cchWideChar is -1, the string is null-terminated */ + if (isNullTerminated) + { + size_t len = _wcslen(lpWideCharStr); + if (len >= INT32_MAX) + return 0; + cchWideChar = (int)len + 1; + } + + NSString *utf = [[NSString alloc] initWithCharacters:lpWideCharStr length:cchWideChar]; + if (!utf) + { + WLog_WARN(TAG, "[NSString alloc] initWithCharacters failed [%d] 'XXX'", cchWideChar); + return -1; + } + + const char *utf8 = [utf cStringUsingEncoding:NSUTF8StringEncoding]; + const size_t utf8Len = [utf lengthOfBytesUsingEncoding:NSUTF8StringEncoding]; + if (!utf8) + { + WLog_WARN(TAG, "[utf cStringUsingEncoding:NSUTF8StringEncoding] failed"); + return -1; + } + + if (cbMultiByte == 0) + return utf8Len; + else if (cbMultiByte < utf8Len) + { + SetLastError(ERROR_INSUFFICIENT_BUFFER); + return 0; + } + else + { + const size_t mlen = MIN((size_t)cbMultiByte, utf8Len); + const size_t len = strnlen(utf8, mlen); + memcpy(lpMultiByteStr, utf8, len * sizeof(char)); + if ((len < (size_t)cbMultiByte) && (len > 0) && (lpMultiByteStr[len - 1] != '\0')) + lpMultiByteStr[len] = '\0'; + return utf8Len; + } +} |