Milestone 5: deliver embedded RDP sessions and lifecycle hardening

This commit is contained in:
Keith Smith
2026-03-03 18:59:26 -07:00
parent 230a401386
commit 36006bd4aa
2941 changed files with 724359 additions and 77 deletions

View File

@@ -0,0 +1,52 @@
# WinPR: Windows Portable Runtime
# libwinpr-crt cmake build script
#
# Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
#
# 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.
set(CRT_FILES
alignment.c
conversion.c
buffer.c
memory.c
unicode.c
string.c
assert.c
)
if(WITH_UNICODE_BUILTIN)
list(APPEND CRT_FILES unicode_builtin.c)
else()
if(ANDROID)
list(APPEND CRT_FILES unicode_android.c)
elseif(NOT APPLE AND NOT WIN32)
find_package(ICU REQUIRED i18n uc io data)
winpr_pc_add_requires_private("icu-uc")
winpr_pc_add_requires_private("icu-io")
winpr_pc_add_requires_private("icu-i18n")
list(APPEND CRT_FILES unicode_icu.c)
winpr_system_include_directory_add(${ICU_INCLUDE_DIRS})
winpr_library_add_private(${ICU_LIBRARIES})
elseif(APPLE)
list(APPEND CRT_FILES unicode_apple.m)
find_library(FOUNDATION_FRAMEWORK Foundation REQUIRED)
winpr_library_add_private(${FOUNDATION_FRAMEWORK})
endif()
endif()
winpr_module_add(${CRT_FILES})
if(BUILD_TESTING_INTERNAL OR BUILD_TESTING)
add_subdirectory(test)
endif()

View File

@@ -0,0 +1,7 @@
set(MINWIN_LAYER "0")
set(MINWIN_GROUP "none")
set(MINWIN_MAJOR_VERSION "0")
set(MINWIN_MINOR_VERSION "0")
set(MINWIN_SHORT_NAME "crt")
set(MINWIN_LONG_NAME "Microsoft C Run-Time")
set(MODULE_LIBRARY_NAME "${MINWIN_SHORT_NAME}")

View File

@@ -0,0 +1,261 @@
/**
* WinPR: Windows Portable Runtime
* Data Alignment
*
* Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
*
* 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.
*/
#include <stdlib.h>
#include <winpr/config.h>
#include <winpr/crt.h>
/* Data Alignment: http://msdn.microsoft.com/en-us/library/fs9stz4e/ */
#if !defined(_WIN32) || (defined(__MINGW32__) && !defined(_UCRT))
#include <stdint.h>
#include <limits.h>
#define WINPR_ALIGNED_MEM_SIGNATURE 0x0BA0BAB
#define WINPR_ALIGNED_MEM_STRUCT_FROM_PTR(_memptr) \
(WINPR_ALIGNED_MEM*)(((size_t)(((BYTE*)(_memptr)) - sizeof(WINPR_ALIGNED_MEM))))
#include <stdlib.h>
#include "../log.h"
#define TAG WINPR_TAG("crt")
struct winpr_aligned_mem
{
UINT32 sig;
size_t size;
void* base_addr;
};
typedef struct winpr_aligned_mem WINPR_ALIGNED_MEM;
void* winpr_aligned_malloc(size_t size, size_t alignment)
{
return winpr_aligned_offset_malloc(size, alignment, 0);
}
void* winpr_aligned_calloc(size_t count, size_t size, size_t alignment)
{
return winpr_aligned_recalloc(nullptr, count, size, alignment);
}
void* winpr_aligned_realloc(void* memblock, size_t size, size_t alignment)
{
return winpr_aligned_offset_realloc(memblock, size, alignment, 0);
}
void* winpr_aligned_recalloc(void* memblock, size_t num, size_t size, size_t alignment)
{
return winpr_aligned_offset_recalloc(memblock, num, size, alignment, 0);
}
void* winpr_aligned_offset_malloc(size_t size, size_t alignment, size_t offset)
{
size_t header = 0;
size_t alignsize = 0;
uintptr_t basesize = 0;
void* base = nullptr;
void* memblock = nullptr;
WINPR_ALIGNED_MEM* pMem = nullptr;
/* alignment must be a power of 2 */
if (alignment % 2 == 1)
return nullptr;
/* offset must be less than size */
if (offset >= size)
return nullptr;
/* minimum alignment is pointer size */
if (alignment < sizeof(void*))
alignment = sizeof(void*);
if (alignment > SIZE_MAX - sizeof(WINPR_ALIGNED_MEM))
return nullptr;
header = sizeof(WINPR_ALIGNED_MEM) + alignment;
if (size > SIZE_MAX - header)
return nullptr;
alignsize = size + header;
/* malloc size + alignment to make sure we can align afterwards */
#if defined(_ISOC11_SOURCE)
base = aligned_alloc(alignment, alignsize);
#elif defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200112L) || (_XOPEN_SOURCE >= 600)
if (posix_memalign(&base, alignment, alignsize) != 0)
return nullptr;
#else
base = malloc(alignsize);
#endif
if (!base)
return nullptr;
basesize = (uintptr_t)base;
if ((offset > UINTPTR_MAX) || (header > UINTPTR_MAX - offset) ||
(basesize > UINTPTR_MAX - header - offset))
{
free(base);
return nullptr;
}
memblock = (void*)(((basesize + header + offset) & ~(alignment - 1)) - offset);
pMem = WINPR_ALIGNED_MEM_STRUCT_FROM_PTR(memblock);
pMem->sig = WINPR_ALIGNED_MEM_SIGNATURE;
pMem->base_addr = base;
pMem->size = size;
return memblock;
}
void* winpr_aligned_offset_realloc(void* memblock, size_t size, size_t alignment, size_t offset)
{
size_t copySize = 0;
void* newMemblock = nullptr;
WINPR_ALIGNED_MEM* pMem = nullptr;
WINPR_ALIGNED_MEM* pNewMem = nullptr;
if (!memblock)
return winpr_aligned_offset_malloc(size, alignment, offset);
pMem = WINPR_ALIGNED_MEM_STRUCT_FROM_PTR(memblock);
if (pMem->sig != WINPR_ALIGNED_MEM_SIGNATURE)
{
WLog_ERR(TAG,
"_aligned_offset_realloc: memory block was not allocated by _aligned_malloc!");
return nullptr;
}
if (size == 0)
{
winpr_aligned_free(memblock);
return nullptr;
}
newMemblock = winpr_aligned_offset_malloc(size, alignment, offset);
if (!newMemblock)
return nullptr;
pNewMem = WINPR_ALIGNED_MEM_STRUCT_FROM_PTR(newMemblock);
copySize = (pNewMem->size < pMem->size) ? pNewMem->size : pMem->size;
CopyMemory(newMemblock, memblock, copySize);
winpr_aligned_free(memblock);
return newMemblock;
}
static inline size_t cMIN(size_t a, size_t b)
{
if (a > b)
return b;
return a;
}
void* winpr_aligned_offset_recalloc(void* memblock, size_t num, size_t size, size_t alignment,
size_t offset)
{
char* newMemblock = nullptr;
WINPR_ALIGNED_MEM* pMem = nullptr;
WINPR_ALIGNED_MEM* pNewMem = nullptr;
if (!memblock)
{
newMemblock = winpr_aligned_offset_malloc(size * num, alignment, offset);
if (newMemblock)
{
pNewMem = WINPR_ALIGNED_MEM_STRUCT_FROM_PTR(newMemblock);
ZeroMemory(newMemblock, pNewMem->size);
}
return newMemblock;
}
pMem = WINPR_ALIGNED_MEM_STRUCT_FROM_PTR(memblock);
if (pMem->sig != WINPR_ALIGNED_MEM_SIGNATURE)
{
WLog_ERR(TAG,
"_aligned_offset_recalloc: memory block was not allocated by _aligned_malloc!");
goto fail;
}
if ((num == 0) || (size == 0))
goto fail;
if (pMem->size > (1ull * num * size) + alignment)
return memblock;
newMemblock = winpr_aligned_offset_malloc(size * num, alignment, offset);
if (!newMemblock)
goto fail;
pNewMem = WINPR_ALIGNED_MEM_STRUCT_FROM_PTR(newMemblock);
{
const size_t csize = cMIN(pMem->size, pNewMem->size);
memcpy(newMemblock, memblock, csize);
ZeroMemory(newMemblock + csize, pNewMem->size - csize);
}
fail:
winpr_aligned_free(memblock);
return newMemblock;
}
size_t winpr_aligned_msize(void* memblock, WINPR_ATTR_UNUSED size_t alignment,
WINPR_ATTR_UNUSED size_t offset)
{
WINPR_ALIGNED_MEM* pMem = nullptr;
if (!memblock)
return 0;
pMem = WINPR_ALIGNED_MEM_STRUCT_FROM_PTR(memblock);
if (pMem->sig != WINPR_ALIGNED_MEM_SIGNATURE)
{
WLog_ERR(TAG, "_aligned_msize: memory block was not allocated by _aligned_malloc!");
return 0;
}
return pMem->size;
}
void winpr_aligned_free(void* memblock)
{
WINPR_ALIGNED_MEM* pMem = nullptr;
if (!memblock)
return;
pMem = WINPR_ALIGNED_MEM_STRUCT_FROM_PTR(memblock);
if (pMem->sig != WINPR_ALIGNED_MEM_SIGNATURE)
{
WLog_ERR(TAG, "_aligned_free: memory block was not allocated by _aligned_malloc!");
return;
}
free(pMem->base_addr);
}
#endif /* _WIN32 */

View File

@@ -0,0 +1,31 @@
/**
* WinPR: Windows Portable Runtime
* Runtime ASSERT macros
*
* Copyright 2021 Armin Novak <armin.novak@thincast.com>
* Copyright 2021 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.
*/
#include <winpr/assert.h>
#include <winpr/wlog.h>
#include <winpr/debug.h>
void winpr_int_assert(const char* condstr, const char* file, const char* fkt, size_t line)
{
wLog* _log_cached_ptr = WLog_Get("com.freerdp.winpr.assert");
WLog_Print(_log_cached_ptr, WLOG_FATAL, "%s [%s:%s:%" PRIuz "]", condstr, file, fkt, line);
winpr_log_backtrace_ex(_log_cached_ptr, WLOG_FATAL, 20);
abort();
}

View File

@@ -0,0 +1,50 @@
/**
* WinPR: Windows Portable Runtime
* Buffer Manipulation
*
* Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
*
* 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.
*/
#include <winpr/config.h>
#include <winpr/crt.h>
/* Buffer Manipulation: http://msdn.microsoft.com/en-us/library/b3893xdy/ */
#ifndef _WIN32
#include <string.h>
errno_t memmove_s(void* dest, size_t numberOfElements, const void* src, size_t count)
{
if (count > numberOfElements)
return -1;
memmove(dest, src, count);
return 0;
}
errno_t wmemmove_s(WCHAR* dest, size_t numberOfElements, const WCHAR* src, size_t count)
{
if (count * sizeof(WCHAR) > numberOfElements)
return -1;
memmove(dest, src, count * 2);
return 0;
}
#endif

View File

