How can I copy a UnicodeString to a wchar_t array in a C++Builder Android app?

847 views Asked by At

I am using C++Builder 10.3 Rio developing a multi-platform app for Android.

I have an array of data as follows:

typedef struct recordstruct
{
    bool shop;
    bool bought;
    wchar_t description[80];
} recordtype;

recordtype MasterItems[MAXITEMS]=
{
    false,false,L"Apples",
    false,false,L"Apricots",
    false,false,L"Avocado",
...
...
};

I've copied this into a TEdit, and want to get the value back to the MasterItems array.

I used to use c_str() and mbstowcs() and strcpy()/wcscpy() etc.

How can I do this please ?

1

There are 1 answers

1
Remy Lebeau On BEST ANSWER

UnicodeString is a UTF-16 encoded string on all platforms. However, wchar_t is a 16bit type used for UTF-16 data only on Windows. On other platforms, wchar_t is a 32bit type used for UTF-32 data.

This is documented in Embarcadero's DocWiki:

String Literals char16_t and wchar_t on macOS and iOS
(Android is included, too)

On macOS and iOS, char16_t is not equivalent to wchar_t (as it is on Windows):

  • On Windows, wchar_t and char16_t are both double-byte characters.
  • On macOS, iOS, and Android, however, a wchar_t is a 4-byte character.

So, to declare UTF-16 constant strings, on Windows use either the L or the u prefix, whereas on macOS, iOS, and Android, use the u prefix.

Example on Windows:

UnicodeString(L"Text"), UnicodeString(u"Text")

Example on macOS, iOS, and Android:

UnicodeString(u"Text")

Using the L prefix for string literals on macOS, iOS, and Android is not, however, wrong. In this case, UTF-32 constant strings are converted to UTF-16 strings.

For portability, use the _D macro to write constant strings that are prefixed accordingly with L or u. Example:

UnicodeString(_D("Text"))

To ensure UTF-16 is used on all platforms, the System::WideChar type is an alias for wchar_t on Windows and char16_t on other platforms. UnicodeString is a container of WideChar elements.

So, if you use wchar_t for your array, then on non-Windows platforms you will need to first convert your UnicodeString to UTF-32 at runtime, such as with the RTL's UnicodeStringToUCS4String() function, before you can then copy that data into your array, eg:

typedef struct recordstruct
{
    bool shop;
    bool bought;
    wchar_t description[80];
} recordtype;

recordtype MasterItems[MAXITEMS]=
{
    false,false,L"Apples",
    false,false,L"Apricots",
    false,false,L"Avocado",
    ...
};

...

#if defined(WIDECHAR_IS_WCHAR) // WideChar = wchar_t = 2 bytes

StrLCopy(MasterItems[index].description, Edit1->Text.c_str(), std::size(MasterItems[index].description)-1); // -1 for null terminator

/* or:
UnicodeString s = Edit1->Text;
size_t len = std::min(s.Length(), std::size(MasterItems[index].destination)-1); // -1 for null terminator
std::copy_n(s.c_str(), len, MasterItems[index].destination);
MasterItems[index].destination[len] = L'\0';
*/

#elif defined(WIDECHAR_IS_CHAR16) // WideChar = char16_t, wchar_t = 4 bytes

UCS4String s = UnicodeStringToUCS4String(Edit1->Text);
size_t len = std::min(s.Length-1, std::size(MasterItems[index].destination)-1); // UCS4String::Length includes the null terminator!
std::copy_n(&s[0], len, MasterItems[index].destination);
MasterItems[index].destination[len] = L'\0';

#else

// unsupported wchar_t size!

#endif

Otherwise, if you want to ensure your array is always 16bit UTF-16 on all platforms, then you need to use char16_t or WideChar instead of wchar_t in your array. The u prefix creates a char16_t-based literal, and the RTL's _D() macro creates a WideChar-based literal (using L or u according to platform), eg:

typedef struct recordstruct
{
    bool shop;
    bool bought;
    char16_t description[80]; // or: System::WideChar
} recordtype;

recordtype MasterItems[MAXITEMS]=
{
    false,false,u"Apples", // or: _D("Apples")
    false,false,u"Apricots", // or: _D("Apricots")
    false,false,u"Avocado", // or: _D("Avocado")
    ...
};

...

StrLCopy(MasterItems[index].description, Edit1->Text.c_str(), std::size(MasterItems[index].description)-1); // -1 for null terminator

/* or:
UnicodeString s = Edit1->Text;
size_t len = std::min(s.Length(), std::size(MasterItems[index].description)-1); // -1 for null terminator
std::copy_n(s.c_str(), len, MasterItems[index].description);
MasterItems[index].description[len] = u'\0'; // or: _D('\0')
*/