@@ -0,0 +1,726 @@
/**
* Unicode case mappings
*
* This code is generated by wine's make_unicode script
* which downloads data from unicode.org and produces
* readily usable conversion tables.
*
* After asking permission from Alexandre Julliard in May 2011,
* it was clarified that no copyright was claimed by the wine
* project on the script's generated output.
*/
#define WINPR_TOLOWERW(_wch) \
(_wch + winpr_casemap_lower[winpr_casemap_lower[_wch >> 8] + (_wch & 0xFF)])
#define WINPR_TOUPPERW(_wch) \
(_wch + winpr_casemap_upper[winpr_casemap_upper[_wch >> 8] + (_wch & 0xFF)])
static const WCHAR winpr_casemap_lower[3807] = {
/* index */
0x01bf, 0x02bf, 0x03bf, 0x044f, 0x054f, 0x064f, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100,
0x0100, 0x0100, 0x0100, 0x0100, 0x06af, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100,
0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x07af, 0x08ae, 0x0100, 0x09ab, 0x0100, 0x0100,
0x0a2f, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0b2f, 0x0100, 0x0100, 0x0100,
0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100,
0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100,
0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100,
0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100,
0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100,
0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100,
0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100,
0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100,
0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100,
0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0c22, 0x0d00,
0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100,
0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100,
0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100,
0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100,
0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100,
0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100,
0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100,
0x0100, 0x0100, 0x0100, 0x0ddf,
/* defaults */
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000,
/* 0x0041 .. 0x00ff */
0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
0x0020, 0x0020, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0000, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
0x0020, 0x0020, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
/* 0x0100 .. 0x01ff */
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0xff39, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0000, 0x0001, 0x0000, 0x0001,
0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001,
0x0000, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0xff87, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0000, 0x0000, 0x00d2, 0x0001, 0x0000,
0x0001, 0x0000, 0x00ce, 0x0001, 0x0000, 0x00cd, 0x00cd, 0x0001, 0x0000, 0x0000, 0x004f, 0x00ca,
0x00cb, 0x0001, 0x0000, 0x00cd, 0x00cf, 0x0000, 0x00d3, 0x00d1, 0x0001, 0x0000, 0x0000, 0x0000,
0x00d3, 0x00d5, 0x0000, 0x00d6, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x00da, 0x0001,
0x0000, 0x00da, 0x0000, 0x0000, 0x0001, 0x0000, 0x00da, 0x0001, 0x0000, 0x00d9, 0x00d9, 0x0001,
0x0000, 0x0001, 0x0000, 0x00db, 0x0001, 0x0000, 0x0000, 0x0000, 0x0001, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0002, 0x0001, 0x0000, 0x0002, 0x0001, 0x0000, 0x0002, 0x0001,
0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001,
0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0000, 0x0002, 0x0001, 0x0000, 0x0001, 0x0000, 0xff9f, 0xffc8, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000,
/* 0x0200 .. 0x02ff */
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0xff7e, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x2a2b, 0x0001,
0x0000, 0xff5d, 0x2a28, 0x0000, 0x0000, 0x0001, 0x0000, 0xff3d, 0x0045, 0x0047, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000,
/* 0x0370 .. 0x03ff */
0x0001, 0x0000, 0x0001, 0x0000, 0x0000, 0x0000, 0x0001, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0026, 0x0000,
0x0025, 0x0025, 0x0025, 0x0000, 0x0040, 0x0000, 0x003f, 0x003f, 0x0000, 0x0020, 0x0020, 0x0020,
0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
0x0020, 0x0020, 0x0000, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0008,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0xffc4, 0x0000, 0x0000, 0x0001, 0x0000, 0xfff9, 0x0001, 0x0000, 0x0000, 0xff7e, 0xff7e, 0xff7e,
/* 0x0400 .. 0x04ff */
0x0050, 0x0050, 0x0050, 0x0050, 0x0050, 0x0050, 0x0050, 0x0050, 0x0050, 0x0050, 0x0050, 0x0050,
0x0050, 0x0050, 0x0050, 0x0050, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x000f, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001,
0x0000, 0x0001, 0x0000, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000,
/* 0x0500 .. 0x05ff */
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030,
0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030,
0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030,
0x0030, 0x0030, 0x0030, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000,
/* 0x10a0 .. 0x10ff */
0x1c60, 0x1c60, 0x1c60, 0x1c60, 0x1c60, 0x1c60, 0x1c60, 0x1c60, 0x1c60, 0x1c60, 0x1c60, 0x1c60,
0x1c60, 0x1c60, 0x1c60, 0x1c60, 0x1c60, 0x1c60, 0x1c60, 0x1c60, 0x1c60, 0x1c60, 0x1c60, 0x1c60,
0x1c60, 0x1c60, 0x1c60, 0x1c60, 0x1c60, 0x1c60, 0x1c60, 0x1c60, 0x1c60, 0x1c60, 0x1c60, 0x1c60,
0x1c60, 0x1c60, 0x0000, 0x1c60, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1c60, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
/* 0x1e00 .. 0x1eff */
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0xe241, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000,
/* 0x1f01 .. 0x1fff */
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xfff8, 0xfff8, 0xfff8, 0xfff8, 0xfff8,
0xfff8, 0xfff8, 0xfff8, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xfff8,
0xfff8, 0xfff8, 0xfff8, 0xfff8, 0xfff8, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0xfff8, 0xfff8, 0xfff8, 0xfff8, 0xfff8, 0xfff8, 0xfff8, 0xfff8, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xfff8, 0xfff8, 0xfff8, 0xfff8, 0xfff8,
0xfff8, 0xfff8, 0xfff8, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xfff8,
0xfff8, 0xfff8, 0xfff8, 0xfff8, 0xfff8, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0xfff8, 0x0000, 0xfff8, 0x0000, 0xfff8, 0x0000, 0xfff8, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xfff8, 0xfff8, 0xfff8, 0xfff8, 0xfff8,
0xfff8, 0xfff8, 0xfff8, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0xfff8, 0xfff8, 0xfff8, 0xfff8, 0xfff8, 0xfff8, 0xfff8, 0xfff8, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xfff8, 0xfff8, 0xfff8, 0xfff8, 0xfff8,
0xfff8, 0xfff8, 0xfff8, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xfff8,
0xfff8, 0xfff8, 0xfff8, 0xfff8, 0xfff8, 0xfff8, 0xfff8, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0xfff8, 0xfff8, 0xffb6, 0xffb6, 0xfff7, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xffaa, 0xffaa, 0xffaa, 0xffaa, 0xfff7,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xfff8,
0xfff8, 0xff9c, 0xff9c, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0xfff8, 0xfff8, 0xff90, 0xff90, 0xfff9, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xff80, 0xff80, 0xff82, 0xff82, 0xfff7,
0x0000, 0x0000, 0x0000,
/* 0x2103 .. 0x21ff */
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xe2a3,
0x0000, 0x0000, 0x0000, 0xdf41, 0xdfba, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x001c,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0010, 0x0010, 0x0010,
0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010,
0x0010, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000,
/* 0x247c .. 0x24ff */
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x001a, 0x001a,
0x001a, 0x001a, 0x001a, 0x001a, 0x001a, 0x001a, 0x001a, 0x001a, 0x001a, 0x001a, 0x001a, 0x001a,
0x001a, 0x001a, 0x001a, 0x001a, 0x001a, 0x001a, 0x001a, 0x001a, 0x001a, 0x001a, 0x001a, 0x001a,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
/* 0x2c00 .. 0x2cff */
0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030,
0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030,
0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030,
0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0001, 0x0000, 0xd609, 0xf11a, 0xd619, 0x0000, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001,
0x0000, 0xd5e4, 0xd603, 0xd5e1, 0xd5e2, 0x0000, 0x0001, 0x0000, 0x0000, 0x0001, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xd5c1, 0xd5c1, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0000,
0x0000, 0x0000, 0x0001, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000,
/* 0xa60d .. 0xa6ff */
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001,
0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001,
0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001,
0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001,
0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001,
0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000,
/* 0xa722 .. 0xa7ff */
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0000, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x75fc, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0x0000, 0x5ad8,
0x0000, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000,
0x0001, 0x0000, 0x0001, 0x0000, 0x5abc, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
/* 0xff21 .. 0xffff */
0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
0x0020, 0x0020, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000
};
static const WCHAR winpr_casemap_upper[3994] = {
/* index */
0x019f, 0x029f, 0x039f, 0x045a, 0x0556, 0x0656, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100,
0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100,
0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x06dd, 0x07dc, 0x08dc, 0x0100, 0x09d0, 0x0100, 0x0100,
0x0a55, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0b3f, 0x0c3f, 0x0100, 0x0100,
0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100,
0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100,
0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100,
0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100,
0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100,
0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100,
0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100,
0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100,
0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100,
0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0cfe, 0x0ddb,
0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100,
0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100,
0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100,
0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100,
0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100,
0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100,
0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100,
0x0100, 0x0100, 0x0100, 0x0e9a,
/* defaults */
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000,
/* 0x0061 .. 0x00ff */
0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0,
0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0,
0xffe0, 0xffe0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x02e7, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0,
0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0,
0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0x0000, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0,
0xffe0, 0xffe0, 0x0079,
/* 0x0100 .. 0x01ff */
0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff,
0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff,
0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff,
0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff,
0x0000, 0xff18, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0x0000, 0xffff, 0x0000,
0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000,
0xffff, 0x0000, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff,
0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff,
0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff,
0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff,
0x0000, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0xfed4, 0x00c3, 0x0000, 0x0000, 0xffff,
0x0000, 0xffff, 0x0000, 0x0000, 0xffff, 0x0000, 0x0000, 0x0000, 0xffff, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0xffff, 0x0000, 0x0000, 0x0061, 0x0000, 0x0000, 0x0000, 0xffff, 0x00a3, 0x0000,
0x0000, 0x0000, 0x0082, 0x0000, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0x0000,
0xffff, 0x0000, 0x0000, 0x0000, 0x0000, 0xffff, 0x0000, 0x0000, 0xffff, 0x0000, 0x0000, 0x0000,
0xffff, 0x0000, 0xffff, 0x0000, 0x0000, 0xffff, 0x0000, 0x0000, 0x0000, 0xffff, 0x0000, 0x0038,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xffff, 0xfffe, 0x0000, 0xffff, 0xfffe, 0x0000, 0xffff,
0xfffe, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000,
0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0xffb1, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff,
0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff,
0x0000, 0x0000, 0xffff, 0xfffe, 0x0000, 0xffff, 0x0000, 0x0000, 0x0000, 0xffff, 0x0000, 0xffff,
0x0000, 0xffff, 0x0000, 0xffff,
/* 0x0200 .. 0x02ff */
0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff,
0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff,
0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0x0000, 0x0000, 0xffff,
0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff,
0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0xffff, 0x0000, 0x0000, 0x2a3f, 0x2a3f, 0x0000, 0xffff, 0x0000, 0x0000, 0x0000, 0x0000, 0xffff,
0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x2a1f, 0x2a1c, 0x2a1e, 0xff2e,
0xff32, 0x0000, 0xff33, 0xff33, 0x0000, 0xff36, 0x0000, 0xff35, 0x0000, 0x0000, 0x0000, 0x0000,
0xff33, 0x0000, 0x0000, 0xff31, 0x0000, 0xa528, 0xa544, 0x0000, 0xff2f, 0xff2d, 0x0000, 0x29f7,
0x0000, 0x0000, 0x0000, 0xff2d, 0x0000, 0x29fd, 0xff2b, 0x0000, 0x0000, 0xff2a, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x29e7, 0x0000, 0x0000, 0xff26, 0x0000, 0x0000, 0xff26,
0x0000, 0x0000, 0x0000, 0x0000, 0xff26, 0xffbb, 0xff27, 0xff27, 0xffb9, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0xff25, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000,
/* 0x0345 .. 0x03ff */
0x0054, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000,
0x0000, 0x0000, 0xffff, 0x0000, 0x0000, 0x0000, 0x0082, 0x0082, 0x0082, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xffda, 0xffdb, 0xffdb, 0xffdb, 0x0000,
0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0,
0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe1, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0,
0xffe0, 0xffe0, 0xffe0, 0xffc0, 0xffc1, 0xffc1, 0x0000, 0xffc2, 0xffc7, 0x0000, 0x0000, 0x0000,
0xffd1, 0xffca, 0xfff8, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000,
0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000,
0xffff, 0x0000, 0xffff, 0xffaa, 0xffb0, 0x0007, 0x0000, 0x0000, 0xffa0, 0x0000, 0x0000, 0xffff,
0x0000, 0x0000, 0xffff, 0x0000, 0x0000, 0x0000, 0x0000,
/* 0x0404 .. 0x04ff */
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xffe0, 0xffe0, 0xffe0, 0xffe0,
0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0,
0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0,
0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffb0, 0xffb0, 0xffb0, 0xffb0, 0xffb0, 0xffb0, 0xffb0, 0xffb0,
0xffb0, 0xffb0, 0xffb0, 0xffb0, 0xffb0, 0xffb0, 0xffb0, 0xffb0, 0x0000, 0xffff, 0x0000, 0xffff,
0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff,
0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff,
0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff,
0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff,
0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff,
0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff,
0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0x0000, 0xffff, 0x0000,
0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0xfff1,
0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff,
0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff,
0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff,
0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff,
/* 0x0500 .. 0x05ff */
0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff,
0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff,
0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff,
0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0,
0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0,
0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0,
0xffd0, 0xffd0, 0xffd0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000,
/* 0x1d79 .. 0x1dff */
0x8a04, 0x0000, 0x0000, 0x0000, 0x0ee6, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000,
/* 0x1e01 .. 0x1eff */
0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000,
0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000,
0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000,
0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000,
0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000,
0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000,
0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000,
0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000,
0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000,
0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000,
0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000,
0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000,
0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xffc5, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000,
0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000,
0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000,
0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000,
0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000,
0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000,
0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000,
0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000,
0xffff, 0x0000, 0xffff,
/* 0x1f00 .. 0x1fff */
0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0008, 0x0008, 0x0008, 0x0008,
0x0008, 0x0008, 0x0008, 0x0008, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0008, 0x0000, 0x0008,
0x0000, 0x0008, 0x0000, 0x0008, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x004a, 0x004a, 0x0056, 0x0056, 0x0056, 0x0056, 0x0064, 0x0064,
0x0080, 0x0080, 0x0070, 0x0070, 0x007e, 0x007e, 0x0000, 0x0000, 0x0008, 0x0008, 0x0008, 0x0008,
0x0008, 0x0008, 0x0008, 0x0008, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0008, 0x0008, 0x0000, 0x0009,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xe3db, 0x0000,
0x0000, 0x0000, 0x0000, 0x0009, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0008, 0x0008, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0008, 0x0008, 0x0000, 0x0000,
0x0000, 0x0007, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0009, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000,
/* 0x210c .. 0x21ff */
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xffe4, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0xfff0, 0xfff0, 0xfff0, 0xfff0, 0xfff0, 0xfff0, 0xfff0, 0xfff0,
0xfff0, 0xfff0, 0xfff0, 0xfff0, 0xfff0, 0xfff0, 0xfff0, 0xfff0, 0x0000, 0x0000, 0x0000, 0x0000,
0xffff, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000,
/* 0x247b .. 0x24ff */
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0xffe6, 0xffe6, 0xffe6, 0xffe6, 0xffe6, 0xffe6, 0xffe6, 0xffe6, 0xffe6, 0xffe6, 0xffe6,
0xffe6, 0xffe6, 0xffe6, 0xffe6, 0xffe6, 0xffe6, 0xffe6, 0xffe6, 0xffe6, 0xffe6, 0xffe6, 0xffe6,
0xffe6, 0xffe6, 0xffe6, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000,
/* 0x2c16 .. 0x2cff */
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0,
0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0,
0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0,
0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0,
0xffd0, 0x0000, 0x0000, 0xffff, 0x0000, 0x0000, 0x0000, 0xd5d5, 0xd5d8, 0x0000, 0xffff, 0x0000,
0xffff, 0x0000, 0xffff, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xffff, 0x0000, 0x0000,
0xffff, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xffff,
0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff,
0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff,
0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff,
0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff,
0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff,
0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff,
0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff,
0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff,
0x0000, 0xffff, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xffff, 0x0000,
0xffff, 0x0000, 0x0000, 0x0000, 0x0000, 0xffff, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
/* 0x2d00 .. 0x2dff */
0xe3a0, 0xe3a0, 0xe3a0, 0xe3a0, 0xe3a0, 0xe3a0, 0xe3a0, 0xe3a0, 0xe3a0, 0xe3a0, 0xe3a0, 0xe3a0,
0xe3a0, 0xe3a0, 0xe3a0, 0xe3a0, 0xe3a0, 0xe3a0, 0xe3a0, 0xe3a0, 0xe3a0, 0xe3a0, 0xe3a0, 0xe3a0,
0xe3a0, 0xe3a0, 0xe3a0, 0xe3a0, 0xe3a0, 0xe3a0, 0xe3a0, 0xe3a0, 0xe3a0, 0xe3a0, 0xe3a0, 0xe3a0,
0xe3a0, 0xe3a0, 0x0000, 0xe3a0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xe3a0, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000,
/* 0xa641 .. 0xa6ff */
0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000,
0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000,
0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000,
0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000,
0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000,
0xffff, 0x0000, 0xffff, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
/* 0xa723 .. 0xa7ff */
0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000,
0xffff, 0x0000, 0x0000, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000,
0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000,
0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000,
0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000,
0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000,
0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000,
0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0x0000, 0x0000, 0x0000, 0xffff, 0x0000, 0x0000,
0x0000, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000,
0xffff, 0x0000, 0xffff, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
/* 0xff41 .. 0xffff */
0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0,
0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0,
0xffe0, 0xffe0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000
};

View File

@@ -0,0 +1,44 @@
/**
* WinPR: Windows Portable Runtime
* Data Conversion
*
* Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
*
* 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.
*/
#include <winpr/config.h>
#include <winpr/crt.h>
#include <winpr/string.h>
/* Data Conversion: http://msdn.microsoft.com/en-us/library/0heszx3w/ */
#ifndef _WIN32
errno_t _itoa_s(int value, char* buffer, size_t sizeInCharacters, WINPR_ATTR_UNUSED int radix)
{
int length = sprintf_s(nullptr, 0, "%d", value);
if (length < 0)
return -1;
if (sizeInCharacters < (size_t)length)
return -1;
(void)sprintf_s(buffer, WINPR_ASSERTING_INT_CAST(size_t, length + 1), "%d", value);
return 0;
}
#endif

View File

@@ -0,0 +1,42 @@
/**
* WinPR: Windows Portable Runtime
* Memory Allocation
*
* Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
*
* 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.
*/
#include <winpr/config.h>
#include <winpr/crt.h>
/* Memory Allocation: http://msdn.microsoft.com/en-us/library/hk1k7x6x.aspx */
/* Memory Management Functions: http://msdn.microsoft.com/en-us/library/windows/desktop/aa366781/ */
#ifndef _WIN32
PVOID SecureZeroMemory(PVOID ptr, size_t cnt)
{
volatile BYTE* p = ptr;
while (cnt--)
{
*p = 0;
p++;
}
return ptr;
}
#endif

View File

@@ -0,0 +1,843 @@
/**
* WinPR: Windows Portable Runtime
* String Manipulation (CRT)
*
* Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
*
* 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.
*/
#include <winpr/config.h>
#include <winpr/assert.h>
#include <errno.h>
#include <stdio.h>
#include <ctype.h>
#include <wctype.h>
#include <wchar.h>
#include <winpr/crt.h>
#include <winpr/endian.h>
#if defined(WITH_URIPARSER)
#include <uriparser/Uri.h>
#endif
/* String Manipulation (CRT): http://msdn.microsoft.com/en-us/library/f0151s4x.aspx */
#include "../log.h"
#define TAG WINPR_TAG("crt")
#if defined(WITH_URIPARSER)
char* winpr_str_url_decode(const char* str, size_t len)
{
char* dst = strndup(str, len);
if (!dst)
return nullptr;
if (!uriUnescapeInPlaceExA(dst, URI_FALSE, URI_BR_DONT_TOUCH))
{
free(dst);
return nullptr;
}
return dst;
}
char* winpr_str_url_encode(const char* str, size_t len)
{
char* dst = calloc(len + 1, sizeof(char) * 3);
if (!dst)
return nullptr;
if (!uriEscapeA(str, dst, URI_FALSE, URI_FALSE))
{
free(dst);
return nullptr;
}
return dst;
}
#else
static const char rfc3986[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2d, 0x2e, 0x00,
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x5f,
0x00, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x00, 0x00, 0x00, 0x7e, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
static char hex2bin(char what)
{
if (what >= 'a')
what -= 'a' - 'A';
if (what >= 'A')
what -= ('A' - 10);
else
what -= '0';
return what;
}
static char unescape(const char* what, size_t* px)
{
if ((*what == '%') && (isxdigit(what[1]) && isxdigit(what[2])))
{
*px += 2;
return 16 * hex2bin(what[1]) + hex2bin(what[2]);
}
return *what;
}
char* winpr_str_url_decode(const char* str, size_t len)
{
char* dst = calloc(len + 1, sizeof(char));
if (!dst)
return nullptr;
size_t pos = 0;
for (size_t x = 0; x < strnlen(str, len); x++)
{
const char* cur = &str[x];
dst[pos++] = unescape(cur, &x);
}
return dst;
}
static char* escape(char* dst, char what)
{
if (rfc3986[what & 0xff])
{
*dst = what;
return dst + 1;
}
sprintf(dst, "%%%02" PRIX8, (BYTE)(what & 0xff));
return dst + 3;
}
char* winpr_str_url_encode(const char* str, size_t len)
{
char* dst = calloc(len + 1, sizeof(char) * 3);
if (!dst)
return nullptr;
char* ptr = dst;
for (size_t x = 0; x < strnlen(str, len); x++)
{
const char cur = str[x];
ptr = escape(ptr, cur);
}
return dst;
}
#endif
BOOL winpr_str_append(const char* what, char* buffer, size_t size, const char* separator)
{
const size_t used = strnlen(buffer, size);
const size_t add = strnlen(what, size);
const size_t sep_len = separator ? strnlen(separator, size) : 0;
const size_t sep = (used > 0) ? sep_len : 0;
if (used + add + sep >= size)
return FALSE;
if ((used > 0) && (sep_len > 0))
strncat(buffer, separator, sep_len);
strncat(buffer, what, add);
return TRUE;
}
WINPR_ATTR_FORMAT_ARG(3, 4)
int winpr_asprintf(char** s, size_t* slen, WINPR_FORMAT_ARG const char* templ, ...)
{
va_list ap = WINPR_C_ARRAY_INIT;
va_start(ap, templ);
int rc = winpr_vasprintf(s, slen, templ, ap);
va_end(ap);
return rc;
}
WINPR_ATTR_FORMAT_ARG(3, 0)
int winpr_vasprintf(char** s, size_t* slen, WINPR_FORMAT_ARG const char* templ, va_list oap)
{
va_list ap = WINPR_C_ARRAY_INIT;
*s = nullptr;
*slen = 0;
va_copy(ap, oap);
const int length = vsnprintf(nullptr, 0, templ, ap);
va_end(ap);
if (length < 0)
return length;
char* str = calloc((size_t)length + 1UL, sizeof(char));
if (!str)
return -1;
va_copy(ap, oap);
const int plen = vsnprintf(str, (size_t)length + 1UL, templ, ap);
va_end(ap);
if (length != plen)
{
free(str);
return -1;
}
*s = str;
*slen = (size_t)length;
return length;
}
#ifndef _WIN32
char* _strdup(const char* strSource)
{
if (strSource == nullptr)
return nullptr;
char* strDestination = strdup(strSource);
if (strDestination == nullptr)
WLog_ERR(TAG, "strdup");
return strDestination;
}
WCHAR* _wcsdup(const WCHAR* strSource)
{
if (!strSource)
return nullptr;
size_t len = _wcslen(strSource);
WCHAR* strDestination = calloc(len + 1, sizeof(WCHAR));
if (strDestination != nullptr)
memcpy(strDestination, strSource, len * sizeof(WCHAR));
if (strDestination == nullptr)
WLog_ERR(TAG, "wcsdup");
return strDestination;
}
WCHAR* _wcsncat(WCHAR* dst, const WCHAR* src, size_t sz)
{
WINPR_ASSERT(dst);
WINPR_ASSERT(src || (sz == 0));
const size_t dlen = _wcslen(dst);
const size_t slen = _wcsnlen(src, sz);
for (size_t x = 0; x < slen; x++)
dst[dlen + x] = src[x];
dst[dlen + slen] = '\0';
return dst;
}
int _stricmp(const char* string1, const char* string2)
{
return strcasecmp(string1, string2);
}
int _strnicmp(const char* string1, const char* string2, size_t count)
{
return strncasecmp(string1, string2, count);
}
/* _wcscmp -> wcscmp */
int _wcscmp(const WCHAR* string1, const WCHAR* string2)
{
WINPR_ASSERT(string1);
WINPR_ASSERT(string2);
while (TRUE)
{
const WCHAR w1 = *string1++;
const WCHAR w2 = *string2++;
if (w1 != w2)
return (int)w1 - w2;
else if ((w1 == '\0') || (w2 == '\0'))
return (int)w1 - w2;
}
}
int _wcsncmp(const WCHAR* string1, const WCHAR* string2, size_t count)
{
WINPR_ASSERT(string1);
WINPR_ASSERT(string2);
for (size_t x = 0; x < count; x++)
{
const WCHAR a = string1[x];
const WCHAR b = string2[x];
if (a != b)
return (int)a - b;
else if ((a == '\0') || (b == '\0'))
return (int)a - b;
}
return 0;
}
/* _wcslen -> wcslen */
size_t _wcslen(const WCHAR* str)
{
const WCHAR* p = str;
WINPR_ASSERT(p);
while (*p)
p++;
return (size_t)(p - str);
}
/* _wcsnlen -> wcsnlen */
size_t _wcsnlen(const WCHAR* str, size_t max)
{
WINPR_ASSERT(str);
size_t x = 0;
for (; x < max; x++)
{
if (str[x] == 0)
return x;
}
return x;
}
/* _wcsstr -> wcsstr */
WCHAR* _wcsstr(const WCHAR* str, const WCHAR* strSearch)
{
WINPR_ASSERT(str);
WINPR_ASSERT(strSearch);
if (strSearch[0] == '\0')
return WINPR_CAST_CONST_PTR_AWAY(str, WCHAR*);
const size_t searchLen = _wcslen(strSearch);
while (*str)
{
if (_wcsncmp(str, strSearch, searchLen) == 0)
return WINPR_CAST_CONST_PTR_AWAY(str, WCHAR*);
str++;
}
return nullptr;
}
/* _wcschr -> wcschr */
WCHAR* _wcschr(const WCHAR* str, WCHAR c)
{
union
{
const WCHAR* cc;
WCHAR* c;
} cnv;
const WCHAR* p = str;
while (*p && (*p != c))
p++;
cnv.cc = (*p == c) ? p : nullptr;
return cnv.c;
}
/* _wcsrchr -> wcsrchr */
WCHAR* _wcsrchr(const WCHAR* str, WCHAR c)
{
union
{
const WCHAR* cc;
WCHAR* c;
} cnv;
const WCHAR* p = nullptr;
if (!str)
return nullptr;
for (; *str != '\0'; str++)
{
const WCHAR ch = *str;
if (ch == c)
p = str;
}
cnv.cc = p;
return cnv.c;
}
char* strtok_s(char* strToken, const char* strDelimit, char** context)
{
return strtok_r(strToken, strDelimit, context);
}
WCHAR* wcstok_s(WCHAR* strToken, const WCHAR* strDelimit, WCHAR** context)
{
WCHAR* nextToken = nullptr;
WCHAR value = 0;
if (!strToken)
strToken = *context;
value = *strToken;
while (*strToken && _wcschr(strDelimit, value))
{
strToken++;
value = *strToken;
}
if (!*strToken)
return nullptr;
nextToken = strToken++;
value = *strToken;
while (*strToken && !(_wcschr(strDelimit, value)))
{
strToken++;
value = *strToken;
}
if (*strToken)
*strToken++ = 0;
*context = strToken;
return nextToken;
}
#endif
#if !defined(_WIN32) || defined(_UWP)
/* Windows API Sets - api-ms-win-core-string-l2-1-0.dll
* http://msdn.microsoft.com/en-us/library/hh802935/
*/
#include "casing.h"
LPSTR CharUpperA(LPSTR lpsz)
{
size_t length = 0;
if (!lpsz)
return nullptr;
length = strlen(lpsz);
if (length < 1)
return (LPSTR) nullptr;
if (length == 1)
{
char c = *lpsz;
if ((c >= 'a') && (c <= 'z'))
c = (char)(c - 'a' + 'A');
*lpsz = c;
return lpsz;
}
for (size_t i = 0; i < length; i++)
{
if ((lpsz[i] >= 'a') && (lpsz[i] <= 'z'))
lpsz[i] = (char)(lpsz[i] - 'a' + 'A');
}
return lpsz;
}
LPWSTR CharUpperW(LPWSTR lpsz)
{
size_t length = 0;
if (!lpsz)
return nullptr;
length = _wcslen(lpsz);
if (length < 1)
return (LPWSTR) nullptr;
if (length == 1)
{
WCHAR c = *lpsz;
if ((c >= L'a') && (c <= L'z'))
c = c - L'a' + L'A';
*lpsz = c;
return lpsz;
}
for (size_t i = 0; i < length; i++)
{
if ((lpsz[i] >= L'a') && (lpsz[i] <= L'z'))
lpsz[i] = lpsz[i] - L'a' + L'A';
}
return lpsz;
}
DWORD CharUpperBuffA(LPSTR lpsz, DWORD cchLength)
{
if (cchLength < 1)
return 0;
for (DWORD i = 0; i < cchLength; i++)
{
if ((lpsz[i] >= 'a') && (lpsz[i] <= 'z'))
lpsz[i] = (char)(lpsz[i] - 'a' + 'A');
}
return cchLength;
}
DWORD CharUpperBuffW(LPWSTR lpsz, DWORD cchLength)
{
for (DWORD i = 0; i < cchLength; i++)
{
WCHAR value = winpr_Data_Get_UINT16(&lpsz[i]);
value = WINPR_TOUPPERW(value);
winpr_Data_Write_UINT16(&lpsz[i], value);
}
return cchLength;
}
LPSTR CharLowerA(LPSTR lpsz)
{
size_t length = 0;
if (!lpsz)
return (LPSTR) nullptr;
length = strlen(lpsz);
if (length < 1)
return (LPSTR) nullptr;
if (length == 1)
{
char c = *lpsz;
if ((c >= 'A') && (c <= 'Z'))
c = (char)(c - 'A' + 'a');
*lpsz = c;
return lpsz;
}
for (size_t i = 0; i < length; i++)
{
if ((lpsz[i] >= 'A') && (lpsz[i] <= 'Z'))
lpsz[i] = (char)(lpsz[i] - 'A' + 'a');
}
return lpsz;
}
LPWSTR CharLowerW(LPWSTR lpsz)
{
const size_t len = _wcsnlen(lpsz, UINT32_MAX + 1);
if (len > UINT32_MAX)
return nullptr;
CharLowerBuffW(lpsz, (UINT32)len);
return lpsz;
}
DWORD CharLowerBuffA(LPSTR lpsz, DWORD cchLength)
{
if (cchLength < 1)
return 0;
for (DWORD i = 0; i < cchLength; i++)
{
if ((lpsz[i] >= 'A') && (lpsz[i] <= 'Z'))
lpsz[i] = (char)(lpsz[i] - 'A' + 'a');
}
return cchLength;
}
DWORD CharLowerBuffW(LPWSTR lpsz, DWORD cchLength)
{
for (DWORD i = 0; i < cchLength; i++)
{
WCHAR value = winpr_Data_Get_UINT16(&lpsz[i]);
value = WINPR_TOLOWERW(value);
winpr_Data_Write_UINT16(&lpsz[i], value);
}
return cchLength;
}
BOOL IsCharAlphaA(CHAR ch)
{
if (((ch >= 'a') && (ch <= 'z')) || ((ch >= 'A') && (ch <= 'Z')))
return 1;
else
return 0;
}
BOOL IsCharAlphaW(WCHAR ch)
{
if (((ch >= L'a') && (ch <= L'z')) || ((ch >= L'A') && (ch <= L'Z')))
return 1;
else
return 0;
}
BOOL IsCharAlphaNumericA(CHAR ch)
{
if (((ch >= 'a') && (ch <= 'z')) || ((ch >= 'A') && (ch <= 'Z')) ||
((ch >= '0') && (ch <= '9')))
return 1;
else
return 0;
}
BOOL IsCharAlphaNumericW(WCHAR ch)
{
if (((ch >= L'a') && (ch <= L'z')) || ((ch >= L'A') && (ch <= L'Z')) ||
((ch >= L'0') && (ch <= L'9')))
return 1;
else
return 0;
}
BOOL IsCharUpperA(CHAR ch)
{
if ((ch >= 'A') && (ch <= 'Z'))
return 1;
else
return 0;
}
BOOL IsCharUpperW(WCHAR ch)
{
if ((ch >= L'A') && (ch <= L'Z'))
return 1;
else
return 0;
}
BOOL IsCharLowerA(CHAR ch)
{
if ((ch >= 'a') && (ch <= 'z'))
return 1;
else
return 0;
}
BOOL IsCharLowerW(WCHAR ch)
{
if ((ch >= L'a') && (ch <= L'z'))
return 1;
else
return 0;
}
#endif
size_t ConvertLineEndingToLF(char* str, size_t size)
{
size_t skip = 0;
WINPR_ASSERT(str || (size == 0));
for (size_t x = 0; x < size; x++)
{
char c = str[x];
switch (c)
{
case '\r':
str[x - skip] = '\n';
if ((x + 1 < size) && (str[x + 1] == '\n'))
skip++;
break;
default:
str[x - skip] = c;
break;
}
}
return size - skip;
}
char* ConvertLineEndingToCRLF(const char* str, size_t* size)
{
WINPR_ASSERT(size);
const size_t s = *size;
WINPR_ASSERT(str || (s == 0));
*size = 0;
if (s == 0)
return nullptr;
size_t linebreaks = 0;
for (size_t x = 0; x < s - 1; x++)
{
char c = str[x];
switch (c)
{
case '\r':
case '\n':
linebreaks++;
break;
default:
break;
}
}
char* cnv = calloc(s + linebreaks * 2ull + 1ull, sizeof(char));
if (!cnv)
return nullptr;
size_t pos = 0;
for (size_t x = 0; x < s; x++)
{
const char c = str[x];
switch (c)
{
case '\r':
cnv[pos++] = '\r';
cnv[pos++] = '\n';
break;
case '\n':
/* Do not duplicate existing \r\n sequences */
if ((x > 0) && (str[x - 1] != '\r'))
{
cnv[pos++] = '\r';
cnv[pos++] = '\n';
}
break;
default:
cnv[pos++] = c;
break;
}
}
*size = pos;
return cnv;
}
char* StrSep(char** stringp, const char* delim)
{
char* start = *stringp;
char* p = nullptr;
p = (start != nullptr) ? strpbrk(start, delim) : nullptr;
if (!p)
*stringp = nullptr;
else
{
*p = '\0';
*stringp = p + 1;
}
return start;
}
INT64 GetLine(char** lineptr, size_t* size, FILE* stream)
{
#if defined(_WIN32)
char c;
char* n;
size_t step = 32;
size_t used = 0;
if (!lineptr || !size)
{
errno = EINVAL;
return -1;
}
do
{
if (used + 2 >= *size)
{
*size += step;
n = realloc(*lineptr, *size);
if (!n)
{
return -1;
}
*lineptr = n;
}
c = fgetc(stream);
if (c != EOF)
(*lineptr)[used++] = c;
} while ((c != '\n') && (c != '\r') && (c != EOF));
(*lineptr)[used] = '\0';
return used;
#elif !defined(ANDROID) && !defined(IOS)
return getline(lineptr, size, stream);
#else
return -1;
#endif
}
#if !defined(WINPR_HAVE_STRNDUP)
char* strndup(const char* src, size_t n)
{
char* dst = calloc(n + 1, sizeof(char));
if (dst)
strncpy(dst, src, n);
return dst;
}
#endif
const WCHAR* InitializeConstWCharFromUtf8(const char* str, WCHAR* buffer, size_t len)
{
WINPR_ASSERT(str);
WINPR_ASSERT(buffer || (len == 0));
(void)ConvertUtf8ToWChar(str, buffer, len);
return buffer;
}
WCHAR* wcsndup(const WCHAR* s, size_t n)
{
if (!s)
return nullptr;
WCHAR* copy = calloc(n + 1, sizeof(WCHAR));
if (!copy)
return nullptr;
memcpy(copy, s, n * sizeof(WCHAR));
return copy;
}

View File

@@ -0,0 +1,23 @@
set(MODULE_NAME "TestCrt")
set(MODULE_PREFIX "TEST_CRT")
disable_warnings_for_directory(${CMAKE_CURRENT_BINARY_DIR})
set(${MODULE_PREFIX}_DRIVER ${MODULE_NAME}.c)
set(${MODULE_PREFIX}_TESTS TestTypes.c TestFormatSpecifiers.c TestAlignment.c TestString.c TestUnicodeConversion.c)
create_test_sourcelist(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_DRIVER} ${${MODULE_PREFIX}_TESTS})
add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS})
target_link_libraries(${MODULE_NAME} winpr)
set_target_properties(${MODULE_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${TESTING_OUTPUT_DIRECTORY}")
foreach(test ${${MODULE_PREFIX}_TESTS})
get_filename_component(TestName ${test} NAME_WE)
add_test(${TestName} ${TESTING_OUTPUT_DIRECTORY}/${MODULE_NAME} ${TestName})
endforeach()
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "WinPR/Test")

View File

@@ -0,0 +1,87 @@
#include <stdio.h>
#include <winpr/crt.h>
#include <winpr/windows.h>
int TestAlignment(int argc, char* argv[])
{
void* ptr = nullptr;
size_t alignment = 0;
size_t offset = 0;
WINPR_UNUSED(argc);
WINPR_UNUSED(argv);
/* Alignment should be 2^N where N is a positive integer */
alignment = 16;
offset = 8;
/* _aligned_malloc */
ptr = winpr_aligned_malloc(100, alignment);
if (ptr == nullptr)
{
printf("Error allocating aligned memory.\n");
return -1;
}
if (((size_t)ptr % alignment) != 0)
{
printf("This pointer, %p, is not aligned on %" PRIuz "\n", ptr, alignment);
return -1;
}
/* _aligned_realloc */
ptr = winpr_aligned_realloc(ptr, 200, alignment);
if (((size_t)ptr % alignment) != 0)
{
printf("This pointer, %p, is not aligned on %" PRIuz "\n", ptr, alignment);
return -1;
}
winpr_aligned_free(ptr);
/* _aligned_offset_malloc */
ptr = winpr_aligned_offset_malloc(200, alignment, offset);
if (ptr == nullptr)
{
printf("Error reallocating aligned offset memory.");
return -1;
}
if (((((size_t)ptr) + offset) % alignment) != 0)
{
printf("This pointer, %p, does not satisfy offset %" PRIuz " and alignment %" PRIuz "\n",
ptr, offset, alignment);
return -1;
}
/* _aligned_offset_realloc */
ptr = winpr_aligned_offset_realloc(ptr, 200, alignment, offset);
if (ptr == nullptr)
{
printf("Error reallocating aligned offset memory.");
return -1;
}
if (((((size_t)ptr) + offset) % alignment) != 0)
{
printf("This pointer, %p, does not satisfy offset %" PRIuz " and alignment %" PRIuz "\n",
ptr, offset, alignment);
return -1;
}
/* _aligned_free works for both _aligned_malloc and _aligned_offset_malloc. free() should not be
* used. */
winpr_aligned_free(ptr);
return 0;
}

View File

@@ -0,0 +1,169 @@
#include <stdio.h>
#include <winpr/wtypes.h>
#include <winpr/string.h>
int TestFormatSpecifiers(int argc, char* argv[])
{
unsigned errors = 0;
char fmt[4096];
WINPR_UNUSED(argc);
WINPR_UNUSED(argv);
/* size_t */
{
size_t arg = 0xabcd;
const char* chk = "uz:43981 oz:125715 xz:abcd Xz:ABCD";
(void)sprintf_s(fmt, sizeof(fmt), "uz:%" PRIuz " oz:%" PRIoz " xz:%" PRIxz " Xz:%" PRIXz "",
arg, arg, arg, arg);
if (strcmp(fmt, chk) != 0)
{
(void)fprintf(stderr, "%s failed size_t test: got [%s] instead of [%s]\n", __func__,
fmt, chk);
errors++;
}
}
/* INT8 */
{
INT8 arg = -16;
const char* chk = "d8:-16 x8:f0 X8:F0";
(void)sprintf_s(fmt, sizeof(fmt), "d8:%" PRId8 " x8:%" PRIx8 " X8:%" PRIX8 "", arg,
(UINT8)arg, (UINT8)arg);
if (strcmp(fmt, chk) != 0)
{
(void)fprintf(stderr, "%s failed INT8 test: got [%s] instead of [%s]\n", __func__, fmt,
chk);
errors++;
}
}
/* UINT8 */
{
UINT8 arg = 0xFE;
const char* chk = "u8:254 o8:376 x8:fe X8:FE";
(void)sprintf_s(fmt, sizeof(fmt), "u8:%" PRIu8 " o8:%" PRIo8 " x8:%" PRIx8 " X8:%" PRIX8 "",
arg, arg, arg, arg);
if (strcmp(fmt, chk) != 0)
{
(void)fprintf(stderr, "%s failed UINT8 test: got [%s] instead of [%s]\n", __func__, fmt,
chk);
errors++;
}
}
/* INT16 */
{
INT16 arg = -16;
const char* chk = "d16:-16 x16:fff0 X16:FFF0";
(void)sprintf_s(fmt, sizeof(fmt), "d16:%" PRId16 " x16:%" PRIx16 " X16:%" PRIX16 "", arg,
(UINT16)arg, (UINT16)arg);
if (strcmp(fmt, chk) != 0)
{
(void)fprintf(stderr, "%s failed INT16 test: got [%s] instead of [%s]\n", __func__, fmt,
chk);
errors++;
}
}
/* UINT16 */
{
UINT16 arg = 0xFFFE;
const char* chk = "u16:65534 o16:177776 x16:fffe X16:FFFE";
(void)sprintf_s(fmt, sizeof(fmt),
"u16:%" PRIu16 " o16:%" PRIo16 " x16:%" PRIx16 " X16:%" PRIX16 "", arg, arg,
arg, arg);
if (strcmp(fmt, chk) != 0)
{
(void)fprintf(stderr, "%s failed UINT16 test: got [%s] instead of [%s]\n", __func__,
fmt, chk);
errors++;
}
}
/* INT32 */
{
INT32 arg = -16;
const char* chk = "d32:-16 x32:fffffff0 X32:FFFFFFF0";
(void)sprintf_s(fmt, sizeof(fmt), "d32:%" PRId32 " x32:%" PRIx32 " X32:%" PRIX32 "", arg,
(UINT32)arg, (UINT32)arg);
if (strcmp(fmt, chk) != 0)
{
(void)fprintf(stderr, "%s failed INT32 test: got [%s] instead of [%s]\n", __func__, fmt,
chk);
errors++;
}
}
/* UINT32 */
{
UINT32 arg = 0xFFFFFFFE;
const char* chk = "u32:4294967294 o32:37777777776 x32:fffffffe X32:FFFFFFFE";
(void)sprintf_s(fmt, sizeof(fmt),
"u32:%" PRIu32 " o32:%" PRIo32 " x32:%" PRIx32 " X32:%" PRIX32 "", arg, arg,
arg, arg);
if (strcmp(fmt, chk) != 0)
{
(void)fprintf(stderr, "%s failed UINT16 test: got [%s] instead of [%s]\n", __func__,
fmt, chk);
errors++;
}
}
/* INT64 */
{
INT64 arg = -16;
const char* chk = "d64:-16 x64:fffffffffffffff0 X64:FFFFFFFFFFFFFFF0";
(void)sprintf_s(fmt, sizeof(fmt), "d64:%" PRId64 " x64:%" PRIx64 " X64:%" PRIX64 "", arg,
(UINT64)arg, (UINT64)arg);
if (strcmp(fmt, chk) != 0)
{
(void)fprintf(stderr, "%s failed INT64 test: got [%s] instead of [%s]\n", __func__, fmt,
chk);
errors++;
}
}
/* UINT64 */
{
UINT64 arg = 0xFFFFFFFFFFFFFFFE;
const char* chk = "u64:18446744073709551614 o64:1777777777777777777776 "
"x64:fffffffffffffffe X64:FFFFFFFFFFFFFFFE";
(void)sprintf_s(fmt, sizeof(fmt),
"u64:%" PRIu64 " o64:%" PRIo64 " x64:%016" PRIx64 " X64:%016" PRIX64 "",
arg, arg, arg, arg);
if (strcmp(fmt, chk) != 0)
{
(void)fprintf(stderr, "%s failed UINT64 test: got [%s] instead of [%s]\n", __func__,
fmt, chk);
errors++;
}
}
if (errors)
{
(void)fprintf(stderr, "%s produced %u errors\n", __func__, errors);
return -1;
}
return 0;
}

View File

@@ -0,0 +1,222 @@
#include <stdio.h>
#include <winpr/crt.h>
#include <winpr/string.h>
#include <winpr/windows.h>
static const CHAR testStringA[] = { 'T', 'h', 'e', ' ', 'q', 'u', 'i', 'c', 'k', ' ', 'b',
'r', 'o', 'w', 'n', ' ', 'f', 'o', 'x', ' ', 'j', 'u',
'm', 'p', 's', ' ', 'o', 'v', 'e', 'r', ' ', 't', 'h',
'e', ' ', 'l', 'a', 'z', 'y', ' ', 'd', 'o', 'g', '\0' };
#define testStringA_Length ((sizeof(testStringA) / sizeof(CHAR)) - 1)
static const CHAR testToken1A[] = { 'q', 'u', 'i', 'c', 'k', '\0' };
static const CHAR testToken2A[] = { 'b', 'r', 'o', 'w', 'n', '\0' };
static const CHAR testToken3A[] = { 'f', 'o', 'x', '\0' };
#define testToken1A_Length ((sizeof(testToken1A) / sizeof(CHAR)) - 1)
#define testToken2A_Length ((sizeof(testToken2A) / sizeof(CHAR)) - 1)
#define testToken3A_Length ((sizeof(testToken3A) / sizeof(CHAR)) - 1)
static const CHAR testTokensA[] = { 'q', 'u', 'i', 'c', 'k', '\r', '\n', 'b', 'r', 'o',
'w', 'n', '\r', '\n', 'f', 'o', 'x', '\r', '\n', '\0' };
#define testTokensA_Length ((sizeof(testTokensA) / sizeof(CHAR)) - 1)
static const CHAR testDelimiterA[] = { '\r', '\n', '\0' };
#define testDelimiterA_Length ((sizeof(testDelimiter) / sizeof(CHAR)) - 1)
struct url_test_pair
{
const char* what;
const char* escaped;
};
static const struct url_test_pair url_tests[] = {
{ "xxx%bar ga<ka>ee#%%#%{h}g{f{e%d|c\\b^a~p[q]r`s;t/u?v:w@x=y&z$xxx",
"xxx%25bar%20ga%3Cka%3Eee%23%25%25%23%25%7Bh%7Dg%7Bf%7Be%25d%7Cc%5Cb%5Ea~p%5Bq%5Dr%60s%3Bt%"
"2Fu%3Fv%3Aw%40x%3Dy%26z%24xxx" },
{ "äöúëü", "%C3%A4%C3%B6%C3%BA%C3%AB%C3%BC" },
{ "🎅🏄🤘😈", "%F0%9F%8E%85%F0%9F%8F%84%F0%9F%A4%98%F0%9F%98%88" },
{ "foo$.%.^.&.\\.txt+", "foo%24.%25.%5E.%26.%5C.txt%2B" }
};
static BOOL test_url_escape(void)
{
for (size_t x = 0; x < ARRAYSIZE(url_tests); x++)
{
const struct url_test_pair* cur = &url_tests[x];
char* escaped = winpr_str_url_encode(cur->what, strlen(cur->what) + 1);
char* what = winpr_str_url_decode(cur->escaped, strlen(cur->escaped) + 1);
const size_t elen = strlen(escaped);
const size_t wlen = strlen(what);
const size_t pelen = strlen(cur->escaped);
const size_t pwlen = strlen(cur->what);
BOOL rc = TRUE;
if (!escaped || (elen != pelen) || (strcmp(escaped, cur->escaped) != 0))
{
printf("expected: [%" PRIuz "] %s\n", pelen, cur->escaped);
printf("got : [%" PRIuz "] %s\n", elen, escaped);
rc = FALSE;
}
else if (!what || (wlen != pwlen) || (strcmp(what, cur->what) != 0))
{
printf("expected: [%" PRIuz "] %s\n", pwlen, cur->what);
printf("got : [%" PRIuz "] %s\n", wlen, what);
rc = FALSE;
}
free(escaped);
free(what);
if (!rc)
return FALSE;
}
return TRUE;
}
static BOOL test_winpr_asprintf(void)
{
BOOL rc = FALSE;
const char test[] = "test string case";
const size_t len = strnlen(test, sizeof(test));
char* str = nullptr;
size_t slen = 0;
const int res = winpr_asprintf(&str, &slen, "%s", test);
if (!str)
goto fail;
if (res < 0)
goto fail;
if ((size_t)res != len)
goto fail;
if (len != slen)
goto fail;
if (strnlen(str, slen + 10) != slen)
goto fail;
rc = TRUE;
fail:
free(str);
return rc;
}
int TestString(int argc, char* argv[])
{
const WCHAR* p = nullptr;
size_t pos = 0;
size_t length = 0;
WCHAR* context = nullptr;
WINPR_UNUSED(argc);
WINPR_UNUSED(argv);
if (!test_winpr_asprintf())
return -1;
if (!test_url_escape())
return -1;
/* _wcslen */
WCHAR testStringW[ARRAYSIZE(testStringA)] = WINPR_C_ARRAY_INIT;
(void)ConvertUtf8NToWChar(testStringA, ARRAYSIZE(testStringA), testStringW,
ARRAYSIZE(testStringW));
const size_t testStringW_Length = testStringA_Length;
length = _wcslen(testStringW);
if (length != testStringW_Length)
{
printf("_wcslen error: length mismatch: Actual: %" PRIuz ", Expected: %" PRIuz "\n", length,
testStringW_Length);
return -1;
}
/* _wcschr */
union
{
char c[2];
WCHAR w;
} search;
search.c[0] = 'r';
search.c[1] = '\0';
p = _wcschr(testStringW, search.w);
pos = (p - testStringW);
if (pos != 11)
{
printf("_wcschr error: position mismatch: Actual: %" PRIuz ", Expected: 11\n", pos);
return -1;
}
p = _wcschr(&testStringW[pos + 1], search.w);
pos = (p - testStringW);
if (pos != 29)
{
printf("_wcschr error: position mismatch: Actual: %" PRIuz ", Expected: 29\n", pos);
return -1;
}
p = _wcschr(&testStringW[pos + 1], search.w);
if (p != nullptr)
{
printf("_wcschr error: return value mismatch: Actual: %p, Expected: nullptr\n",
(const void*)p);
return -1;
}
/* wcstok_s */
WCHAR testDelimiterW[ARRAYSIZE(testDelimiterA)] = WINPR_C_ARRAY_INIT;
WCHAR testTokensW[ARRAYSIZE(testTokensA)] = WINPR_C_ARRAY_INIT;
(void)ConvertUtf8NToWChar(testTokensA, ARRAYSIZE(testTokensA), testTokensW,
ARRAYSIZE(testTokensW));
(void)ConvertUtf8NToWChar(testDelimiterA, ARRAYSIZE(testDelimiterA), testDelimiterW,
ARRAYSIZE(testDelimiterW));
p = wcstok_s(testTokensW, testDelimiterW, &context);
WCHAR testToken1W[ARRAYSIZE(testToken1A)] = WINPR_C_ARRAY_INIT;
(void)ConvertUtf8NToWChar(testToken1A, ARRAYSIZE(testToken1A), testToken1W,
ARRAYSIZE(testToken1W));
if (memcmp(p, testToken1W, sizeof(testToken1W)) != 0)
{
printf("wcstok_s error: token #1 mismatch\n");
return -1;
}
p = wcstok_s(nullptr, testDelimiterW, &context);
WCHAR testToken2W[ARRAYSIZE(testToken2A)] = WINPR_C_ARRAY_INIT;
(void)ConvertUtf8NToWChar(testToken2A, ARRAYSIZE(testToken2A), testToken2W,
ARRAYSIZE(testToken2W));
if (memcmp(p, testToken2W, sizeof(testToken2W)) != 0)
{
printf("wcstok_s error: token #2 mismatch\n");
return -1;
}
p = wcstok_s(nullptr, testDelimiterW, &context);
WCHAR testToken3W[ARRAYSIZE(testToken3A)] = WINPR_C_ARRAY_INIT;
(void)ConvertUtf8NToWChar(testToken3A, ARRAYSIZE(testToken3A), testToken3W,
ARRAYSIZE(testToken3W));
if (memcmp(p, testToken3W, sizeof(testToken3W)) != 0)
{
printf("wcstok_s error: token #3 mismatch\n");
return -1;
}
p = wcstok_s(nullptr, testDelimiterW, &context);
if (p != nullptr)
{
printf("wcstok_s error: return value is not nullptr\n");
return -1;
}
return 0;
}

View File

@@ -0,0 +1,115 @@
#include <stdio.h>
#include <winpr/crt.h>
#include <winpr/windows.h>
#define EXPECTED_SIZEOF_BYTE 1
#define EXPECTED_SIZEOF_BOOLEAN 1
#define EXPECTED_SIZEOF_CHAR 1
#define EXPECTED_SIZEOF_UCHAR 1
#define EXPECTED_SIZEOF_INT8 1
#define EXPECTED_SIZEOF_UINT8 1
#define EXPECTED_SIZEOF_INT16 2
#define EXPECTED_SIZEOF_UINT16 2
#define EXPECTED_SIZEOF_WORD 2
#define EXPECTED_SIZEOF_WCHAR 2
#define EXPECTED_SIZEOF_SHORT 2
#define EXPECTED_SIZEOF_USHORT 2
#define EXPECTED_SIZEOF_BOOL 4
#define EXPECTED_SIZEOF_INT 4
#define EXPECTED_SIZEOF_UINT 4
#define EXPECTED_SIZEOF_INT32 4
#define EXPECTED_SIZEOF_UINT32 4
#define EXPECTED_SIZEOF_DWORD 4
#define EXPECTED_SIZEOF_DWORD32 4
#define EXPECTED_SIZEOF_LONG 4
#define EXPECTED_SIZEOF_LONG32 4
#define EXPECTED_SIZEOF_INT64 8
#define EXPECTED_SIZEOF_UINT64 8
#define EXPECTED_SIZEOF_DWORD64 8
#define EXPECTED_SIZEOF_DWORDLONG 8
#define EXPECTED_SIZEOF_LONG64 8
#define EXPECTED_SIZEOF_ULONGLONG 8
#define EXPECTED_SIZEOF_LUID 8
#define EXPECTED_SIZEOF_FILETIME 8
#define EXPECTED_SIZEOF_LARGE_INTEGER 8
#define EXPECTED_SIZEOF_ULARGE_INTEGER 8
#define EXPECTED_SIZEOF_GUID 16
#define EXPECTED_SIZEOF_SYSTEMTIME 16
#define EXPECTED_SIZEOF_size_t sizeof(void*)
#define EXPECTED_SIZEOF_INT_PTR sizeof(void*)
#define EXPECTED_SIZEOF_UINT_PTR sizeof(void*)
#define EXPECTED_SIZEOF_DWORD_PTR sizeof(void*)
#define EXPECTED_SIZEOF_LONG_PTR sizeof(void*)
#define EXPECTED_SIZEOF_ULONG_PTR sizeof(void*)
#define TEST_SIZEOF_TYPE(_name) \
if (sizeof(_name) != EXPECTED_SIZEOF_##_name) \
{ \
(void)fprintf(stderr, "sizeof(%s) mismatch: Actual: %" PRIuz ", Expected: %" PRIuz "\n", \
#_name, sizeof(_name), (size_t)EXPECTED_SIZEOF_##_name); \
status = -1; \
}
int TestTypes(int argc, char* argv[])
{
int status = 0;
WINPR_UNUSED(argc);
WINPR_UNUSED(argv);
TEST_SIZEOF_TYPE(INT8)
TEST_SIZEOF_TYPE(UINT8)
TEST_SIZEOF_TYPE(BYTE)
TEST_SIZEOF_TYPE(BOOLEAN)
TEST_SIZEOF_TYPE(CHAR)
TEST_SIZEOF_TYPE(UCHAR)
TEST_SIZEOF_TYPE(INT16)
TEST_SIZEOF_TYPE(UINT16)
TEST_SIZEOF_TYPE(WORD)
TEST_SIZEOF_TYPE(WCHAR)
TEST_SIZEOF_TYPE(SHORT)
TEST_SIZEOF_TYPE(USHORT)
/* fails on OS X */
// TEST_SIZEOF_TYPE(BOOL)
TEST_SIZEOF_TYPE(INT)
TEST_SIZEOF_TYPE(UINT)
TEST_SIZEOF_TYPE(DWORD)
TEST_SIZEOF_TYPE(DWORD32)
TEST_SIZEOF_TYPE(LONG)
TEST_SIZEOF_TYPE(LONG32)
TEST_SIZEOF_TYPE(INT32)
TEST_SIZEOF_TYPE(UINT32)
TEST_SIZEOF_TYPE(INT64)
TEST_SIZEOF_TYPE(UINT64)
TEST_SIZEOF_TYPE(DWORD64)
TEST_SIZEOF_TYPE(DWORDLONG)
TEST_SIZEOF_TYPE(LONG64)
TEST_SIZEOF_TYPE(ULONGLONG)
TEST_SIZEOF_TYPE(LUID)
TEST_SIZEOF_TYPE(FILETIME)
TEST_SIZEOF_TYPE(LARGE_INTEGER)
TEST_SIZEOF_TYPE(ULARGE_INTEGER)
TEST_SIZEOF_TYPE(GUID)
TEST_SIZEOF_TYPE(SYSTEMTIME)
TEST_SIZEOF_TYPE(size_t)
TEST_SIZEOF_TYPE(INT_PTR)
TEST_SIZEOF_TYPE(UINT_PTR)
TEST_SIZEOF_TYPE(DWORD_PTR)
TEST_SIZEOF_TYPE(LONG_PTR)
TEST_SIZEOF_TYPE(ULONG_PTR)
return status;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,652 @@
/**
* WinPR: Windows Portable Runtime
* Unicode Conversion (CRT)
*
* Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
* 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.
*/
#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 _WIN32
#include "unicode.h"
/**
* Notes on cross-platform Unicode portability:
*
* Unicode has many possible Unicode Transformation Format (UTF) encodings,
* where some of the most commonly used are UTF-8, UTF-16 and sometimes UTF-32.
*
* The number in the UTF encoding name (8, 16, 32) refers to the number of bits
* per code unit. A code unit is the minimal bit combination that can represent
* a unit of encoded text in the given encoding. For instance, UTF-8 encodes
* the English alphabet using 8 bits (or one byte) each, just like in ASCII.
*
* However, the total number of code points (values in the Unicode codespace)
* only fits completely within 32 bits. This means that for UTF-8 and UTF-16,
* more than one code unit may be required to fully encode a specific value.
* UTF-8 and UTF-16 are variable-width encodings, while UTF-32 is fixed-width.
*
* UTF-8 has the advantage of being backwards compatible with ASCII, and is
* one of the most commonly used Unicode encoding.
*
* UTF-16 is used everywhere in the Windows API. The strategy employed by
* Microsoft to provide backwards compatibility in their API was to create
* an ANSI and a Unicode version of the same function, ending with A (ANSI)
* and W (Wide character, or UTF-16 Unicode). In headers, the original
* function name is replaced by a macro that defines to either the ANSI
* or Unicode version based on the definition of the _UNICODE macro.
*
* UTF-32 has the advantage of being fixed width, but wastes a lot of space
* for English text (4x more than UTF-8, 2x more than UTF-16).
*
* In C, wide character strings are often defined with the wchar_t type.
* Many functions are provided to deal with those wide character strings,
* such as wcslen (strlen equivalent) or wprintf (printf equivalent).
*
* This may lead to some confusion, since many of these functions exist
* on both Windows and Linux, but they are *not* the same!
*
* This sample hello world is a good example:
*
* #include <wchar.h>
*
* wchar_t hello[] = L"Hello, World!\n";
*
* int main(int argc, char** argv)
* {
* wprintf(hello);
* wprintf(L"sizeof(wchar_t): %d\n", sizeof(wchar_t));
* return 0;
* }
*
* There is a reason why the sample prints the size of the wchar_t type:
* On Windows, wchar_t is two bytes (UTF-16), while on most other systems
* it is 4 bytes (UTF-32). This means that if you write code on Windows,
* use L"" to define a string which is meant to be UTF-16 and not UTF-32,
* you will have a little surprise when trying to port your code to Linux.
*
* Since the Windows API uses UTF-16, not UTF-32, WinPR defines the WCHAR
* type to always be 2-bytes long and uses it instead of wchar_t. Do not
* ever use wchar_t with WinPR unless you know what you are doing.
*
* As for L"", it is unfortunately unusable in a portable way, unless a
* special option is passed to GCC to define wchar_t as being two bytes.
* For string constants that must be UTF-16, it is a pain, but they can
* be defined in a portable way like this:
*
* WCHAR hello[] = { 'H','e','l','l','o','\0' };
*
* Such strings cannot be passed to native functions like wcslen(), which
* may expect a different wchar_t size. For this reason, WinPR provides
* _wcslen, which expects UTF-16 WCHAR strings on all platforms.
*
*/
/** \deprecated We no longer export this function, see ConvertUtf8ToWChar family of functions for a
* replacement
*
* Conversion to Unicode (UTF-16)
* MultiByteToWideChar: http://msdn.microsoft.com/en-us/library/windows/desktop/dd319072/
*
* cbMultiByte is an input size in bytes (BYTE)
* cchWideChar is an output size in wide characters (WCHAR)
*
* Null-terminated UTF-8 strings:
*
* cchWideChar *cannot* be assumed to be cbMultiByte since UTF-8 is variable-width!
*
* Instead, obtain the required cchWideChar output size like this:
* cchWideChar = MultiByteToWideChar(CP_UTF8, 0, (LPCSTR) lpMultiByteStr, -1, nullptr, 0);
*
* A value of -1 for cbMultiByte indicates that the input string is null-terminated,
* and the null terminator *will* be processed. The size returned by MultiByteToWideChar
* will therefore include the null terminator. Equivalent behavior can be obtained by
* computing the length in bytes of the input buffer, including the null terminator:
*
* cbMultiByte = strlen((char*) lpMultiByteStr) + 1;
*
* An output buffer of the proper size can then be allocated:
*
* lpWideCharStr = (LPWSTR) malloc(cchWideChar * sizeof(WCHAR));
*
* Since cchWideChar is an output size in wide characters, the actual buffer size is:
* (cchWideChar * sizeof(WCHAR)) or (cchWideChar * 2)
*
* Finally, perform the conversion:
*
* cchWideChar = MultiByteToWideChar(CP_UTF8, 0, (LPCSTR) lpMultiByteStr, -1, lpWideCharStr,
* cchWideChar);
*
* The value returned by MultiByteToWideChar corresponds to the number of wide characters written
* to the output buffer, and should match the value obtained on the first call to
* MultiByteToWideChar.
*
*/
#if !defined(WITH_WINPR_DEPRECATED)
static
#endif
int
MultiByteToWideChar(UINT CodePage, DWORD dwFlags, LPCSTR lpMultiByteStr, int cbMultiByte,
LPWSTR lpWideCharStr, int cchWideChar)
{
return int_MultiByteToWideChar(CodePage, dwFlags, lpMultiByteStr, cbMultiByte, lpWideCharStr,
cchWideChar);
}
/** \deprecated We no longer export this function, see ConvertWCharToUtf8 family of functions for a
* replacement
*
* Conversion from Unicode (UTF-16)
* WideCharToMultiByte: http://msdn.microsoft.com/en-us/library/windows/desktop/dd374130/
*
* cchWideChar is an input size in wide characters (WCHAR)
* cbMultiByte is an output size in bytes (BYTE)
*
* Null-terminated UTF-16 strings:
*
* cbMultiByte *cannot* be assumed to be cchWideChar since UTF-8 is variable-width!
*
* Instead, obtain the required cbMultiByte output size like this:
* cbMultiByte = WideCharToMultiByte(CP_UTF8, 0, (LPCWSTR) lpWideCharStr, -1, nullptr, 0, nullptr,
* nullptr);
*
* A value of -1 for cbMultiByte indicates that the input string is null-terminated,
* and the null terminator *will* be processed. The size returned by WideCharToMultiByte
* will therefore include the null terminator. Equivalent behavior can be obtained by
* computing the length in bytes of the input buffer, including the null terminator:
*
* cchWideChar = _wcslen((WCHAR*) lpWideCharStr) + 1;
*
* An output buffer of the proper size can then be allocated:
* lpMultiByteStr = (LPSTR) malloc(cbMultiByte);
*
* Since cbMultiByte is an output size in bytes, it is the same as the buffer size
*
* Finally, perform the conversion:
*
* cbMultiByte = WideCharToMultiByte(CP_UTF8, 0, (LPCWSTR) lpWideCharStr, -1, lpMultiByteStr,
* cbMultiByte, nullptr, nullptr);
*
* The value returned by WideCharToMultiByte corresponds to the number of bytes written
* to the output buffer, and should match the value obtained on the first call to
* WideCharToMultiByte.
*
*/
#if !defined(WITH_WINPR_DEPRECATED)
static
#endif
int
WideCharToMultiByte(UINT CodePage, DWORD dwFlags, LPCWSTR lpWideCharStr, int cchWideChar,
LPSTR lpMultiByteStr, int cbMultiByte, LPCSTR lpDefaultChar,
LPBOOL lpUsedDefaultChar)
{
return int_WideCharToMultiByte(CodePage, dwFlags, lpWideCharStr, cchWideChar, lpMultiByteStr,
cbMultiByte, lpDefaultChar, lpUsedDefaultChar);
}
#endif
/**
* ConvertToUnicode is a convenience wrapper for MultiByteToWideChar:
*
* If the lpWideCharStr parameter for the converted string points to nullptr
* or if the cchWideChar parameter is set to 0 this function will automatically
* allocate the required memory which is guaranteed to be null-terminated
* after the conversion, even if the source c string isn't.
*
* If the cbMultiByte parameter is set to -1 the passed lpMultiByteStr must
* be null-terminated and the required length for the converted string will be
* calculated accordingly.
*/
#if defined(WITH_WINPR_DEPRECATED)
int ConvertToUnicode(UINT CodePage, DWORD dwFlags, LPCSTR lpMultiByteStr, int cbMultiByte,
LPWSTR* lpWideCharStr, int cchWideChar)
{
int status = 0;
BOOL allocate = FALSE;
if (!lpMultiByteStr)
return 0;
if (!lpWideCharStr)
return 0;
if (cbMultiByte == -1)
{
size_t len = strnlen(lpMultiByteStr, INT_MAX);
if (len >= INT_MAX)
return 0;
cbMultiByte = (int)(len + 1);
}
if (cchWideChar == 0)
{
cchWideChar =
MultiByteToWideChar(CodePage, dwFlags, lpMultiByteStr, cbMultiByte, nullptr, 0);
allocate = TRUE;
}
else if (!(*lpWideCharStr))
allocate = TRUE;
if (cchWideChar < 1)
return 0;
if (allocate)
{
*lpWideCharStr = (LPWSTR)calloc((size_t)cchWideChar + 1ull, sizeof(WCHAR));
if (!(*lpWideCharStr))
{
// SetLastError(ERROR_INSUFFICIENT_BUFFER);
return 0;
}
}
status = MultiByteToWideChar(CodePage, dwFlags, lpMultiByteStr, cbMultiByte, *lpWideCharStr,
cchWideChar);
if (status != cchWideChar)
{
if (allocate)
{
free(*lpWideCharStr);
*lpWideCharStr = nullptr;
status = 0;
}
}
return status;
}
#endif
/**
* ConvertFromUnicode is a convenience wrapper for WideCharToMultiByte:
*
* If the lpMultiByteStr parameter for the converted string points to nullptr
* or if the cbMultiByte parameter is set to 0 this function will automatically
* allocate the required memory which is guaranteed to be null-terminated
* after the conversion, even if the source unicode string isn't.
*
* If the cchWideChar parameter is set to -1 the passed lpWideCharStr must
* be null-terminated and the required length for the converted string will be
* calculated accordingly.
*/
#if defined(WITH_WINPR_DEPRECATED)
int ConvertFromUnicode(UINT CodePage, DWORD dwFlags, LPCWSTR lpWideCharStr, int cchWideChar,
LPSTR* lpMultiByteStr, int cbMultiByte, LPCSTR lpDefaultChar,
LPBOOL lpUsedDefaultChar)
{
int status = 0;
BOOL allocate = FALSE;
if (!lpWideCharStr)
return 0;
if (!lpMultiByteStr)
return 0;
if (cchWideChar == -1)
cchWideChar = (int)(_wcslen(lpWideCharStr) + 1);
if (cbMultiByte == 0)
{
cbMultiByte = WideCharToMultiByte(CodePage, dwFlags, lpWideCharStr, cchWideChar, nullptr, 0,
nullptr, nullptr);
allocate = TRUE;
}
else if (!(*lpMultiByteStr))
allocate = TRUE;
if (cbMultiByte < 1)
return 0;
if (allocate)
{
*lpMultiByteStr = (LPSTR)calloc(1, (size_t)cbMultiByte + 1ull);
if (!(*lpMultiByteStr))
{
// SetLastError(ERROR_INSUFFICIENT_BUFFER);
return 0;
}
}
status = WideCharToMultiByte(CodePage, dwFlags, lpWideCharStr, cchWideChar, *lpMultiByteStr,
cbMultiByte, lpDefaultChar, lpUsedDefaultChar);
if ((status != cbMultiByte) && allocate)
{
status = 0;
}
if ((status <= 0) && allocate)
{
free(*lpMultiByteStr);
*lpMultiByteStr = nullptr;
}
return status;
}
#endif
/**
* Swap Unicode byte order (UTF16LE <-> UTF16BE)
*/
const WCHAR* ByteSwapUnicode(WCHAR* wstr, size_t length)
{
WINPR_ASSERT(wstr || (length == 0));
for (size_t x = 0; x < length; x++)
wstr[x] = _byteswap_ushort(wstr[x]);
return wstr;
}
SSIZE_T ConvertWCharToUtf8(const WCHAR* wstr, char* str, size_t len)
{
if (!wstr)
{
if (str && len)
str[0] = 0;
return 0;
}
const size_t wlen = _wcslen(wstr);
return ConvertWCharNToUtf8(wstr, wlen + 1, str, len);
}
SSIZE_T ConvertWCharNToUtf8(const WCHAR* wstr, size_t wlen, char* str, size_t len)
{
BOOL isNullTerminated = FALSE;
if (wlen == 0)
return 0;
WINPR_ASSERT(wstr);
size_t iwlen = _wcsnlen(wstr, wlen);
if ((len > INT32_MAX) || (wlen > INT32_MAX))
{
SetLastError(ERROR_INVALID_PARAMETER);
return -1;
}
if (iwlen < wlen)
{
isNullTerminated = TRUE;
iwlen++;
}
const int rc =
WideCharToMultiByte(CP_UTF8, 0, wstr, (int)iwlen, str, (int)len, nullptr, nullptr);
if ((rc <= 0) || ((len > 0) && ((size_t)rc > len)))
return -1;
else if (!isNullTerminated)
{
if (str && ((size_t)rc < len))
str[rc] = '\0';
return rc;
}
else if ((size_t)rc == len)
{
if (str && (str[rc - 1] != '\0'))
return rc;
}
return rc - 1;
}
SSIZE_T ConvertMszWCharNToUtf8(const WCHAR* wstr, size_t wlen, char* str, size_t len)
{
if (wlen == 0)
return 0;
WINPR_ASSERT(wstr);
if ((len > INT32_MAX) || (wlen > INT32_MAX))
{
SetLastError(ERROR_INVALID_PARAMETER);
return -1;
}
const int iwlen = (int)len;
const int rc = WideCharToMultiByte(CP_UTF8, 0, wstr, (int)wlen, str, iwlen, nullptr, nullptr);
if ((rc <= 0) || ((len > 0) && (rc > iwlen)))
return -1;
return rc;
}
SSIZE_T ConvertUtf8ToWChar(const char* str, WCHAR* wstr, size_t wlen)
{
if (!str)
{
if (wstr && wlen)
wstr[0] = 0;
return 0;
}
const size_t len = strlen(str);
return ConvertUtf8NToWChar(str, len + 1, wstr, wlen);
}
SSIZE_T ConvertUtf8NToWChar(const char* str, size_t len, WCHAR* wstr, size_t wlen)
{
size_t ilen = strnlen(str, len);
BOOL isNullTerminated = FALSE;
if (len == 0)
return 0;
WINPR_ASSERT(str);
if ((len > INT32_MAX) || (wlen > INT32_MAX))
{
SetLastError(ERROR_INVALID_PARAMETER);
return -1;
}
if (ilen < len)
{
isNullTerminated = TRUE;
ilen++;
}
const int iwlen = (int)wlen;
const int rc = MultiByteToWideChar(CP_UTF8, 0, str, (int)ilen, wstr, iwlen);
if ((rc <= 0) || ((wlen > 0) && (rc > iwlen)))
return -1;
if (!isNullTerminated)
{
if (wstr && (rc < iwlen))
wstr[rc] = '\0';
return rc;
}
else if (rc == iwlen)
{
if (wstr && (wstr[rc - 1] != '\0'))
return rc;
}
return rc - 1;
}
SSIZE_T ConvertMszUtf8NToWChar(const char* str, size_t len, WCHAR* wstr, size_t wlen)
{
if (len == 0)
return 0;
WINPR_ASSERT(str);
if ((len > INT32_MAX) || (wlen > INT32_MAX))
{
SetLastError(ERROR_INVALID_PARAMETER);
return -1;
}
const int iwlen = (int)wlen;
const int rc = MultiByteToWideChar(CP_UTF8, 0, str, (int)len, wstr, iwlen);
if ((rc <= 0) || ((wlen > 0) && (rc > iwlen)))
return -1;
return rc;
}
char* ConvertWCharToUtf8Alloc(const WCHAR* wstr, size_t* pUtfCharLength)
{
char* tmp = nullptr;
const SSIZE_T rc = ConvertWCharToUtf8(wstr, nullptr, 0);
if (pUtfCharLength)
*pUtfCharLength = 0;
if (rc < 0)
return nullptr;
tmp = calloc((size_t)rc + 1ull, sizeof(char));
if (!tmp)
return nullptr;
const SSIZE_T rc2 = ConvertWCharToUtf8(wstr, tmp, (size_t)rc + 1ull);
if (rc2 < 0)
{
free(tmp);
return nullptr;
}
WINPR_ASSERT(rc == rc2);
if (pUtfCharLength)
*pUtfCharLength = (size_t)rc2;
return tmp;
}
char* ConvertWCharNToUtf8Alloc(const WCHAR* wstr, size_t wlen, size_t* pUtfCharLength)
{
char* tmp = nullptr;
const SSIZE_T rc = ConvertWCharNToUtf8(wstr, wlen, nullptr, 0);
if (pUtfCharLength)
*pUtfCharLength = 0;
if (rc < 0)
return nullptr;
tmp = calloc((size_t)rc + 1ull, sizeof(char));
if (!tmp)
return nullptr;
const SSIZE_T rc2 = ConvertWCharNToUtf8(wstr, wlen, tmp, (size_t)rc + 1ull);
if (rc2 < 0)
{
free(tmp);
return nullptr;
}
WINPR_ASSERT(rc == rc2);
if (pUtfCharLength)
*pUtfCharLength = (size_t)rc2;
return tmp;
}
char* ConvertMszWCharNToUtf8Alloc(const WCHAR* wstr, size_t wlen, size_t* pUtfCharLength)
{
char* tmp = nullptr;
const SSIZE_T rc = ConvertMszWCharNToUtf8(wstr, wlen, nullptr, 0);
if (pUtfCharLength)
*pUtfCharLength = 0;
if (rc < 0)
return nullptr;
tmp = calloc((size_t)rc + 1ull, sizeof(char));
if (!tmp)
return nullptr;
const SSIZE_T rc2 = ConvertMszWCharNToUtf8(wstr, wlen, tmp, (size_t)rc + 1ull);
if (rc2 < 0)
{
free(tmp);
return nullptr;
}
WINPR_ASSERT(rc == rc2);
if (pUtfCharLength)
*pUtfCharLength = (size_t)rc2;
return tmp;
}
WCHAR* ConvertUtf8ToWCharAlloc(const char* str, size_t* pSize)
{
WCHAR* tmp = nullptr;
const SSIZE_T rc = ConvertUtf8ToWChar(str, nullptr, 0);
if (pSize)
*pSize = 0;
if (rc < 0)
return nullptr;
tmp = calloc((size_t)rc + 1ull, sizeof(WCHAR));
if (!tmp)
return nullptr;
const SSIZE_T rc2 = ConvertUtf8ToWChar(str, tmp, (size_t)rc + 1ull);
if (rc2 < 0)
{
free(tmp);
return nullptr;
}
WINPR_ASSERT(rc == rc2);
if (pSize)
*pSize = (size_t)rc2;
return tmp;
}
WCHAR* ConvertUtf8NToWCharAlloc(const char* str, size_t len, size_t* pSize)
{
WCHAR* tmp = nullptr;
const SSIZE_T rc = ConvertUtf8NToWChar(str, len, nullptr, 0);
if (pSize)
*pSize = 0;
if (rc < 0)
return nullptr;
tmp = calloc((size_t)rc + 1ull, sizeof(WCHAR));
if (!tmp)
return nullptr;
const SSIZE_T rc2 = ConvertUtf8NToWChar(str, len, tmp, (size_t)rc + 1ull);
if (rc2 < 0)
{
free(tmp);
return nullptr;
}
WINPR_ASSERT(rc == rc2);
if (pSize)
*pSize = (size_t)rc2;
return tmp;
}
WCHAR* ConvertMszUtf8NToWCharAlloc(const char* str, size_t len, size_t* pSize)
{
WCHAR* tmp = nullptr;
const SSIZE_T rc = ConvertMszUtf8NToWChar(str, len, nullptr, 0);
if (pSize)
*pSize = 0;
if (rc < 0)
return nullptr;
tmp = calloc((size_t)rc + 1ull, sizeof(WCHAR));
if (!tmp)
return nullptr;
const SSIZE_T rc2 = ConvertMszUtf8NToWChar(str, len, tmp, (size_t)rc + 1ull);
if (rc2 < 0)
{
free(tmp);
return nullptr;
}
WINPR_ASSERT(rc == rc2);
if (pSize)
*pSize = (size_t)rc2;
return tmp;
}

View File

@@ -0,0 +1,32 @@
/**
* 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.
*/
#ifndef WINPR_CRT_UNICODE_INTERNAL
#define WINPR_CRT_UNICODE_INTERNAL
#include <winpr/wtypes.h>
int int_MultiByteToWideChar(UINT CodePage, DWORD dwFlags, LPCSTR lpMultiByteStr, int cbMultiByte,
LPWSTR lpWideCharStr, int cchWideChar);
int int_WideCharToMultiByte(UINT CodePage, DWORD dwFlags, LPCWSTR lpWideCharStr, int cchWideChar,
LPSTR lpMultiByteStr, int cbMultiByte, LPCSTR lpDefaultChar,
LPBOOL lpUsedDefaultChar);
#endif

View File

@@ -0,0 +1,184 @@
/**
* 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.
*/
#include <winpr/config.h>
#include <winpr/assert.h>
#include <winpr/string.h>
#include "../utils/android.h"
#include "unicode.h"
#ifndef MIN
#define MIN(a, b) (a) < (b) ? (a) : (b)
#endif
#include "../log.h"
#define TAG WINPR_TAG("unicode")
static int convert_int(JNIEnv* env, const void* data, size_t size, void* buffer, size_t buffersize,
BOOL toUTF16)
{
WINPR_ASSERT(env);
WINPR_ASSERT(data || (size == 0));
WINPR_ASSERT(buffer || (buffersize == 0));
jstring utf8 = (*env)->NewStringUTF(env, "UTF-8");
jstring utf16 = (*env)->NewStringUTF(env, "UTF-16LE");
jclass stringClass = (*env)->FindClass(env, "java/lang/String");
if (!utf8 || !utf16 || !stringClass)
{
WLog_ERR(TAG, "utf8-%p, utf16=%p, stringClass=%p", utf8, utf16, stringClass);
return -1;
}
jmethodID constructorID =
(*env)->GetMethodID(env, stringClass, "<init>", "([BLjava/lang/String;)V");
jmethodID getBytesID =
(*env)->GetMethodID(env, stringClass, "getBytes", "(Ljava/lang/String;)[B");
if (!constructorID || !getBytesID)
{
WLog_ERR(TAG, "constructorID=%p, getBytesID=%p", constructorID, getBytesID);
return -2;
}
jbyteArray ret = (*env)->NewByteArray(env, size);
if (!ret)
{
WLog_ERR(TAG, "NewByteArray(%" PRIuz ") failed", size);
return -3;
}
(*env)->SetByteArrayRegion(env, ret, 0, size, data);
jobject obj = (*env)->NewObject(env, stringClass, constructorID, ret, toUTF16 ? utf8 : utf16);
if (!obj)
{
WLog_ERR(TAG, "NewObject(String, byteArray, UTF-%d) failed", toUTF16 ? 16 : 8);
return -4;
}
jbyteArray res = (*env)->CallObjectMethod(env, obj, getBytesID, toUTF16 ? utf16 : utf8);
if (!res)
{
WLog_ERR(TAG, "CallObjectMethod(String, getBytes, UTF-%d) failed", toUTF16 ? 16 : 8);
return -4;
}
jsize rlen = (*env)->GetArrayLength(env, res);
if (buffersize > 0)
{
if (rlen > buffersize)
{
SetLastError(ERROR_INSUFFICIENT_BUFFER);
return 0;
}
rlen = MIN(rlen, buffersize);
(*env)->GetByteArrayRegion(env, res, 0, rlen, buffer);
}
if (toUTF16)
rlen /= sizeof(WCHAR);
return rlen;
}
static int convert(const void* data, size_t size, void* buffer, size_t buffersize, BOOL toUTF16)
{
int rc;
JNIEnv* env = nullptr;
jboolean attached = winpr_jni_attach_thread(&env);
rc = convert_int(env, data, size, buffer, buffersize, toUTF16);
if (attached)
winpr_jni_detach_thread();
return rc;
}
int int_MultiByteToWideChar(UINT CodePage, DWORD dwFlags, LPCSTR lpMultiByteStr, int cbMultiByte,
LPWSTR lpWideCharStr, int cchWideChar)
{
size_t cbCharLen = (size_t)cbMultiByte;
WINPR_UNUSED(dwFlags);
/* If cbMultiByte is 0, the function fails */
if ((cbMultiByte == 0) || (cbMultiByte < -1))
return 0;
if (cchWideChar < 0)
return -1;
if (cbMultiByte < 0)
{
const size_t len = strlen(lpMultiByteStr);
if (len >= INT32_MAX)
return 0;
cbCharLen = (int)len + 1;
}
else
cbCharLen = cbMultiByte;
WINPR_ASSERT(lpMultiByteStr);
switch (CodePage)
{
case CP_ACP:
case CP_UTF8:
break;
default:
WLog_ERR(TAG, "Unsupported encoding %u", CodePage);
return 0;
}
return convert(lpMultiByteStr, cbCharLen, lpWideCharStr, cchWideChar * sizeof(WCHAR), TRUE);
}
int int_WideCharToMultiByte(UINT CodePage, DWORD dwFlags, LPCWSTR lpWideCharStr, int cchWideChar,
LPSTR lpMultiByteStr, int cbMultiByte, LPCSTR lpDefaultChar,
LPBOOL lpUsedDefaultChar)
{
size_t cbCharLen = (size_t)cchWideChar;
WINPR_UNUSED(dwFlags);
/* If cchWideChar is 0, the function fails */
if ((cchWideChar == 0) || (cchWideChar < -1))
return 0;
if (cbMultiByte < 0)
return -1;
WINPR_ASSERT(lpWideCharStr);
/* If cchWideChar is -1, the string is null-terminated */
if (cchWideChar == -1)
{
const size_t len = _wcslen(lpWideCharStr);
if (len >= INT32_MAX)
return 0;
cbCharLen = (int)len + 1;
}
else
cbCharLen = cchWideChar;
/*
* if cbMultiByte is 0, the function returns the required buffer size
* in bytes for lpMultiByteStr and makes no use of the output parameter itself.
*/
return convert(lpWideCharStr, cbCharLen * sizeof(WCHAR), lpMultiByteStr, cbMultiByte, FALSE);
}

View File

@@ -0,0 +1,149 @@
/**
* 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>
#include "unicode.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) || ((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;
}
}

View File

@@ -0,0 +1,729 @@
/*
* Copyright 2001-2004 Unicode, Inc.
*
* Disclaimer
*
* This source code is provided as is by Unicode, Inc. No claims are
* made as to fitness for any particular purpose. No warranties of any
* kind are expressed or implied. The recipient agrees to determine
* applicability of information provided. If this file has been
* purchased on magnetic or optical media from Unicode, Inc., the
* sole remedy for any claim will be exchange of defective media
* within 90 days of receipt.
*
* Limitations on Rights to Redistribute This Code
*
* Unicode, Inc. hereby grants the right to freely use the information
* supplied in this file in the creation of products supporting the
* Unicode Standard, and to make copies of this file in any form
* for internal or external distribution as long as this notice
* remains attached.
*/
/* ---------------------------------------------------------------------
Conversions between UTF32, UTF-16, and UTF-8. Source code file.
Author: Mark E. Davis, 1994.
Rev History: Rick McGowan, fixes & updates May 2001.
Sept 2001: fixed const & error conditions per
mods suggested by S. Parent & A. Lillich.
June 2002: Tim Dodd added detection and handling of incomplete
source sequences, enhanced error detection, added casts
to eliminate compiler warnings.
July 2003: slight mods to back out aggressive FFFE detection.
Jan 2004: updated switches in from-UTF8 conversions.
Oct 2004: updated to use UNI_MAX_LEGAL_UTF32 in UTF-32 conversions.
See the header file "utf.h" for complete documentation.
------------------------------------------------------------------------ */
#include <winpr/wtypes.h>
#include <winpr/string.h>
#include <winpr/assert.h>
#include <winpr/cast.h>
#include "unicode.h"
#include "../log.h"
#define TAG WINPR_TAG("unicode")
/*
* Character Types:
*
* UTF8: uint8_t 8 bits
* UTF16: uint16_t 16 bits
* UTF32: uint32_t 32 bits
*/
/* Some fundamental constants */
#define UNI_REPLACEMENT_CHAR (uint32_t)0x0000FFFD
#define UNI_MAX_BMP (uint32_t)0x0000FFFF
#define UNI_MAX_UTF16 (uint32_t)0x0010FFFF
#define UNI_MAX_UTF32 (uint32_t)0x7FFFFFFF
#define UNI_MAX_LEGAL_UTF32 (uint32_t)0x0010FFFF
typedef enum
{
conversionOK, /* conversion successful */
sourceExhausted, /* partial character in source, but hit end */
targetExhausted, /* insuff. room in target for conversion */
sourceIllegal /* source sequence is illegal/malformed */
} ConversionResult;
typedef enum
{
strictConversion = 0,
lenientConversion
} ConversionFlags;
static const int halfShift = 10; /* used for shifting by 10 bits */
static const uint32_t halfBase = 0x0010000UL;
static const uint32_t halfMask = 0x3FFUL;
#define UNI_SUR_HIGH_START (uint32_t)0xD800
#define UNI_SUR_HIGH_END (uint32_t)0xDBFF
#define UNI_SUR_LOW_START (uint32_t)0xDC00
#define UNI_SUR_LOW_END (uint32_t)0xDFFF
/* --------------------------------------------------------------------- */
/*
* Index into the table below with the first byte of a UTF-8 sequence to
* get the number of trailing bytes that are supposed to follow it.
* Note that *legal* UTF-8 values can't have 4 or 5-bytes. The table is
* left as-is for anyone who may want to do such conversion, which was
* allowed in earlier algorithms.
*/
static const char trailingBytesForUTF8[256] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5
};
/*
* Magic values subtracted from a buffer value during UTF8 conversion.
* This table contains as many values as there might be trailing bytes
* in a UTF-8 sequence.
*/
static const uint32_t offsetsFromUTF8[6] = { 0x00000000UL, 0x00003080UL, 0x000E2080UL,
0x03C82080UL, 0xFA082080UL, 0x82082080UL };
/*
* Once the bits are split out into bytes of UTF-8, this is a mask OR-ed
* into the first byte, depending on how many bytes follow. There are
* as many entries in this table as there are UTF-8 sequence types.
* (I.e., one byte sequence, two byte... etc.). Remember that sequence
* for *legal* UTF-8 will be 4 or fewer bytes total.
*/
static const uint8_t firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
/* We always need UTF-16LE, even on big endian systems! */
static WCHAR setWcharFrom(WCHAR w)
{
#if defined(__BIG_ENDIAN__)
union
{
WCHAR w;
char c[2];
} cnv;
cnv.w = w;
const char c = cnv.c[0];
cnv.c[0] = cnv.c[1];
cnv.c[1] = c;
return cnv.w;
#else
return w;
#endif
}
/* --------------------------------------------------------------------- */
/* The interface converts a whole buffer to avoid function-call overhead.
* Constants have been gathered. Loops & conditionals have been removed as
* much as possible for efficiency, in favor of drop-through switches.
* (See "Note A" at the bottom of the file for equivalent code.)
* If your compiler supports it, the "isLegalUTF8" call can be turned
* into an inline function.
*/
/* --------------------------------------------------------------------- */
static ConversionResult winpr_ConvertUTF16toUTF8_Internal(const uint16_t** sourceStart,
const uint16_t* sourceEnd,
uint8_t** targetStart,
const uint8_t* targetEnd,
ConversionFlags flags)
{
bool computeLength = (!targetEnd) ? true : false;
const uint16_t* source = *sourceStart;
uint8_t* target = *targetStart;
ConversionResult result = conversionOK;
while (source < sourceEnd)
{
uint32_t ch = 0;
unsigned short bytesToWrite = 0;
const uint32_t byteMask = 0xBF;
const uint32_t byteMark = 0x80;
const uint16_t* oldSource =
source; /* In case we have to back up because of target overflow. */
ch = setWcharFrom(*source++);
/* If we have a surrogate pair, convert to UTF32 first. */
if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END)
{
/* If the 16 bits following the high surrogate are in the source buffer... */
if (source < sourceEnd)
{
uint32_t ch2 = setWcharFrom(*source);
/* If it's a low surrogate, convert to UTF32. */
if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END)
{
ch = ((ch - UNI_SUR_HIGH_START) << halfShift) + (ch2 - UNI_SUR_LOW_START) +
halfBase;
++source;
}
else if (flags == strictConversion)
{
/* it's an unpaired high surrogate */
--source; /* return to the illegal value itself */
result = sourceIllegal;
break;
}
}
else
{
/* We don't have the 16 bits following the high surrogate. */
--source; /* return to the high surrogate */
result = sourceExhausted;
break;
}
}
else if (flags == strictConversion)
{
/* UTF-16 surrogate values are illegal in UTF-32 */
if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END)
{
--source; /* return to the illegal value itself */
result = sourceIllegal;
break;
}
}
/* Figure out how many bytes the result will require */
if (ch < (uint32_t)0x80)
{
bytesToWrite = 1;
}
else if (ch < (uint32_t)0x800)
{
bytesToWrite = 2;
}
else if (ch < (uint32_t)0x10000)
{
bytesToWrite = 3;
}
else if (ch < (uint32_t)0x110000)
{
bytesToWrite = 4;
}
else
{
bytesToWrite = 3;
ch = UNI_REPLACEMENT_CHAR;
}
target += bytesToWrite;
if ((target > targetEnd) && (!computeLength))
{
source = oldSource; /* Back up source pointer! */
target -= bytesToWrite;
result = targetExhausted;
break;
}
if (!computeLength)
{
switch (bytesToWrite)
{
/* note: everything falls through. */
case 4:
*--target = (uint8_t)((ch | byteMark) & byteMask);
ch >>= 6;
/* fallthrough */
WINPR_FALLTHROUGH
case 3:
*--target = (uint8_t)((ch | byteMark) & byteMask);
ch >>= 6;
/* fallthrough */
WINPR_FALLTHROUGH
case 2:
*--target = (uint8_t)((ch | byteMark) & byteMask);
ch >>= 6;
/* fallthrough */
WINPR_FALLTHROUGH
case 1:
*--target = (uint8_t)(ch | firstByteMark[bytesToWrite]);
break;
default:
return sourceIllegal;
}
}
else
{
switch (bytesToWrite)
{
/* note: everything falls through. */
case 4:
--target;
/* fallthrough */
WINPR_FALLTHROUGH
case 3:
--target;
/* fallthrough */
WINPR_FALLTHROUGH
case 2:
--target;
/* fallthrough */
WINPR_FALLTHROUGH
case 1:
--target;
break;
default:
return sourceIllegal;
}
}
target += bytesToWrite;
}
*sourceStart = source;
*targetStart = target;
return result;
}
/* --------------------------------------------------------------------- */
/*
* Utility routine to tell whether a sequence of bytes is legal UTF-8.
* This must be called with the length pre-determined by the first byte.
* If not calling this from ConvertUTF8to*, then the length can be set by:
* length = trailingBytesForUTF8[*source]+1;
* and the sequence is illegal right away if there aren't that many bytes
* available.
* If presented with a length > 4, this returns false. The Unicode
* definition of UTF-8 goes up to 4-byte sequences.
*/
static bool isLegalUTF8(const uint8_t* source, int length)
{
uint8_t a = 0;
const uint8_t* srcptr = source + length;
switch (length)
{
default:
return false;
/* Everything else falls through when "true"... */
case 4:
if ((a = (*--srcptr)) < 0x80 || a > 0xBF)
return false;
/* fallthrough */
WINPR_FALLTHROUGH
case 3:
if ((a = (*--srcptr)) < 0x80 || a > 0xBF)
return false;
/* fallthrough */
WINPR_FALLTHROUGH
case 2:
if ((a = (*--srcptr)) > 0xBF)
return false;
switch (*source)
{
/* no fall-through in this inner switch */
case 0xE0:
if (a < 0xA0)
return false;
break;
case 0xED:
if (a > 0x9F)
return false;
break;
case 0xF0:
if (a < 0x90)
return false;
break;
case 0xF4:
if (a > 0x8F)
return false;
break;
default:
if (a < 0x80)
return false;
break;
}
/* fallthrough */
WINPR_FALLTHROUGH
case 1:
if (*source >= 0x80 && *source < 0xC2)
return false;
}
if (*source > 0xF4)
return false;
return true;
}
/* --------------------------------------------------------------------- */
static ConversionResult winpr_ConvertUTF8toUTF16_Internal(const uint8_t** sourceStart,
const uint8_t* sourceEnd,
uint16_t** targetStart,
const uint16_t* targetEnd,
ConversionFlags flags)
{
bool computeLength = (!targetEnd) ? true : false;
ConversionResult result = conversionOK;
const uint8_t* source = *sourceStart;
uint16_t* target = *targetStart;
while (source < sourceEnd)
{
uint32_t ch = 0;
unsigned short extraBytesToRead =
WINPR_ASSERTING_INT_CAST(unsigned short, trailingBytesForUTF8[*source]);
if ((source + extraBytesToRead) >= sourceEnd)
{
result = sourceExhausted;
break;
}
/* Do this check whether lenient or strict */
if (!isLegalUTF8(source, extraBytesToRead + 1))
{
result = sourceIllegal;
break;
}
/*
* The cases all fall through. See "Note A" below.
*/
switch (extraBytesToRead)
{
case 5:
ch += *source++;
ch <<= 6; /* remember, illegal UTF-8 */
/* fallthrough */
WINPR_FALLTHROUGH
case 4:
ch += *source++;
ch <<= 6; /* remember, illegal UTF-8 */
/* fallthrough */
WINPR_FALLTHROUGH
case 3:
ch += *source++;
ch <<= 6;
/* fallthrough */
WINPR_FALLTHROUGH
case 2:
ch += *source++;
ch <<= 6;
/* fallthrough */
WINPR_FALLTHROUGH
case 1:
ch += *source++;
ch <<= 6;
/* fallthrough */
WINPR_FALLTHROUGH
case 0:
ch += *source++;
break;
default:
return sourceIllegal;
}
ch -= offsetsFromUTF8[extraBytesToRead];
if ((target >= targetEnd) && (!computeLength))
{
source -= (extraBytesToRead + 1); /* Back up source pointer! */
result = targetExhausted;
break;
}
if (ch <= UNI_MAX_BMP)
{
/* Target is a character <= 0xFFFF */
/* UTF-16 surrogate values are illegal in UTF-32 */
if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END)
{
if (flags == strictConversion)
{
source -= (extraBytesToRead + 1); /* return to the illegal value itself */
result = sourceIllegal;
break;
}
else
{
if (!computeLength)
*target++ = setWcharFrom(UNI_REPLACEMENT_CHAR);
else
target++;
}
}
else
{
if (!computeLength)
*target++ = setWcharFrom((WCHAR)ch); /* normal case */
else
target++;
}
}
else if (ch > UNI_MAX_UTF16)
{
if (flags == strictConversion)
{
result = sourceIllegal;
source -= (extraBytesToRead + 1); /* return to the start */
break; /* Bail out; shouldn't continue */
}
else
{
if (!computeLength)
*target++ = setWcharFrom(UNI_REPLACEMENT_CHAR);
else
target++;
}
}
else
{
/* target is a character in range 0xFFFF - 0x10FFFF. */
if ((target + 1 >= targetEnd) && (!computeLength))
{
source -= (extraBytesToRead + 1); /* Back up source pointer! */
result = targetExhausted;
break;
}
ch -= halfBase;
if (!computeLength)
{
*target++ = setWcharFrom((WCHAR)((ch >> halfShift) + UNI_SUR_HIGH_START));
*target++ = setWcharFrom((WCHAR)((ch & halfMask) + UNI_SUR_LOW_START));
}
else
{
target++;
target++;
}
}
}
*sourceStart = source;
*targetStart = target;
return result;
}
/**
* WinPR built-in Unicode API
*/
static int winpr_ConvertUTF8toUTF16(const uint8_t* src, int cchSrc, uint16_t* dst, int cchDst)
{
size_t length = 0;
uint16_t* dstBeg = nullptr;
uint16_t* dstEnd = nullptr;
const uint8_t* srcBeg = nullptr;
const uint8_t* srcEnd = nullptr;
ConversionResult result = sourceIllegal;
if (cchSrc == -1)
cchSrc = (int)strnlen((const char*)src, INT32_MAX - 1) + 1;
srcBeg = src;
srcEnd = &src[cchSrc];
if (cchDst == 0)
{
result =
winpr_ConvertUTF8toUTF16_Internal(&srcBeg, srcEnd, &dstBeg, dstEnd, strictConversion);
length = dstBeg - (uint16_t*)nullptr;
}
else
{
dstBeg = dst;
dstEnd = &dst[cchDst];
result =
winpr_ConvertUTF8toUTF16_Internal(&srcBeg, srcEnd, &dstBeg, dstEnd, strictConversion);
length = dstBeg - dst;
}
if (result == targetExhausted)
{
SetLastError(ERROR_INSUFFICIENT_BUFFER);
return 0;
}
return (result == conversionOK) ? WINPR_ASSERTING_INT_CAST(int, length) : 0;
}
static int winpr_ConvertUTF16toUTF8(const uint16_t* src, int cchSrc, uint8_t* dst, int cchDst)
{
size_t length = 0;
uint8_t* dstBeg = nullptr;
uint8_t* dstEnd = nullptr;
const uint16_t* srcBeg = nullptr;
const uint16_t* srcEnd = nullptr;
ConversionResult result = sourceIllegal;
if (cchSrc == -1)
cchSrc = (int)_wcsnlen((const WCHAR*)src, INT32_MAX - 1) + 1;
srcBeg = src;
srcEnd = &src[cchSrc];
if (cchDst == 0)
{
result =
winpr_ConvertUTF16toUTF8_Internal(&srcBeg, srcEnd, &dstBeg, dstEnd, strictConversion);
length = dstBeg - ((uint8_t*)nullptr);
}
else
{
dstBeg = dst;
dstEnd = &dst[cchDst];
result =
winpr_ConvertUTF16toUTF8_Internal(&srcBeg, srcEnd, &dstBeg, dstEnd, strictConversion);
length = dstBeg - dst;
}
if (result == targetExhausted)
{
SetLastError(ERROR_INSUFFICIENT_BUFFER);
return 0;
}
return (result == conversionOK) ? WINPR_ASSERTING_INT_CAST(int, length) : 0;
}
/* --------------------------------------------------------------------- */
int int_MultiByteToWideChar(UINT CodePage, DWORD dwFlags, LPCSTR lpMultiByteStr, int cbMultiByte,
LPWSTR lpWideCharStr, int cchWideChar)
{
size_t cbCharLen = (size_t)cbMultiByte;
WINPR_UNUSED(dwFlags);
/* If cbMultiByte is 0, the function fails */
if ((cbMultiByte == 0) || (cbMultiByte < -1))
return 0;
if (cchWideChar < 0)
return -1;
if (cbMultiByte < 0)
{
const size_t len = strlen(lpMultiByteStr);
if (len >= INT32_MAX)
return 0;
cbCharLen = (int)len + 1;
}
else
cbCharLen = cbMultiByte;
WINPR_ASSERT(lpMultiByteStr);
switch (CodePage)
{
case CP_ACP:
case CP_UTF8:
break;
default:
WLog_ERR(TAG, "Unsupported encoding %u", CodePage);
return 0;
}
return winpr_ConvertUTF8toUTF16((const uint8_t*)lpMultiByteStr,
WINPR_ASSERTING_INT_CAST(int, cbCharLen),
(uint16_t*)lpWideCharStr, cchWideChar);
}
int int_WideCharToMultiByte(UINT CodePage, DWORD dwFlags, LPCWSTR lpWideCharStr, int cchWideChar,
LPSTR lpMultiByteStr, int cbMultiByte, LPCSTR lpDefaultChar,
LPBOOL lpUsedDefaultChar)
{
size_t cbCharLen = (size_t)cchWideChar;
WINPR_UNUSED(dwFlags);
/* If cchWideChar is 0, the function fails */
if ((cchWideChar == 0) || (cchWideChar < -1))
return 0;
if (cbMultiByte < 0)
return -1;
WINPR_ASSERT(lpWideCharStr);
/* If cchWideChar is -1, the string is null-terminated */
if (cchWideChar == -1)
{
const size_t len = _wcslen(lpWideCharStr);
if (len >= INT32_MAX)
return 0;
cbCharLen = (int)len + 1;
}
else
cbCharLen = cchWideChar;
/*
* if cbMultiByte is 0, the function returns the required buffer size
* in bytes for lpMultiByteStr and makes no use of the output parameter itself.
*/
return winpr_ConvertUTF16toUTF8((const uint16_t*)lpWideCharStr,
WINPR_ASSERTING_INT_CAST(int, cbCharLen),
(uint8_t*)lpMultiByteStr, cbMultiByte);
}

View File

@@ -0,0 +1,234 @@
/**
* WinPR: Windows Portable Runtime
* Unicode Conversion (CRT)
*
* Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
* 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.
*/
#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>
#include <unicode/ucnv.h>
#include <unicode/ustring.h>
#include "unicode.h"
#include "../log.h"
#define TAG WINPR_TAG("unicode")
#define UCNV_CONVERT 1
int int_MultiByteToWideChar(UINT CodePage, DWORD dwFlags, LPCSTR lpMultiByteStr, int cbMultiByte,
LPWSTR lpWideCharStr, int cchWideChar)
{
const BOOL isNullTerminated = cbMultiByte < 0;
WINPR_UNUSED(dwFlags);
/* If cbMultiByte is 0, the function fails */
if ((cbMultiByte == 0) || (cbMultiByte < -1))
{
SetLastError(ERROR_INVALID_PARAMETER);
return 0;
}
size_t len = 0;
if (isNullTerminated)
len = strlen(lpMultiByteStr) + 1;
else
len = WINPR_ASSERTING_INT_CAST(size_t, cbMultiByte);
if (len >= INT_MAX)
{
SetLastError(ERROR_INVALID_PARAMETER);
return 0;
}
cbMultiByte = WINPR_ASSERTING_INT_CAST(int, len);
/*
* if cchWideChar is 0, the function returns the required buffer size
* in characters for lpWideCharStr and makes no use of the output parameter itself.
*/
{
UErrorCode error = U_ZERO_ERROR;
int32_t targetLength = -1;
switch (CodePage)
{
case CP_ACP:
case CP_UTF8:
break;
default:
WLog_ERR(TAG, "Unsupported encoding %u", CodePage);
SetLastError(ERROR_INVALID_PARAMETER);
return 0;
}
const int32_t targetCapacity = cchWideChar;
#if defined(UCNV_CONVERT)
char* targetStart = (char*)lpWideCharStr;
targetLength =
ucnv_convert("UTF-16LE", "UTF-8", targetStart, targetCapacity * (int32_t)sizeof(WCHAR),
lpMultiByteStr, cbMultiByte, &error);
if (targetLength > 0)
targetLength /= sizeof(WCHAR);
#else
WCHAR* targetStart = lpWideCharStr;
u_strFromUTF8(targetStart, targetCapacity, &targetLength, lpMultiByteStr, cbMultiByte,
&error);
#endif
switch (error)
{
case U_BUFFER_OVERFLOW_ERROR:
if (targetCapacity > 0)
{
cchWideChar = 0;
WLog_ERR(TAG, "insufficient buffer supplied, got %d, required %d",
targetCapacity, targetLength);
SetLastError(ERROR_INSUFFICIENT_BUFFER);
}
else
cchWideChar = targetLength;
break;
case U_STRING_NOT_TERMINATED_WARNING:
cchWideChar = targetLength;
break;
case U_ZERO_ERROR:
cchWideChar = targetLength;
break;
default:
WLog_WARN(TAG, "unexpected ICU error code %s [0x%08" PRIx32 "]", u_errorName(error),
WINPR_CXX_COMPAT_CAST(unsigned, error));
if (U_FAILURE(error))
{
WLog_ERR(TAG, "unexpected ICU error code %s [0x%08" PRIx32 "] is fatal",
u_errorName(error), WINPR_CXX_COMPAT_CAST(unsigned, error));
cchWideChar = 0;
SetLastError(ERROR_NO_UNICODE_TRANSLATION);
}
else
cchWideChar = targetLength;
break;
}
}
return cchWideChar;
}
int int_WideCharToMultiByte(UINT CodePage, WINPR_ATTR_UNUSED DWORD dwFlags, LPCWSTR lpWideCharStr,
int cchWideChar, LPSTR lpMultiByteStr, int cbMultiByte,
WINPR_ATTR_UNUSED LPCSTR lpDefaultChar,
WINPR_ATTR_UNUSED LPBOOL lpUsedDefaultChar)
{
/* If cchWideChar is 0, the function fails */
if ((cchWideChar == 0) || (cchWideChar < -1))
{
SetLastError(ERROR_INVALID_PARAMETER);
return 0;
}
/* If cchWideChar is -1, the string is null-terminated */
size_t len = 0;
if (cchWideChar == -1)
len = _wcslen(lpWideCharStr) + 1;
else
len = WINPR_ASSERTING_INT_CAST(size_t, cchWideChar);
if (len >= INT32_MAX)
{
SetLastError(ERROR_INVALID_PARAMETER);
return 0;
}
cchWideChar = WINPR_ASSERTING_INT_CAST(int, len);
/*
* if cbMultiByte is 0, the function returns the required buffer size
* in bytes for lpMultiByteStr and makes no use of the output parameter itself.
*/
{
UErrorCode error = U_ZERO_ERROR;
int32_t targetLength = -1;
switch (CodePage)
{
case CP_ACP:
case CP_UTF8:
break;
default:
WLog_ERR(TAG, "Unsupported encoding %u", CodePage);
SetLastError(ERROR_INVALID_PARAMETER);
return 0;
}
char* targetStart = lpMultiByteStr;
const int32_t targetCapacity = cbMultiByte;
#if defined(UCNV_CONVERT)
const char* str = (const char*)lpWideCharStr;
targetLength = ucnv_convert("UTF-8", "UTF-16LE", targetStart, targetCapacity, str,
cchWideChar * (int32_t)sizeof(WCHAR), &error);
#else
u_strToUTF8(targetStart, targetCapacity, &targetLength, lpWideCharStr, cchWideChar, &error);
#endif
switch (error)
{
case U_BUFFER_OVERFLOW_ERROR:
if (targetCapacity > 0)
{
WLog_ERR(TAG, "insufficient buffer supplied, got %d, required %d",
targetCapacity, targetLength);
cbMultiByte = 0;
SetLastError(ERROR_INSUFFICIENT_BUFFER);
}
else
cbMultiByte = targetLength;
break;
case U_STRING_NOT_TERMINATED_WARNING:
cbMultiByte = targetLength;
break;
case U_ZERO_ERROR:
cbMultiByte = targetLength;
break;
default:
WLog_WARN(TAG, "unexpected ICU error code %s [0x%08" PRIx32 "]", u_errorName(error),
WINPR_CXX_COMPAT_CAST(unsigned, error));
if (U_FAILURE(error))
{
WLog_ERR(TAG, "unexpected ICU error code %s [0x%08" PRIx32 "] is fatal",
u_errorName(error), WINPR_CXX_COMPAT_CAST(unsigned, error));
cbMultiByte = 0;
SetLastError(ERROR_NO_UNICODE_TRANSLATION);
}
else
cbMultiByte = targetLength;
break;
}
}
return cbMultiByte;
}