VirtualBox

Changeset 33563 in vbox


Ignore:
Timestamp:
Oct 28, 2010 2:46:26 PM (14 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
67169
Message:

iprt:ministring: Added the java-style equals() and equalsIgnoreCase() as equals() can optimize the comparison by first checking if the length is the same (compare() cannot as it needs to determin the ordering). Added appendCodePoint() for UTF-8. Fixed the incorrect assumption in toUpper and toLower that the string length remained unchanged - the string might shrink as the folded code points may have a shorter encoding. Added testcase that verifies that a code point will not grow during folding and that have a stable encoding length after it has been changed in a folding.

Location:
trunk
Files:
5 edited
1 copied

Legend:

Unmodified
Added
Removed
  • trunk/include/iprt/cpp/ministring.h

    r33074 r33563  
    6565    MiniString()
    6666        : m_psz(NULL),
    67           m_cbLength(0),
     67          m_cch(0),
    6868          m_cbAllocated(0)
    6969    {
     
    118118    size_t length() const
    119119    {
    120         return m_cbLength;
     120        return m_cch;
    121121    }
    122122
     
    149149    {
    150150        if (    cb != m_cbAllocated
    151              && cb > m_cbLength + 1
     151             && cb > m_cch + 1
    152152           )
    153153        {
     
    235235     * Appends the given character to "this".
    236236     *
    237      * @param   c               The character to append.
     237     * @param   ch              The character to append.
    238238     *
    239239     * @throws  std::bad_alloc  On allocation error.  The object is left unchanged.
     
    241241     * @returns Reference to the object.
    242242     */
    243     MiniString &append(char c);
     243    MiniString &append(char ch);
     244
     245    /**
     246     * Appends the given unicode code point to "this".
     247     *
     248     * @param   uc              The unicode code point to append.
     249     *
     250     * @throws  std::bad_alloc  On allocation error.  The object is left unchanged.
     251     *
     252     * @returns Reference to the object.
     253     */
     254    MiniString &appendCodePoint(RTUNICP uc);
    244255
    245256    /**
     
    287298    {
    288299        if (length())
     300        {
     301            /* Folding an UTF-8 string may result in a shorter encoding (see
     302               testcase), so recalculate the length afterwars. */
    289303            ::RTStrToUpper(m_psz);
     304            size_t cchNew = strlen(m_psz);
     305            Assert(cchNew <= m_cch);
     306            m_cch = cchNew;
     307        }
    290308        return *this;
    291309    }
     
    299317    {
    300318        if (length())
     319        {
     320            /* Folding an UTF-8 string may result in a shorter encoding (see
     321               testcase), so recalculate the length afterwars. */
    301322            ::RTStrToLower(m_psz);
     323            size_t cchNew = strlen(m_psz);
     324            Assert(cchNew <= m_cch);
     325            m_cch = cchNew;
     326        }
    302327        return *this;
    303328    }
     
    361386        if (m_psz)
    362387        {
    363             m_cbLength = strlen(m_psz);
    364             m_cbAllocated = m_cbLength + 1; /* (Required for the Utf8Str::asOutParam case) */
     388            m_cch = strlen(m_psz);
     389            m_cbAllocated = m_cch + 1; /* (Required for the Utf8Str::asOutParam case) */
    365390        }
    366391        else
    367392        {
    368             m_cbLength = 0;
     393            m_cch = 0;
    369394            m_cbAllocated = 0;
    370395        }
     
    434459    }
    435460
     461    /**
     462     * Compares the two strings.
     463     *
     464     * @returns true if equal, false if not.
     465     * @param   that    The string to compare with.
     466     */
     467    bool equals(const MiniString &that) const
     468    {
     469        return that.length() == length()
     470            && memcmp(that.m_psz, m_psz, length()) == 0;
     471    }
     472
     473    /**
     474     * Compares the two strings.
     475     *
     476     * @returns true if equal, false if not.
     477     * @param   pszThat The string to compare with.
     478     */
     479    bool equals(const char *pszThat) const
     480    {
     481        return RTStrCmp(pszThat, m_psz) == 0;
     482    }
     483
     484    /**
     485     * Compares the two strings ignoring differences in case.
     486     *
     487     * @returns true if equal, false if not.
     488     * @param   that    The string to compare with.
     489     */
     490    bool equalsIgnoreCase(const MiniString &that) const
     491    {
     492        /* Unfolded upper and lower case characters may require different
     493           amount of encoding space, so the length optimization doesn't work. */
     494        return RTStrICmp(that.m_psz, m_psz) == 0;
     495    }
     496
     497    /**
     498     * Compares the two strings ignoring differences in case.
     499     *
     500     * @returns true if equal, false if not.
     501     * @param   pszThat The string to compare with.
     502     */
     503    bool equalsIgnoreCase(const char *pszThat) const
     504    {
     505        return RTStrICmp(pszThat, m_psz) == 0;
     506    }
     507
    436508    /** @name Comparison operators.
    437509     * @{  */
    438     bool operator==(const MiniString &that) const { return !compare(that); }
    439     bool operator!=(const MiniString &that) const { return !!compare(that); }
     510    bool operator==(const MiniString &that) const { return equals(that); }
     511    bool operator!=(const MiniString &that) const { return !equals(that); }
    440512    bool operator<( const MiniString &that) const { return compare(that) < 0; }
    441513    bool operator>( const MiniString &that) const { return compare(that) > 0; }
    442514
    443     bool operator==(const char *that) const       { return !compare(that); }
    444     bool operator!=(const char *that) const       { return !!compare(that); }
    445     bool operator<( const char *that) const       { return compare(that) < 0; }
    446     bool operator>( const char *that) const       { return compare(that) > 0; }
     515    bool operator==(const char *pszThat) const    { return equals(pszThat); }
     516    bool operator!=(const char *pszThat) const    { return !equals(pszThat); }
     517    bool operator<( const char *pszThat) const    { return compare(pszThat) < 0; }
     518    bool operator>( const char *pszThat) const    { return compare(pszThat) > 0; }
    447519    /** @} */
    448520
     
    567639            RTStrFree(m_psz);
    568640            m_psz = NULL;
    569             m_cbLength = 0;
     641            m_cch = 0;
    570642            m_cbAllocated = 0;
    571643        }
     
    591663    void copyFrom(const MiniString &s)
    592664    {
    593         if ((m_cbLength = s.m_cbLength))
    594         {
    595             m_cbAllocated = m_cbLength + 1;
     665        if ((m_cch = s.m_cch))
     666        {
     667            m_cbAllocated = m_cch + 1;
    596668            m_psz = (char *)RTStrAlloc(m_cbAllocated);
    597669            if (RT_LIKELY(m_psz))
     
    599671            else
    600672            {
    601                 m_cbLength = 0;
     673                m_cch = 0;
    602674                m_cbAllocated = 0;
    603675#ifdef RT_EXCEPTIONS_ENABLED
     
    631703        if (pcsz && *pcsz)
    632704        {
    633             m_cbLength = strlen(pcsz);
    634             m_cbAllocated = m_cbLength + 1;
     705            m_cch = strlen(pcsz);
     706            m_cbAllocated = m_cch + 1;
    635707            m_psz = (char *)RTStrAlloc(m_cbAllocated);
    636708            if (RT_LIKELY(m_psz))
     
    638710            else
    639711            {
    640                 m_cbLength = 0;
     712                m_cch = 0;
    641713                m_cbAllocated = 0;
    642714#ifdef RT_EXCEPTIONS_ENABLED
     
    647719        else
    648720        {
    649             m_cbLength = 0;
     721            m_cch = 0;
    650722            m_cbAllocated = 0;
    651723            m_psz = NULL;
     
    654726
    655727    char    *m_psz;                     /**< The string buffer. */
    656     size_t  m_cbLength;                 /**< strlen(m_psz) - i.e. no terminator included. */
     728    size_t  m_cch;                      /**< strlen(m_psz) - i.e. no terminator included. */
    657729    size_t  m_cbAllocated;              /**< Size of buffer that m_psz points to; at least m_cbLength + 1. */
    658730};
  • trunk/src/VBox/Main/glue/string.cpp

    r33073 r33563  
    115115                                  &m_psz,           // char **ppsz: output buffer
    116116                                  0,                // size_t cch: if 0, func allocates buffer in *ppsz
    117                                   &m_cbLength);     // size_t *pcch: receives the size of the output string, excluding the terminator.
     117                                  &m_cch);          // size_t *pcch: receives the size of the output string, excluding the terminator.
    118118        if (RT_FAILURE(vrc))
    119119        {
     
    124124
    125125            // @todo what do we do with bad input strings? throw also? for now just keep an empty string
    126             m_cbLength = 0;
     126            m_cch = 0;
    127127            m_cbAllocated = 0;
    128128            m_psz = NULL;
    129129        }
    130130        else
    131             m_cbAllocated = m_cbLength + 1;
     131            m_cbAllocated = m_cch + 1;
    132132    }
    133133    else
    134134    {
    135         m_cbLength = 0;
     135        m_cch = 0;
    136136        m_cbAllocated = 0;
    137137        m_psz = NULL;
     
    143143    if (!format || !*format)
    144144    {
    145         m_cbLength = 0;
     145        m_cch = 0;
    146146        m_cbAllocated = 0;
    147147        m_psz = NULL;
     
    149149    else
    150150    {
    151         m_cbLength = RTStrAPrintfV(&m_psz, format, args);
    152         m_cbAllocated = m_cbLength + 1;
     151        m_cch = RTStrAPrintfV(&m_psz, format, args);
     152        m_cbAllocated = m_cch + 1;
    153153    }
    154154}
  • trunk/src/VBox/Runtime/common/string/ministring.cpp

    r30318 r33563  
    88
    99/*
    10  * Copyright (C) 2007-2009 Oracle Corporation
     10 * Copyright (C) 2007-2010 Oracle Corporation
    1111 *
    1212 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    2828 */
    2929
     30
     31/*******************************************************************************
     32*   Header Files                                                               *
     33*******************************************************************************/
    3034#include <iprt/cpp/ministring.h>
    31 
    3235using namespace iprt;
    3336
     37
     38/*******************************************************************************
     39*   Global Variables                                                           *
     40*******************************************************************************/
    3441const size_t MiniString::npos = ~(size_t)0;
    3542
     43/*******************************************************************************
     44*   Defined Constants And Macros                                               *
     45*******************************************************************************/
     46/** Allocation block alignment used when appending bytes to a string. */
     47#define IPRT_MINISTRING_APPEND_ALIGNMENT    64
     48
     49
    3650MiniString &MiniString::append(const MiniString &that)
    3751{
    38     size_t lenThat = that.length();
    39     if (lenThat)
    40     {
    41         size_t lenThis = length();
    42         size_t cbBoth = lenThis + lenThat + 1;
    43 
    44         reserve(cbBoth);
    45             // calls realloc(cbBoth) and sets m_cbAllocated; may throw bad_alloc.
    46 #ifndef RT_EXCEPTIONS_ENABLED
    47         AssertRelease(capacity() >= cbBoth);
    48 #endif
    49 
    50         memcpy(m_psz + lenThis, that.m_psz, lenThat);
    51         m_psz[lenThis + lenThat] = '\0';
    52         m_cbLength = cbBoth - 1;
     52    size_t cchThat = that.length();
     53    if (cchThat)
     54    {
     55        size_t cchThis = length();
     56        size_t cchBoth = cchThis + cchThat;
     57
     58        if (cchBoth >= m_cbAllocated)
     59        {
     60            reserve(RT_ALIGN_Z(cchBoth + 1, IPRT_MINISTRING_APPEND_ALIGNMENT));
     61            // calls realloc(cchBoth + 1) and sets m_cbAllocated; may throw bad_alloc.
     62#ifndef RT_EXCEPTIONS_ENABLED
     63            AssertRelease(capacity() > cchBoth);
     64#endif
     65        }
     66
     67        memcpy(m_psz + cchThis, that.m_psz, cchThat);
     68        m_psz[cchBoth] = '\0';
     69        m_cch = cchBoth;
    5370    }
    5471    return *this;
     
    6178    {
    6279        size_t cchThis = length();
    63         size_t cbBoth = cchThis + cchThat + 1;
    64 
    65         reserve(cbBoth);
     80        size_t cchBoth = cchThis + cchThat;
     81
     82        if (cchBoth >= m_cbAllocated)
     83        {
     84            reserve(RT_ALIGN_Z(cchBoth + 1, IPRT_MINISTRING_APPEND_ALIGNMENT));
     85            // calls realloc(cchBoth + 1) and sets m_cbAllocated; may throw bad_alloc.
     86#ifndef RT_EXCEPTIONS_ENABLED
     87            AssertRelease(capacity() > cchBoth);
     88#endif
     89        }
     90
     91        memcpy(&m_psz[cchThis], pszThat, cchThat);
     92        m_psz[cchBoth] = '\0';
     93        m_cch = cchBoth;
     94    }
     95    return *this;
     96}
     97
     98MiniString& MiniString::append(char ch)
     99{
     100    Assert((unsigned char)ch < 0x80);                  /* Don't create invalid UTF-8. */
     101    if (ch)
     102    {
     103        // allocate in chunks of 20 in case this gets called several times
     104        if (m_cch + 1 >= m_cbAllocated)
     105        {
     106            reserve(RT_ALIGN_Z(m_cch + 2, IPRT_MINISTRING_APPEND_ALIGNMENT));
    66107            // calls realloc(cbBoth) and sets m_cbAllocated; may throw bad_alloc.
    67108#ifndef RT_EXCEPTIONS_ENABLED
    68         AssertRelease(capacity() >= cbBoth);
    69 #endif
    70 
    71         memcpy(m_psz + cchThis, pszThat, cchThat);
    72         m_psz[cbBoth - 1] = '\0';
    73         m_cbLength = cbBoth - 1;
    74     }
    75     return *this;
    76 }
    77 
    78 MiniString& MiniString::append(char c)
    79 {
    80     if (c)
    81     {
    82         // allocate in chunks of 20 in case this gets called several times
    83         if (m_cbLength + 1 >= m_cbAllocated)
    84         {
    85             reserve(m_cbLength + 10);
    86             // calls realloc(cbBoth) and sets m_cbAllocated; may throw bad_alloc.
    87 #ifndef RT_EXCEPTIONS_ENABLED
    88             AssertRelease(capacity() >= m_cbLength + 1);
    89 #endif
    90         }
    91 
    92         m_psz[m_cbLength] = c;
    93         m_psz[m_cbLength + 1] = '\0';
    94         ++m_cbLength;
    95     }
     109            AssertRelease(capacity() > m_cch + 1);
     110#endif
     111        }
     112
     113        m_psz[m_cch] = ch;
     114        m_psz[++m_cch] = '\0';
     115    }
     116    return *this;
     117}
     118
     119MiniString &MiniString::appendCodePoint(RTUNICP uc)
     120{
     121    /*
     122     * Single byte encoding.
     123     */
     124    if (uc < 0x80)
     125        return MiniString::append((char)uc);
     126
     127    /*
     128     * Multibyte encoding.
     129     * Assume max encoding length when resizing the string, that's simpler.
     130     */
     131    AssertReturn(uc <= UINT32_C(0x7fffffff), *this);
     132
     133    if (m_cch + 6 >= m_cbAllocated)
     134    {
     135        reserve(RT_ALIGN_Z(m_cch + 6 + 1, IPRT_MINISTRING_APPEND_ALIGNMENT));
     136        // calls realloc(cbBoth) and sets m_cbAllocated; may throw bad_alloc.
     137#ifndef RT_EXCEPTIONS_ENABLED
     138        AssertRelease(capacity() > m_cch + 6);
     139#endif
     140    }
     141
     142    char *pszNext = RTStrPutCp(&m_psz[m_cch], uc);
     143    m_cch = pszNext - m_psz;
     144    *pszNext = '\0';
     145
    96146    return *this;
    97147}
     
    148198#endif
    149199                memcpy(ret.m_psz, pFirst, cbCopy);
    150                 ret.m_cbLength = cbCopy;
     200                ret.m_cch = cbCopy;
    151201                ret.m_psz[cbCopy] = '\0';
    152202            }
  • trunk/src/VBox/Runtime/testcase/Makefile.kmk

    r33426 r33563  
    6868        tstRTHeapSimple \
    6969        tstRTInlineAsm \
     70        tstIprtMiniString \
    7071        tstLdr \
    7172        tstLdrLoad \
     
    257258tstRTInlineAsmPIC3_DEFS = PIC
    258259
     260tstIprtMiniString_TEMPLATE = VBOXR3TSTEXE
     261tstIprtMiniString_SOURCES = tstIprtMiniString.cpp
     262
    259263tstLdr_SOURCES = tstLdr.cpp
    260264
  • trunk/src/VBox/Runtime/testcase/tstIprtMiniString.cpp

    r33487 r33563  
    11/* $Id$ */
    22/** @file
    3  * IPRT Testcase - UTF-8 and UTF-16 string conversions.
     3 * IPRT Testcase - iprt::MiniString.
    44 */
    55
    66/*
    7  * Copyright (C) 2006-2007 Oracle Corporation
     7 * Copyright (C) 2006-2010 Oracle Corporation
    88 *
    99 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    2828*   Header Files                                                               *
    2929*******************************************************************************/
     30#include <iprt/cpp/ministring.h>
     31
     32#include <iprt/err.h>
     33#include <iprt/mem.h>
    3034#include <iprt/string.h>
     35#include <iprt/test.h>
    3136#include <iprt/uni.h>
    32 #include <iprt/initterm.h>
    33 #include <iprt/uuid.h>
    34 #include <iprt/time.h>
    35 #include <iprt/stream.h>
    36 #include <iprt/alloc.h>
    37 #include <iprt/assert.h>
    38 #include <iprt/err.h>
    39 #include <iprt/test.h>
    40 #include <iprt/cpp/ministring.h>
    41 
    42 #include <stdlib.h> /** @todo use our random. */
    43 
    44 
    45 
    46 /**
    47  * Generate a random codepoint for simple UTF-16 encoding.
    48  */
    49 static RTUTF16 GetRandUtf16(void)
    50 {
    51     RTUTF16 wc;
    52     do
    53     {
    54         wc = (RTUTF16)((long long)rand() * 0xffff / RAND_MAX);
    55     } while ((wc >= 0xd800 && wc <= 0xdfff) || wc == 0);
    56     return wc;
    57 }
    58 
    59 
    60 /**
    61  *
    62  */
     37
     38
     39
    6340static void test1(RTTEST hTest)
    6441{
    65     static const char s_szBadString1[] = "Bad \xe0\x13\x0";
    66     static const char s_szBadString2[] = "Bad \xef\xbf\xc3";
    67     int rc;
    68     char *pszUtf8;
    69     char *pszCurrent;
    70     PRTUTF16 pwsz;
    71     PRTUTF16 pwszRand;
    72 
    73     /*
    74      * Invalid UTF-8 to UCS-2 test.
    75      */
    76     RTTestSub(hTest, "Feeding bad UTF-8 to RTStrToUtf16");
    77     rc = RTStrToUtf16(s_szBadString1, &pwsz);
    78     RTTEST_CHECK_MSG(hTest, rc == VERR_NO_TRANSLATION || rc == VERR_INVALID_UTF8_ENCODING,
    79                      (hTest, "Conversion of first bad UTF-8 string to UTF-16 apparantly succeeded. It shouldn't. rc=%Rrc\n", rc));
    80     rc = RTStrToUtf16(s_szBadString2, &pwsz);
    81     RTTEST_CHECK_MSG(hTest, rc == VERR_NO_TRANSLATION || rc == VERR_INVALID_UTF8_ENCODING,
    82                      (hTest, "Conversion of second bad UTF-8 strings to UTF-16 apparantly succeeded. It shouldn't. rc=%Rrc\n", rc));
    83 
    84     /*
    85      * Test current CP convertion.
    86      */
    87     RTTestSub(hTest, "Rand UTF-16 -> UTF-8 -> CP -> UTF-8");
    88     pwszRand = (PRTUTF16)RTMemAlloc(31 * sizeof(*pwsz));
    89     srand((unsigned)RTTimeNanoTS());
    90     for (int i = 0; i < 30; i++)
    91         pwszRand[i] = GetRandUtf16();
    92     pwszRand[30] = 0;
    93 
    94     rc = RTUtf16ToUtf8(pwszRand, &pszUtf8);
    95     if (rc == VINF_SUCCESS)
    96     {
    97         rc = RTStrUtf8ToCurrentCP(&pszCurrent, pszUtf8);
    98         if (rc == VINF_SUCCESS)
    99         {
    100             rc = RTStrCurrentCPToUtf8(&pszUtf8, pszCurrent);
    101             if (rc == VINF_SUCCESS)
    102                 RTTestPassed(hTest, "Random UTF-16 -> UTF-8 -> Current -> UTF-8 successful.\n");
    103             else
    104                 RTTestFailed(hTest, "%d: The third part of random UTF-16 -> UTF-8 -> Current -> UTF-8 failed with return value %Rrc.",
    105                              __LINE__, rc);
    106         }
    107         else if (rc == VERR_NO_TRANSLATION)
    108             RTTestPassed(hTest, "The second part of random UTF-16 -> UTF-8 -> Current -> UTF-8 returned VERR_NO_TRANSLATION.  This is probably as it should be.\n");
    109         else
    110             RTTestFailed(hTest, "%d: The second part of random UTF-16 -> UTF-8 -> Current -> UTF-8 failed with return value %Rrc.",
    111                          __LINE__, rc);
    112     }
    113     else
    114         RTTestFailed(hTest, "%d: The first part of random UTF-16 -> UTF-8 -> Current -> UTF-8 failed with return value %Rrc.",
    115                      __LINE__, rc);
    116 
    117     /*
    118      * Generate a new random string.
    119      */
    120     RTTestSub(hTest, "Random UTF-16 -> UTF-8 -> UTF-16");
    121     pwszRand = (PRTUTF16)RTMemAlloc(31 * sizeof(*pwsz));
    122     srand((unsigned)RTTimeNanoTS());
    123     for (int i = 0; i < 30; i++)
    124         pwszRand[i] = GetRandUtf16();
    125     pwszRand[30] = 0;
    126     rc = RTUtf16ToUtf8(pwszRand, &pszUtf8);
    127     if (rc == VINF_SUCCESS)
    128     {
    129         rc = RTStrToUtf16(pszUtf8, &pwsz);
    130         if (rc == VINF_SUCCESS)
    131         {
    132             int i;
    133             for (i = 0; pwszRand[i] == pwsz[i] && pwsz[i] != 0; i++)
    134                 /* nothing */;
    135             if (pwszRand[i] == pwsz[i] && pwsz[i] == 0)
    136                 RTTestPassed(hTest, "Random UTF-16 -> UTF-8 -> UTF-16 successful.\n");
    137             else
    138             {
    139                 RTTestFailed(hTest, "%d: The second part of random UTF-16 -> UTF-8 -> UTF-16 failed.", __LINE__);
    140                 RTTestPrintf(hTest, RTTESTLVL_FAILURE, "First differing character is at position %d and has the value %x.\n", i, pwsz[i]);
    141             }
    142         }
    143         else
    144             RTTestFailed(hTest, "%d: The second part of random UTF-16 -> UTF-8 -> UTF-16 failed with return value %Rrc.",
    145                          __LINE__, rc);
    146     }
    147     else
    148         RTTestFailed(hTest, "%d: The first part of random UTF-16 -> UTF-8 -> UTF-16 failed with return value %Rrc.",
    149                      __LINE__, rc);
    150 
    151     /*
    152      * Generate yet another random string and convert it to a buffer.
    153      */
    154     RTTestSub(hTest, "Random RTUtf16ToUtf8Ex + RTStrToUtf16");
    155     pwszRand = (PRTUTF16)RTMemAlloc(31 * sizeof(*pwsz));
    156     srand((unsigned)RTTimeNanoTS());
    157     for (int i = 0; i < 30; i++)
    158         pwszRand[i] = GetRandUtf16();
    159     pwszRand[30] = 0;
    160 
    161     char szUtf8Array[120];
    162     char *pszUtf8Array  = szUtf8Array;
    163     rc = RTUtf16ToUtf8Ex(pwszRand, RTSTR_MAX, &pszUtf8Array, 120, NULL);
    164     if (rc == 0)
    165     {
    166         rc = RTStrToUtf16(pszUtf8Array, &pwsz);
    167         if (rc == 0)
    168         {
    169             int i;
    170             for (i = 0; pwszRand[i] == pwsz[i] && pwsz[i] != 0; i++)
    171                 ;
    172             if (pwsz[i] == 0 && i >= 8)
    173                 RTTestPassed(hTest, "Random UTF-16 -> fixed length UTF-8 -> UTF-16 successful.\n");
    174             else
    175             {
    176                 RTTestFailed(hTest, "%d: Incorrect conversion of UTF-16 -> fixed length UTF-8 -> UTF-16.\n", __LINE__);
    177                 RTTestPrintf(hTest, RTTESTLVL_FAILURE, "First differing character is at position %d and has the value %x.\n", i, pwsz[i]);
    178             }
    179         }
    180         else
    181             RTTestFailed(hTest, "%d: The second part of random UTF-16 -> fixed length UTF-8 -> UTF-16 failed with return value %Rrc.\n", __LINE__, rc);
    182     }
    183     else
    184         RTTestFailed(hTest, "%d: The first part of random UTF-16 -> fixed length UTF-8 -> UTF-16 failed with return value %Rrc.\n", __LINE__, rc);
    185 
    186     /*
    187      * And again.
    188      */
    189     RTTestSub(hTest, "Random RTUtf16ToUtf8 + RTStrToUtf16Ex");
    190     pwszRand = (PRTUTF16)RTMemAlloc(31 * sizeof(*pwsz));
    191     srand((unsigned)RTTimeNanoTS());
    192     for (int i = 0; i < 30; i++)
    193         pwszRand[i] = GetRandUtf16();
    194     pwszRand[30] = 0;
    195 
    196     RTUTF16     wszBuf[70];
    197     PRTUTF16    pwsz2Buf = wszBuf;
    198     rc = RTUtf16ToUtf8(pwszRand, &pszUtf8);
    199     if (rc == 0)
    200     {
    201         rc = RTStrToUtf16Ex(pszUtf8, RTSTR_MAX, &pwsz2Buf, 70, NULL);
    202         if (rc == 0)
    203         {
    204             int i;
    205             for (i = 0; pwszRand[i] == pwsz2Buf[i] && pwsz2Buf[i] != 0; i++)
    206                 ;
    207             if (pwszRand[i] == 0 && pwsz2Buf[i] == 0)
    208                 RTTestPassed(hTest, "Random UTF-16 -> UTF-8 -> fixed length UTF-16 successful.\n");
    209             else
    210             {
    211                 RTTestFailed(hTest, "%d: Incorrect conversion of random UTF-16 -> UTF-8 -> fixed length UTF-16.\n", __LINE__);
    212                 RTTestPrintf(hTest, RTTESTLVL_FAILURE, "First differing character is at position %d and has the value %x.\n", i, pwsz2Buf[i]);
    213             }
    214         }
    215         else
    216             RTTestFailed(hTest, "%d: The second part of random UTF-16 -> UTF-8 -> fixed length UTF-16 failed with return value %Rrc.\n", __LINE__, rc);
    217     }
    218     else
    219         RTTestFailed(hTest, "%d: The first part of random UTF-16 -> UTF-8 -> fixed length UTF-16 failed with return value %Rrc.\n",
    220                      __LINE__, rc);
    221     pwszRand = (PRTUTF16)RTMemAlloc(31 * sizeof(*pwsz));
    222     srand((unsigned)RTTimeNanoTS());
    223     for (int i = 0; i < 30; i++)
    224         pwszRand[i] = GetRandUtf16();
    225     pwszRand[30] = 0;
    226 
    227     rc = RTUtf16ToUtf8Ex(pwszRand, RTSTR_MAX, &pszUtf8Array, 20, NULL);
    228     if (rc == VERR_BUFFER_OVERFLOW)
    229         RTTestPassed(hTest, "Random UTF-16 -> fixed length UTF-8 with too short buffer successfully rejected.\n");
    230     else
    231         RTTestFailed(hTest, "%d: Random UTF-16 -> fixed length UTF-8 with too small buffer returned value %d instead of VERR_BUFFER_OVERFLOW.\n",
    232                      __LINE__, rc);
    233 
    234     /*
    235      * last time...
    236      */
    237     RTTestSub(hTest, "Random RTUtf16ToUtf8 + RTStrToUtf16Ex");
    238     pwszRand = (PRTUTF16)RTMemAlloc(31 * sizeof(*pwsz));
    239     srand((unsigned)RTTimeNanoTS());
    240     for (int i = 0; i < 30; i++)
    241         pwszRand[i] = GetRandUtf16();
    242     pwszRand[30] = 0;
    243 
    244     rc = RTUtf16ToUtf8(pwszRand, &pszUtf8);
    245     if (rc == VINF_SUCCESS)
    246     {
    247         rc = RTStrToUtf16Ex(pszUtf8, RTSTR_MAX, &pwsz2Buf, 20, NULL);
    248         if (rc == VERR_BUFFER_OVERFLOW)
    249             RTTestPassed(hTest, "Random UTF-16 -> UTF-8 -> fixed length UTF-16 with too short buffer successfully rejected.\n");
    250         else
    251             RTTestFailed(hTest, "%d: The second part of random UTF-16 -> UTF-8 -> fixed length UTF-16 with too short buffer returned value %Rrc instead of VERR_BUFFER_OVERFLOW.\n",
    252                          __LINE__, rc);
    253     }
    254     else
    255         RTTestFailed(hTest, "%d:The first part of random UTF-16 -> UTF-8 -> fixed length UTF-16 failed with return value %Rrc.\n",
    256                      __LINE__, rc);
    257 
    258 
    259     RTTestSubDone(hTest);
    260 }
    261 
    262 
    263 static RTUNICP g_uszAll[0x110000 - 1 - 0x800 - 2 + 1];
    264 static RTUTF16 g_wszAll[0xfffe - (0xe000 - 0xd800) + (0x110000 - 0x10000) * 2];
    265 static char     g_szAll[0x7f + (0x800 - 0x80) * 2 + (0xfffe - 0x800 - (0xe000 - 0xd800))* 3 + (0x110000 - 0x10000) * 4 + 1];
    266 
    267 static void whereami(int cBits, size_t off)
    268 {
    269     if (cBits == 8)
    270     {
    271         if (off < 0x7f)
    272             RTTestPrintf(NIL_RTTEST, RTTESTLVL_FAILURE, "UTF-8 U+%#x\n", off + 1);
    273         else if (off < 0xf7f)
    274             RTTestPrintf(NIL_RTTEST, RTTESTLVL_FAILURE, "UTF-8 U+%#x\n", (off - 0x7f) / 2 + 0x80);
    275         else if (off < 0x27f7f)
    276             RTTestPrintf(NIL_RTTEST, RTTESTLVL_FAILURE, "UTF-8 U+%#x\n", (off - 0xf7f) / 3 + 0x800);
    277         else if (off < 0x2df79)
    278             RTTestPrintf(NIL_RTTEST, RTTESTLVL_FAILURE, "UTF-8 U+%#x\n", (off - 0x27f7f) / 3 + 0xe000);
    279         else if (off < 0x42df79)
    280             RTTestPrintf(NIL_RTTEST, RTTESTLVL_FAILURE, "UTF-8 U+%#x\n", (off - 0x2df79) / 4 + 0x10000);
    281         else
    282             RTTestPrintf(NIL_RTTEST, RTTESTLVL_FAILURE, "UTF-8 ???\n");
    283     }
    284     else if (cBits == 16)
    285     {
    286         if (off < 0xd7ff*2)
    287             RTTestPrintf(NIL_RTTEST, RTTESTLVL_FAILURE, "UTF-16 U+%#x\n", off / 2 + 1);
    288         else if (off < 0xf7fd*2)
    289             RTTestPrintf(NIL_RTTEST, RTTESTLVL_FAILURE, "UTF-16 U+%#x\n", (off - 0xd7ff*2) / 2 + 0xe000);
    290         else if (off < 0x20f7fd)
    291             RTTestPrintf(NIL_RTTEST, RTTESTLVL_FAILURE, "UTF-16 U+%#x\n", (off - 0xf7fd*2) / 4 + 0x10000);
    292         else
    293             RTTestPrintf(NIL_RTTEST, RTTESTLVL_FAILURE, "UTF-16 ???\n");
    294     }
    295     else
    296     {
    297         if (off < (0xd800 - 1) * sizeof(RTUNICP))
    298             RTTestPrintf(NIL_RTTEST, RTTESTLVL_FAILURE, "RTUNICP U+%#x\n", off / sizeof(RTUNICP) + 1);
    299         else if (off < (0xfffe - 0x800 - 1) * sizeof(RTUNICP))
    300             RTTestPrintf(NIL_RTTEST, RTTESTLVL_FAILURE, "RTUNICP U+%#x\n", off / sizeof(RTUNICP) + 0x800 + 1);
    301         else
    302             RTTestPrintf(NIL_RTTEST, RTTESTLVL_FAILURE, "RTUNICP U+%#x\n", off / sizeof(RTUNICP) + 0x800 + 1 + 2);
    303     }
    304 }
    305 
    306 int mymemcmp(const void *pv1, const void *pv2, size_t cb, int cBits)
    307 {
    308     const uint8_t  *pb1 = (const uint8_t *)pv1;
    309     const uint8_t  *pb2 = (const uint8_t *)pv2;
    310     for (size_t off = 0; off < cb; off++)
    311     {
    312         if (pb1[off] != pb2[off])
    313         {
    314             RTTestPrintf(NIL_RTTEST, RTTESTLVL_FAILURE, "mismatch at %#x: ", off);
    315             whereami(cBits, off);
    316             RTTestPrintf(NIL_RTTEST, RTTESTLVL_FAILURE, " %#x: %02x != %02x!\n", off-1, pb1[off-1], pb2[off-1]);
    317             RTTestPrintf(NIL_RTTEST, RTTESTLVL_FAILURE, "*%#x: %02x != %02x!\n", off, pb1[off], pb2[off]);
    318             RTTestPrintf(NIL_RTTEST, RTTESTLVL_FAILURE, " %#x: %02x != %02x!\n", off+1, pb1[off+1], pb2[off+1]);
    319             RTTestPrintf(NIL_RTTEST, RTTESTLVL_FAILURE, " %#x: %02x != %02x!\n", off+2, pb1[off+2], pb2[off+2]);
    320             RTTestPrintf(NIL_RTTEST, RTTESTLVL_FAILURE, " %#x: %02x != %02x!\n", off+3, pb1[off+3], pb2[off+3]);
    321             RTTestPrintf(NIL_RTTEST, RTTESTLVL_FAILURE, " %#x: %02x != %02x!\n", off+4, pb1[off+4], pb2[off+4]);
    322             RTTestPrintf(NIL_RTTEST, RTTESTLVL_FAILURE, " %#x: %02x != %02x!\n", off+5, pb1[off+5], pb2[off+5]);
    323             RTTestPrintf(NIL_RTTEST, RTTESTLVL_FAILURE, " %#x: %02x != %02x!\n", off+6, pb1[off+6], pb2[off+6]);
    324             RTTestPrintf(NIL_RTTEST, RTTESTLVL_FAILURE, " %#x: %02x != %02x!\n", off+7, pb1[off+7], pb2[off+7]);
    325             RTTestPrintf(NIL_RTTEST, RTTESTLVL_FAILURE, " %#x: %02x != %02x!\n", off+8, pb1[off+8], pb2[off+8]);
    326             RTTestPrintf(NIL_RTTEST, RTTESTLVL_FAILURE, " %#x: %02x != %02x!\n", off+9, pb1[off+9], pb2[off+9]);
    327             return 1;
    328         }
    329     }
    330     return 0;
    331 }
    332 
    333 
    334 void InitStrings()
    335 {
    336     /*
    337      * Generate unicode string containing all the legal UTF-16 codepoints, both UTF-16 and UTF-8 version.
    338      */
    339     /* the simple code point array first */
    340     unsigned i = 0;
    341     RTUNICP  uc = 1;
    342     while (uc < 0xd800)
    343         g_uszAll[i++] = uc++;
    344     uc = 0xe000;
    345     while (uc < 0xfffe)
    346         g_uszAll[i++] = uc++;
    347     uc = 0x10000;
    348     while (uc < 0x110000)
    349         g_uszAll[i++] = uc++;
    350     g_uszAll[i++] = 0;
    351     Assert(RT_ELEMENTS(g_uszAll) == i);
    352 
    353     /* the utf-16 one */
    354     i = 0;
    355     uc = 1;
    356     //RTPrintf("tstUtf8: %#x=%#x", i, uc);
    357     while (uc < 0xd800)
    358         g_wszAll[i++] = uc++;
    359     uc = 0xe000;
    360     //RTPrintf(" %#x=%#x", i, uc);
    361     while (uc < 0xfffe)
    362         g_wszAll[i++] = uc++;
    363     uc = 0x10000;
    364     //RTPrintf(" %#x=%#x", i, uc);
    365     while (uc < 0x110000)
    366     {
    367         g_wszAll[i++] = 0xd800 | ((uc - 0x10000) >> 10);
    368         g_wszAll[i++] = 0xdc00 | ((uc - 0x10000) & 0x3ff);
    369         uc++;
    370     }
    371     //RTPrintf(" %#x=%#x\n", i, uc);
    372     g_wszAll[i++] = '\0';
    373     Assert(RT_ELEMENTS(g_wszAll) == i);
    374 
    375     /*
    376      * The utf-8 one
    377      */
    378     i = 0;
    379     uc = 1;
    380     //RTPrintf("tstUtf8: %#x=%#x", i, uc);
    381     while (uc < 0x80)
    382         g_szAll[i++] = uc++;
    383     //RTPrintf(" %#x=%#x", i, uc);
    384     while (uc < 0x800)
    385     {
    386         g_szAll[i++] = 0xc0 | (uc >> 6);
    387         g_szAll[i++] = 0x80 | (uc & 0x3f);
    388         Assert(!((uc >> 6) & ~0x1f));
    389         uc++;
    390     }
    391     //RTPrintf(" %#x=%#x", i, uc);
    392     while (uc < 0xd800)
    393     {
    394         g_szAll[i++] = 0xe0 |  (uc >> 12);
    395         g_szAll[i++] = 0x80 | ((uc >>  6) & 0x3f);
    396         g_szAll[i++] = 0x80 |  (uc & 0x3f);
    397         Assert(!((uc >> 12) & ~0xf));
    398         uc++;
    399     }
    400     uc = 0xe000;
    401     //RTPrintf(" %#x=%#x", i, uc);
    402     while (uc < 0xfffe)
    403     {
    404         g_szAll[i++] = 0xe0 |  (uc >> 12);
    405         g_szAll[i++] = 0x80 | ((uc >>  6) & 0x3f);
    406         g_szAll[i++] = 0x80 |  (uc & 0x3f);
    407         Assert(!((uc >> 12) & ~0xf));
    408         uc++;
    409     }
    410     uc = 0x10000;
    411     //RTPrintf(" %#x=%#x", i, uc);
    412     while (uc < 0x110000)
    413     {
    414         g_szAll[i++] = 0xf0 |  (uc >> 18);
    415         g_szAll[i++] = 0x80 | ((uc >> 12) & 0x3f);
    416         g_szAll[i++] = 0x80 | ((uc >>  6) & 0x3f);
    417         g_szAll[i++] = 0x80 |  (uc & 0x3f);
    418         Assert(!((uc >> 18) & ~0x7));
    419         uc++;
    420     }
    421     //RTPrintf(" %#x=%#x\n", i, uc);
    422     g_szAll[i++] = '\0';
    423     Assert(RT_ELEMENTS(g_szAll) == i);
    424 }
    425 
    426 
    427 void test2(RTTEST hTest)
    428 {
    429     /*
    430      * Convert to UTF-8 and back.
    431      */
    432     RTTestSub(hTest, "UTF-16 -> UTF-8 -> UTF-16");
    433     char *pszUtf8;
    434     int rc = RTUtf16ToUtf8(&g_wszAll[0], &pszUtf8);
    435     if (rc == VINF_SUCCESS)
    436     {
    437         if (mymemcmp(pszUtf8, g_szAll, sizeof(g_szAll), 8))
    438             RTTestFailed(hTest, "UTF-16 -> UTF-8 mismatch!");
    439 
    440         PRTUTF16 pwszUtf16;
    441         rc = RTStrToUtf16(pszUtf8, &pwszUtf16);
    442         if (rc == VINF_SUCCESS)
    443         {
    444             if (mymemcmp(pwszUtf16, g_wszAll, sizeof(g_wszAll), 16))
    445                 RTTestFailed(hTest, "UTF-8 -> UTF-16 failed compare!");
    446             RTUtf16Free(pwszUtf16);
    447         }
    448         else
    449             RTTestFailed(hTest, "UTF-8 -> UTF-16 failed, rc=%Rrc.", rc);
    450         RTStrFree(pszUtf8);
    451     }
    452     else
    453         RTTestFailed(hTest, "UTF-16 -> UTF-8 failed, rc=%Rrc.", rc);
    454 
    455 
    456     /*
    457      * Convert to UTF-16 and back. (just in case the above test fails)
    458      */
    459     RTTestSub(hTest, "UTF-8 -> UTF-16 -> UTF-8");
    460     PRTUTF16 pwszUtf16;
    461     rc = RTStrToUtf16(&g_szAll[0], &pwszUtf16);
    462     if (rc == VINF_SUCCESS)
    463     {
    464         if (mymemcmp(pwszUtf16, g_wszAll, sizeof(g_wszAll), 16))
    465             RTTestFailed(hTest, "UTF-8 -> UTF-16 failed compare!");
    466 
    467         rc = RTUtf16ToUtf8(pwszUtf16, &pszUtf8);
    468         if (rc == VINF_SUCCESS)
    469         {
    470             if (mymemcmp(pszUtf8, g_szAll, sizeof(g_szAll), 8))
    471                 RTTestFailed(hTest, "UTF-16 -> UTF-8 failed compare!");
    472             RTStrFree(pszUtf8);
    473         }
    474         else
    475             RTTestFailed(hTest, "UTF-16 -> UTF-8 failed, rc=%Rrc.", rc);
    476         RTUtf16Free(pwszUtf16);
    477     }
    478     else
    479         RTTestFailed(hTest, "UTF-8 -> UTF-16 failed, rc=%Rrc.", rc);
    480 
    481     /*
    482      * Convert UTF-8 to CPs.
    483      */
    484     RTTestSub(hTest, "UTF-8 -> UNI -> UTF-8");
    485     PRTUNICP paCps;
    486     rc = RTStrToUni(g_szAll, &paCps);
    487     if (rc == VINF_SUCCESS)
    488     {
    489         if (mymemcmp(paCps, g_uszAll, sizeof(g_uszAll), 32))
    490             RTTestFailed(hTest, "UTF-8 -> UTF-16 failed, rc=%Rrc.", rc);
    491 
    492         size_t cCps;
    493         rc = RTStrToUniEx(g_szAll, RTSTR_MAX, &paCps, RT_ELEMENTS(g_uszAll), &cCps);
    494         if (rc == VINF_SUCCESS)
    495         {
    496             if (cCps != RT_ELEMENTS(g_uszAll) - 1)
    497                 RTTestFailed(hTest, "wrong Code Point count %zu, expected %zu\n", cCps, RT_ELEMENTS(g_uszAll) - 1);
    498         }
    499         else
    500             RTTestFailed(hTest, "UTF-8 -> Code Points failed, rc=%Rrc.\n", rc);
    501 
    502         /** @todo RTCpsToUtf8 or something. */
    503     }
    504     else
    505         RTTestFailed(hTest, "UTF-8 -> Code Points failed, rc=%Rrc.\n", rc);
    506 
    507     /*
    508      * Check the various string lengths.
    509      */
    510     RTTestSub(hTest, "Lengths");
    511     size_t cuc1 = RTStrCalcUtf16Len(g_szAll);
    512     size_t cuc2 = RTUtf16Len(g_wszAll);
    513     if (cuc1 != cuc2)
    514         RTTestFailed(hTest, "cuc1=%zu != cuc2=%zu\n", cuc1, cuc2);
    515     //size_t cuc3 = RTUniLen(g_uszAll);
    516 
    517 
    518     /*
    519      * Enumerate the strings.
    520      */
    521     RTTestSub(hTest, "Code Point Getters and Putters");
    522     char *pszPut1Base = (char *)RTMemAlloc(sizeof(g_szAll));
    523     AssertRelease(pszPut1Base);
    524     char *pszPut1 = pszPut1Base;
    525     PRTUTF16 pwszPut2Base = (PRTUTF16)RTMemAlloc(sizeof(g_wszAll));
    526     AssertRelease(pwszPut2Base);
    527     PRTUTF16 pwszPut2 = pwszPut2Base;
    528     const char *psz1 = g_szAll;
    529     const char *psz2 = g_szAll;
    530     PCRTUTF16   pwsz3 = g_wszAll;
    531     PCRTUTF16   pwsz4 = g_wszAll;
    532     for (;;)
    533     {
    534         /*
    535          * getters
    536          */
    537         RTUNICP uc1;
    538         rc = RTStrGetCpEx(&psz1, &uc1);
    539         if (RT_FAILURE(rc))
    540         {
    541             RTTestFailed(hTest, "RTStrGetCpEx failed with rc=%Rrc at %.10Rhxs", rc, psz2);
    542             whereami(8, psz2 - &g_szAll[0]);
    543             break;
    544         }
    545         char *pszPrev1 = RTStrPrevCp(g_szAll, psz1);
    546         if (pszPrev1 != psz2)
    547         {
    548             RTTestFailed(hTest, "RTStrPrevCp returned %p expected %p!", pszPrev1, psz2);
    549             whereami(8, psz2 - &g_szAll[0]);
    550             break;
    551         }
    552         RTUNICP uc2 = RTStrGetCp(psz2);
    553         if (uc2 != uc1)
    554         {
    555             RTTestFailed(hTest, "RTStrGetCpEx and RTStrGetCp returned different CPs: %RTunicp != %RTunicp", uc2, uc1);
    556             whereami(8, psz2 - &g_szAll[0]);
    557             break;
    558         }
    559         psz2 = RTStrNextCp(psz2);
    560         if (psz2 != psz1)
    561         {
    562             RTTestFailed(hTest, "RTStrGetCpEx and RTStrGetNext returned different next pointer!");
    563             whereami(8, psz2 - &g_szAll[0]);
    564             break;
    565         }
    566 
    567         RTUNICP uc3;
    568         rc = RTUtf16GetCpEx(&pwsz3, &uc3);
    569         if (RT_FAILURE(rc))
    570         {
    571             RTTestFailed(hTest, "RTUtf16GetCpEx failed with rc=%Rrc at %.10Rhxs", rc, pwsz4);
    572             whereami(16, pwsz4 - &g_wszAll[0]);
    573             break;
    574         }
    575         if (uc3 != uc2)
    576         {
    577             RTTestFailed(hTest, "RTUtf16GetCpEx and RTStrGetCp returned different CPs: %RTunicp != %RTunicp", uc3, uc2);
    578             whereami(16, pwsz4 - &g_wszAll[0]);
    579             break;
    580         }
    581         RTUNICP uc4 = RTUtf16GetCp(pwsz4);
    582         if (uc3 != uc4)
    583         {
    584             RTTestFailed(hTest, "RTUtf16GetCpEx and RTUtf16GetCp returned different CPs: %RTunicp != %RTunicp", uc3, uc4);
    585             whereami(16, pwsz4 - &g_wszAll[0]);
    586             break;
    587         }
    588         pwsz4 = RTUtf16NextCp(pwsz4);
    589         if (pwsz4 != pwsz3)
    590         {
    591             RTTestFailed(hTest, "RTUtf16GetCpEx and RTUtf16GetNext returned different next pointer!");
    592             whereami(8, pwsz4 - &g_wszAll[0]);
    593             break;
    594         }
    595 
    596 
    597         /*
    598          * putters
    599          */
    600         pszPut1 = RTStrPutCp(pszPut1, uc1);
    601         if (pszPut1 - pszPut1Base != psz1 - &g_szAll[0])
    602         {
    603             RTTestFailed(hTest, "RTStrPutCp is not at the same offset! %p != %p",
    604                          pszPut1 - pszPut1Base, psz1 - &g_szAll[0]);
    605             whereami(8, psz2 - &g_szAll[0]);
    606             break;
    607         }
    608 
    609         pwszPut2 = RTUtf16PutCp(pwszPut2, uc3);
    610         if (pwszPut2 - pwszPut2Base != pwsz3 - &g_wszAll[0])
    611         {
    612             RTTestFailed(hTest, "RTStrPutCp is not at the same offset! %p != %p",
    613                          pwszPut2 - pwszPut2Base, pwsz3 - &g_wszAll[0]);
    614             whereami(8, pwsz4 - &g_wszAll[0]);
    615             break;
    616         }
    617 
    618 
    619         /* the end? */
    620         if (!uc1)
    621             break;
    622     }
    623 
    624     /* check output if we seems to have made it thru it all. */
    625     if (psz2 == &g_szAll[sizeof(g_szAll)])
    626     {
    627         if (mymemcmp(pszPut1Base, g_szAll, sizeof(g_szAll), 8))
    628             RTTestFailed(hTest, "RTStrPutCp encoded the string incorrectly.");
    629         if (mymemcmp(pwszPut2Base, g_wszAll, sizeof(g_wszAll), 16))
    630             RTTestFailed(hTest, "RTUtf16PutCp encoded the string incorrectly.");
    631     }
    632 
    633     RTMemFree(pszPut1Base);
    634     RTMemFree(pwszPut2Base);
    635 
    636     RTTestSubDone(hTest);
    637 }
    638 
    639 
    640 /**
    641  * Check case insensitivity.
    642  */
    643 void test3(RTTEST hTest)
    644 {
    645     RTTestSub(hTest, "Case Sensitivitity");
    646 
    647     if (    RTUniCpToLower('a') != 'a'
    648         ||  RTUniCpToLower('A') != 'a'
    649         ||  RTUniCpToLower('b') != 'b'
    650         ||  RTUniCpToLower('B') != 'b'
    651         ||  RTUniCpToLower('Z') != 'z'
    652         ||  RTUniCpToLower('z') != 'z'
    653         ||  RTUniCpToUpper('c') != 'C'
    654         ||  RTUniCpToUpper('C') != 'C'
    655         ||  RTUniCpToUpper('z') != 'Z'
    656         ||  RTUniCpToUpper('Z') != 'Z')
    657         RTTestFailed(hTest, "RTUniToUpper/Lower failed basic tests.\n");
    658 
    659     if (RTUtf16ICmp(g_wszAll, g_wszAll))
    660         RTTestFailed(hTest, "RTUtf16ICmp failed the basic test.\n");
    661 
    662     if (RTUtf16Cmp(g_wszAll, g_wszAll))
    663         RTTestFailed(hTest, "RTUtf16Cmp failed the basic test.\n");
    664 
    665     static RTUTF16 s_wszTst1a[] = { 'a', 'B', 'c', 'D', 'E', 'f', 'g', 'h', 'i', 'j', 'K', 'L', 'm', 'N', 'o', 'P', 'q', 'r', 'S', 't', 'u', 'V', 'w', 'x', 'Y', 'Z', 0xc5, 0xc6, 0xf8, 0 };
    666     static RTUTF16 s_wszTst1b[] = { 'A', 'B', 'c', 'd', 'e', 'F', 'G', 'h', 'i', 'J', 'k', 'l', 'M', 'n', 'O', 'p', 'Q', 'R', 's', 't', 'U', 'v', 'w', 'X', 'y', 'z', 0xe5, 0xe6, 0xd8, 0 };
    667     if (    RTUtf16ICmp(s_wszTst1b, s_wszTst1b)
    668         ||  RTUtf16ICmp(s_wszTst1a, s_wszTst1a)
    669         ||  RTUtf16ICmp(s_wszTst1a, s_wszTst1b)
    670         ||  RTUtf16ICmp(s_wszTst1b, s_wszTst1a)
    671         )
    672         RTTestFailed(hTest, "RTUtf16ICmp failed the alphabet test.\n");
    673 
    674     if (    RTUtf16Cmp(s_wszTst1b, s_wszTst1b)
    675         ||  RTUtf16Cmp(s_wszTst1a, s_wszTst1a)
    676         ||  !RTUtf16Cmp(s_wszTst1a, s_wszTst1b)
    677         ||  !RTUtf16Cmp(s_wszTst1b, s_wszTst1a)
    678         )
    679         RTTestFailed(hTest, "RTUtf16Cmp failed the alphabet test.\n");
    680 
    681     RTTestSubDone(hTest);
    682 }
    683 
    684 
    685 /**
    686  * Test the RTStr*Cmp functions.
    687  */
    688 void TstRTStrXCmp(RTTEST hTest)
    689 {
    690 #define CHECK_DIFF(expr, op) \
    691     do \
    692     { \
    693         int iDiff = expr; \
    694         if (!(iDiff op 0)) \
    695             RTTestFailed(hTest, "%d: %d " #op " 0: %s\n", __LINE__, iDiff, #expr); \
    696     } while (0)
    697 
    698 /** @todo test the non-ascii bits. */
    699 
    700     RTTestSub(hTest, "RTStrCmp");
    701     CHECK_DIFF(RTStrCmp(NULL, NULL), == );
    702     CHECK_DIFF(RTStrCmp(NULL, ""), < );
    703     CHECK_DIFF(RTStrCmp("", NULL), > );
    704     CHECK_DIFF(RTStrCmp("", ""), == );
    705     CHECK_DIFF(RTStrCmp("abcdef", "abcdef"), == );
    706     CHECK_DIFF(RTStrCmp("abcdef", "abcde"), > );
    707     CHECK_DIFF(RTStrCmp("abcde", "abcdef"), < );
    708     CHECK_DIFF(RTStrCmp("abcdeg", "abcdef"), > );
    709     CHECK_DIFF(RTStrCmp("abcdef", "abcdeg"), < );
    710     CHECK_DIFF(RTStrCmp("abcdeF", "abcdef"), < );
    711     CHECK_DIFF(RTStrCmp("abcdef", "abcdeF"), > );
    712 
    713 
    714     RTTestSub(hTest, "RTStrNCmp");
    715     CHECK_DIFF(RTStrNCmp(NULL, NULL, RTSTR_MAX), == );
    716     CHECK_DIFF(RTStrNCmp(NULL, "", RTSTR_MAX), < );
    717     CHECK_DIFF(RTStrNCmp("", NULL, RTSTR_MAX), > );
    718     CHECK_DIFF(RTStrNCmp("", "", RTSTR_MAX), == );
    719     CHECK_DIFF(RTStrNCmp("abcdef", "abcdef", RTSTR_MAX), == );
    720     CHECK_DIFF(RTStrNCmp("abcdef", "abcde", RTSTR_MAX), > );
    721     CHECK_DIFF(RTStrNCmp("abcde", "abcdef", RTSTR_MAX), < );
    722     CHECK_DIFF(RTStrNCmp("abcdeg", "abcdef", RTSTR_MAX), > );
    723     CHECK_DIFF(RTStrNCmp("abcdef", "abcdeg", RTSTR_MAX), < );
    724     CHECK_DIFF(RTStrNCmp("abcdeF", "abcdef", RTSTR_MAX), < );
    725     CHECK_DIFF(RTStrNCmp("abcdef", "abcdeF", RTSTR_MAX), > );
    726 
    727     CHECK_DIFF(RTStrNCmp("abcdef", "fedcba", 0), ==);
    728     CHECK_DIFF(RTStrNCmp("abcdef", "abcdeF", 5), ==);
    729     CHECK_DIFF(RTStrNCmp("abcdef", "abcdeF", 6), > );
    730 
    731 
    732     RTTestSub(hTest, "RTStrICmp");
    733     CHECK_DIFF(RTStrICmp(NULL, NULL), == );
    734     CHECK_DIFF(RTStrICmp(NULL, ""), < );
    735     CHECK_DIFF(RTStrICmp("", NULL), > );
    736     CHECK_DIFF(RTStrICmp("", ""), == );
    737     CHECK_DIFF(RTStrICmp("abcdef", "abcdef"), == );
    738     CHECK_DIFF(RTStrICmp("abcdef", "abcde"), > );
    739     CHECK_DIFF(RTStrICmp("abcde", "abcdef"), < );
    740     CHECK_DIFF(RTStrICmp("abcdeg", "abcdef"), > );
    741     CHECK_DIFF(RTStrICmp("abcdef", "abcdeg"), < );
    742 
    743     CHECK_DIFF(RTStrICmp("abcdeF", "abcdef"), ==);
    744     CHECK_DIFF(RTStrICmp("abcdef", "abcdeF"), ==);
    745     CHECK_DIFF(RTStrICmp("ABCDEF", "abcdef"), ==);
    746     CHECK_DIFF(RTStrICmp("abcdef", "ABCDEF"), ==);
    747     CHECK_DIFF(RTStrICmp("AbCdEf", "aBcDeF"), ==);
    748     CHECK_DIFF(RTStrICmp("AbCdEg", "aBcDeF"), > );
    749     CHECK_DIFF(RTStrICmp("AbCdEG", "aBcDef"), > ); /* diff performed on the lower case cp. */
    750 
    751 
    752 
    753     RTTestSub(hTest, "RTStrNICmp");
    754     CHECK_DIFF(RTStrNICmp(NULL, NULL, RTSTR_MAX), == );
    755     CHECK_DIFF(RTStrNICmp(NULL, "", RTSTR_MAX), < );
    756     CHECK_DIFF(RTStrNICmp("", NULL, RTSTR_MAX), > );
    757     CHECK_DIFF(RTStrNICmp("", "", RTSTR_MAX), == );
    758     CHECK_DIFF(RTStrNICmp(NULL, NULL, 0), == );
    759     CHECK_DIFF(RTStrNICmp(NULL, "", 0), == );
    760     CHECK_DIFF(RTStrNICmp("", NULL, 0), == );
    761     CHECK_DIFF(RTStrNICmp("", "", 0), == );
    762     CHECK_DIFF(RTStrNICmp("abcdef", "abcdef", RTSTR_MAX), == );
    763     CHECK_DIFF(RTStrNICmp("abcdef", "abcde", RTSTR_MAX), > );
    764     CHECK_DIFF(RTStrNICmp("abcde", "abcdef", RTSTR_MAX), < );
    765     CHECK_DIFF(RTStrNICmp("abcdeg", "abcdef", RTSTR_MAX), > );
    766     CHECK_DIFF(RTStrNICmp("abcdef", "abcdeg", RTSTR_MAX), < );
    767 
    768     CHECK_DIFF(RTStrNICmp("abcdeF", "abcdef", RTSTR_MAX), ==);
    769     CHECK_DIFF(RTStrNICmp("abcdef", "abcdeF", RTSTR_MAX), ==);
    770     CHECK_DIFF(RTStrNICmp("ABCDEF", "abcdef", RTSTR_MAX), ==);
    771     CHECK_DIFF(RTStrNICmp("abcdef", "ABCDEF", RTSTR_MAX), ==);
    772     CHECK_DIFF(RTStrNICmp("AbCdEf", "aBcDeF", RTSTR_MAX), ==);
    773     CHECK_DIFF(RTStrNICmp("AbCdEg", "aBcDeF", RTSTR_MAX), > );
    774     CHECK_DIFF(RTStrNICmp("AbCdEG", "aBcDef", RTSTR_MAX), > ); /* diff performed on the lower case cp. */
    775 
    776     CHECK_DIFF(RTStrNICmp("ABCDEF", "fedcba", 0), ==);
    777     CHECK_DIFF(RTStrNICmp("AbCdEg", "aBcDeF", 5), ==);
    778     CHECK_DIFF(RTStrNICmp("AbCdEf", "aBcDeF", 5), ==);
    779     CHECK_DIFF(RTStrNICmp("AbCdE",  "aBcDe", 5), ==);
    780     CHECK_DIFF(RTStrNICmp("AbCdE",  "aBcDeF", 5), ==);
    781     CHECK_DIFF(RTStrNICmp("AbCdEf", "aBcDe", 5), ==);
    782     CHECK_DIFF(RTStrNICmp("AbCdEg", "aBcDeF", 6), > );
    783     CHECK_DIFF(RTStrNICmp("AbCdEG", "aBcDef", 6), > ); /* diff performed on the lower case cp. */
    784     /* We should continue using byte comparison when we hit the invalid CP.  Will assert in debug builds. */
    785     // CHECK_DIFF(RTStrNICmp("AbCd\xff""eg", "aBcD\xff""eF", 6), ==);
    786 
    787     RTTestSubDone(hTest);
    788 }
    789 
    790 
    791 
    792 /**
    793  * Check case insensitivity.
    794  */
    795 void TstRTStrPurgeEncoding(RTTEST hTest)
    796 {
    797     RTTestSub(hTest, "RTStrPurgeEncoding");
    798 
    799     /*
    800      * Test some good strings.
    801      */
    802     char sz1[] = "1234567890wertyuiopsdfghjklzxcvbnm";
    803     char sz1Copy[sizeof(sz1)];
    804     memcpy(sz1Copy, sz1, sizeof(sz1));
    805 
    806     RTTESTI_CHECK_RETV(RTStrPurgeEncoding(sz1) == 0);
    807     RTTESTI_CHECK_RETV(!memcmp(sz1, sz1Copy, sizeof(sz1)));
    808 
    809     char *pszAll = RTStrDup(g_szAll);
    810     if (pszAll)
    811     {
    812         RTTESTI_CHECK(RTStrPurgeEncoding(pszAll) == 0);
    813         RTTESTI_CHECK(!memcmp(pszAll, g_szAll, sizeof(g_szAll)));
    814         RTStrFree(pszAll);
    815     }
    816 
    817     /*
    818      * Test some bad stuff.
    819      */
    820     struct
    821     {
    822         size_t          cErrors;
    823         unsigned char   szIn[5];
    824         const char     *pszExpect;
    825     } aTests[] =
    826     {
    827         { 0, {  '1',  '2',  '3',  '4', '\0' }, "1234" },
    828         { 1, { 0x80,  '2',  '3',  '4', '\0' }, "?234" },
    829         { 1, {  '1', 0x80,  '3',  '4', '\0' }, "1?34" },
    830         { 1, {  '1',  '2', 0x80,  '4', '\0' }, "12?4" },
    831         { 1, {  '1',  '2',  '3', 0x80, '\0' }, "123?" },
    832         { 2, { 0x80, 0x81,  '3',  '4', '\0' }, "??34" },
    833         { 2, {  '1', 0x80, 0x81,  '4', '\0' }, "1??4" },
    834         { 2, {  '1',  '2', 0x80, 0x81, '\0' }, "12??" },
    835     };
    836     for (size_t i = 0; i < RT_ELEMENTS(aTests); i++)
    837     {
    838         size_t cErrors = RTStrPurgeEncoding((char *)aTests[i].szIn);
    839         if (cErrors != aTests[i].cErrors)
    840             RTTestFailed(hTest, "#%u: cErrors=%u expected %u\n", i, cErrors, aTests[i].cErrors);
    841         else if (strcmp((char *)aTests[i].szIn, aTests[i].pszExpect))
    842             RTTestFailed(hTest, "#%u: %.5Rhxs expected %.5Rhxs (%s)\n", i, aTests[i].szIn, aTests[i].pszExpect, aTests[i].pszExpect);
    843     }
    844 
    845     RTTestSubDone(hTest);
    846 }
    847 
    848 
    849 /**
    850  * Benchmark stuff.
    851  */
    852 void Benchmarks(RTTEST hTest)
    853 {
    854     static union
    855     {
    856         RTUTF16 wszBuf[sizeof(g_wszAll)];
    857         char szBuf[sizeof(g_szAll)];
    858     } s_Buf;
    859 
    860     RTTestSub(hTest, "Benchmarks");
    861 /** @todo add RTTest* methods for reporting benchmark results. */
    862     RTTestPrintf(hTest, RTTESTLVL_ALWAYS, "Benchmarking RTStrToUtf16Ex:  "); /** @todo figure this stuff into the test framework. */
    863     PRTUTF16 pwsz = &s_Buf.wszBuf[0];
    864     int rc = RTStrToUtf16Ex(&g_szAll[0], RTSTR_MAX, &pwsz, RT_ELEMENTS(s_Buf.wszBuf), NULL);
    865     if (RT_SUCCESS(rc))
    866     {
    867         int i;
    868         uint64_t u64Start = RTTimeNanoTS();
    869         for (i = 0; i < 100; i++)
    870         {
    871             rc = RTStrToUtf16Ex(&g_szAll[0], RTSTR_MAX, &pwsz, RT_ELEMENTS(s_Buf.wszBuf), NULL);
    872             if (RT_FAILURE(rc))
    873             {
    874                 RTTestFailed(hTest, "UTF-8 -> UTF-16 benchmark failed at i=%d, rc=%Rrc\n", i, rc);
    875                 break;
    876             }
    877         }
    878         uint64_t u64Elapsed = RTTimeNanoTS() - u64Start;
    879         RTTestPrintf(hTest, RTTESTLVL_ALWAYS, "%d in %'RI64 ns\n", i, u64Elapsed);
    880     }
    881 
    882     RTTestPrintf(hTest, RTTESTLVL_ALWAYS, "Benchmarking RTUtf16ToUtf8Ex: ");
    883     char *psz = &s_Buf.szBuf[0];
    884     rc = RTUtf16ToUtf8Ex(&g_wszAll[0], RTSTR_MAX, &psz, RT_ELEMENTS(s_Buf.szBuf), NULL);
    885     if (RT_SUCCESS(rc))
    886     {
    887         int i;
    888         uint64_t u64Start = RTTimeNanoTS();
    889         for (i = 0; i < 100; i++)
    890         {
    891             rc = RTUtf16ToUtf8Ex(&g_wszAll[0], RTSTR_MAX, &psz, RT_ELEMENTS(s_Buf.szBuf), NULL);
    892             if (RT_FAILURE(rc))
    893             {
    894                 RTTestFailed(hTest, "UTF-16 -> UTF-8 benchmark failed at i=%d, rc=%Rrc\n", i, rc);
    895                 break;
    896             }
    897         }
    898         uint64_t u64Elapsed = RTTimeNanoTS() - u64Start;
    899         RTTestPrintf(hTest, RTTESTLVL_ALWAYS, "%d in %'RI64 ns\n", i, u64Elapsed);
    900     }
    901 
    902     RTTestSubDone(hTest);
    903 }
    904 
    905 
    906 /**
    907  * Tests RTStrEnd
    908  */
    909 static void testStrEnd(RTTEST hTest)
    910 {
    911     RTTestSub(hTest, "RTStrEnd");
    912 
    913     static char const s_szEmpty[1] = "";
    914     RTTESTI_CHECK(RTStrEnd(s_szEmpty, 0) == NULL);
    915     RTTESTI_CHECK(RTStrEnd(s_szEmpty, 1) == &s_szEmpty[0]);
    916     for (size_t i = 0; i < _1M; i++)
    917         RTTESTI_CHECK(RTStrEnd(s_szEmpty, ~i) == &s_szEmpty[0]);
    918 
    919 }
    920 
    921 
    922 /**
    923  * Tests RTStrStr and RTStrIStr.
    924  */
    925 static void testStrStr(RTTEST hTest)
    926 {
    927 #define CHECK_NULL(expr) \
    928     do { \
    929         const char *pszRet = expr; \
    930         if (pszRet != NULL) \
    931             RTTestFailed(hTest, "%d: %#x -> %s expected NULL", __LINE__, #expr, pszRet); \
    932     } while (0)
    933 
    934 #define CHECK(expr, expect) \
    935     do { \
    936         const char *pszRet = expr; \
    937         if (   (pszRet != NULL && (expect) == NULL) \
    938             || (pszRet == NULL && (expect) != NULL) \
    939             || strcmp(pszRet, (expect)) \
    940             ) \
    941             RTTestFailed(hTest, "%d: %#x -> %s expected %s", __LINE__, #expr, pszRet, (expect)); \
    942     } while (0)
    943 
    944 
    945     RTTestSub(hTest, "RTStrStr");
    946     CHECK(RTStrStr("abcdef", ""), "abcdef");
    947     CHECK_NULL(RTStrStr("abcdef", NULL));
    948     CHECK_NULL(RTStrStr(NULL, ""));
    949     CHECK_NULL(RTStrStr(NULL, NULL));
    950     CHECK(RTStrStr("abcdef", "abcdef"), "abcdef");
    951     CHECK(RTStrStr("abcdef", "b"), "bcdef");
    952     CHECK(RTStrStr("abcdef", "bcdef"), "bcdef");
    953     CHECK(RTStrStr("abcdef", "cdef"), "cdef");
    954     CHECK(RTStrStr("abcdef", "cde"), "cdef");
    955     CHECK(RTStrStr("abcdef", "cd"), "cdef");
    956     CHECK(RTStrStr("abcdef", "c"), "cdef");
    957     CHECK(RTStrStr("abcdef", "f"), "f");
    958     CHECK(RTStrStr("abcdef", "ef"), "ef");
    959     CHECK(RTStrStr("abcdef", "e"), "ef");
    960     CHECK_NULL(RTStrStr("abcdef", "z"));
    961     CHECK_NULL(RTStrStr("abcdef", "A"));
    962     CHECK_NULL(RTStrStr("abcdef", "F"));
    963 
    964     RTTestSub(hTest, "RTStrIStr");
    965     CHECK(RTStrIStr("abcdef", ""), "abcdef");
    966     CHECK_NULL(RTStrIStr("abcdef", NULL));
    967     CHECK_NULL(RTStrIStr(NULL, ""));
    968     CHECK_NULL(RTStrIStr(NULL, NULL));
    969     CHECK(RTStrIStr("abcdef", "abcdef"), "abcdef");
    970     CHECK(RTStrIStr("abcdef", "Abcdef"), "abcdef");
    971     CHECK(RTStrIStr("abcdef", "ABcDeF"), "abcdef");
    972     CHECK(RTStrIStr("abcdef", "b"), "bcdef");
    973     CHECK(RTStrIStr("abcdef", "B"), "bcdef");
    974     CHECK(RTStrIStr("abcdef", "bcdef"), "bcdef");
    975     CHECK(RTStrIStr("abcdef", "BCdEf"), "bcdef");
    976     CHECK(RTStrIStr("abcdef", "bCdEf"), "bcdef");
    977     CHECK(RTStrIStr("abcdef", "bcdEf"), "bcdef");
    978     CHECK(RTStrIStr("abcdef", "BcdEf"), "bcdef");
    979     CHECK(RTStrIStr("abcdef", "cdef"), "cdef");
    980     CHECK(RTStrIStr("abcdef", "cde"), "cdef");
    981     CHECK(RTStrIStr("abcdef", "cd"), "cdef");
    982     CHECK(RTStrIStr("abcdef", "c"), "cdef");
    983     CHECK(RTStrIStr("abcdef", "f"), "f");
    984     CHECK(RTStrIStr("abcdeF", "F"), "F");
    985     CHECK(RTStrIStr("abcdef", "F"), "f");
    986     CHECK(RTStrIStr("abcdef", "ef"), "ef");
    987     CHECK(RTStrIStr("EeEef", "e"), "EeEef");
    988     CHECK(RTStrIStr("EeEef", "E"), "EeEef");
    989     CHECK(RTStrIStr("EeEef", "EE"), "EeEef");
    990     CHECK(RTStrIStr("EeEef", "EEE"), "EeEef");
    991     CHECK(RTStrIStr("EeEef", "EEEF"), "eEef");
    992     CHECK_NULL(RTStrIStr("EeEef", "z"));
    993 
    994 #undef CHECK
    995 #undef CHECK_NULL
    996     RTTestSubDone(hTest);
    997 }
    998 
    999 
    1000 void testMinistring(RTTEST hTest)
    1001 {
    1002     RTTestSub(hTest, "class iprt::MiniString");
    1003 
    1004 #define CHECK(expr) \
    1005     do { \
    1006         if (!(expr)) \
    1007             RTTestFailed(hTest, "%d: FAILED %s", __LINE__, #expr); \
    1008     } while (0)
    1009 
     42    RTTestSub(hTest, "Basics");
     43
     44#define CHECK(expr) RTTESTI_CHECK(expr)
    101045#define CHECK_DUMP(expr, value) \
    101146    do { \
     
    103065    sixbytes.append(iprt::MiniString("678"));
    103166    CHECK(sixbytes.length() == 8);
    1032     CHECK(sixbytes.capacity() == 9);
     67    CHECK(sixbytes.capacity() >= 9);
    103368
    103469    sixbytes.append("9a");
    103570    CHECK(sixbytes.length() == 10);
    1036     CHECK(sixbytes.capacity() == 11);
     71    CHECK(sixbytes.capacity() >= 11);
    103772
    103873    char *psz = sixbytes.mutableRaw();
     
    1072107    CHECK(iprt::MiniString("abc") == iprt::MiniString("abc"));
    1073108
     109    CHECK(iprt::MiniString("abc") <  "def");
     110    CHECK(iprt::MiniString("abc") != "def");
     111    CHECK_DUMP_I(iprt::MiniString("def") > "abc");
     112    CHECK(iprt::MiniString("abc") == "abc");
     113
     114    CHECK(iprt::MiniString("abc").equals("abc"));
     115    CHECK(!iprt::MiniString("abc").equals("def"));
     116    CHECK(iprt::MiniString("abc").equalsIgnoreCase("Abc"));
     117    CHECK(iprt::MiniString("abc").equalsIgnoreCase("ABc"));
     118    CHECK(iprt::MiniString("abc").equalsIgnoreCase("ABC"));
     119    CHECK(!iprt::MiniString("abc").equalsIgnoreCase("dBC"));
     120
    1074121    copy2.setNull();
    1075122    for (int i = 0; i < 100; ++i)
     
    1094141
    1095142
    1096 void testUtf8Latin1(RTTEST hTest)
     143static int mymemcmp(const char *psz1, const char *psz2, size_t cch)
    1097144{
    1098     RTTestSub(hTest, "Latin-1 <-> Utf-8 conversion functions");
    1099 
    1100     /* Test Utf8 -> Latin1 */
    1101     size_t cch_szAll = 0;
    1102     size_t cbShort = RTStrCalcLatin1Len(g_szAll);
    1103     RTTEST_CHECK(hTest, cbShort == 0);
    1104     int rc = RTStrCalcLatin1LenEx(g_szAll, 383, &cch_szAll);
    1105     RTTEST_CHECK(hTest, (cch_szAll == 255));
    1106     rc = RTStrCalcLatin1LenEx(g_szAll, RTSTR_MAX, &cch_szAll);
    1107     RTTEST_CHECK_RC(hTest, rc, VERR_NO_TRANSLATION);
    1108     char *psz = NULL;
    1109     char szShort[256] = { 0 };
    1110     memcpy(szShort, g_szAll, 255);
    1111     cbShort = RTStrCalcLatin1Len(szShort);
    1112     RTTEST_CHECK(hTest, cbShort == 191);
    1113     rc = RTStrToLatin1(szShort, &psz);
    1114     RTTEST_CHECK_RC_OK(hTest, rc);
    1115     if (RT_SUCCESS(rc))
    1116     {
    1117         RTTEST_CHECK(hTest, (strlen(psz) == 191));
    1118         for (unsigned i = 0, j = 1; psz[i] != '\0'; ++i, ++j)
    1119             if (psz[i] != (char) j)
    1120             {
    1121                 RTTestFailed(hTest, "conversion of g_szAll to Latin1 failed at position %u\n", i);
    1122                 break;
    1123             }
    1124     }
    1125     RTStrFree(psz);
    1126     rc = RTStrToLatin1(g_szAll, &psz);
    1127     RTTEST_CHECK_RC(hTest, rc, VERR_NO_TRANSLATION);
    1128     char sz[512];
    1129     char *psz2 = &sz[0];
    1130     size_t cchActual = 0;
    1131     rc = RTStrToLatin1Ex(g_szAll, sizeof(sz) - 1, &psz2, sizeof(sz),
    1132                           &cchActual);
    1133     RTTEST_CHECK_RC(hTest, rc, VERR_NO_TRANSLATION);
    1134     RTTEST_CHECK_MSG(hTest, cchActual == 0,
    1135                      (hTest, "cchActual=%lu\n", cchActual));
    1136     rc = RTStrToLatin1Ex(g_szAll, 383, &psz2, sizeof(sz),
    1137                           &cchActual);
    1138     RTTEST_CHECK_RC_OK(hTest, rc);
    1139     if (RT_SUCCESS(rc))
    1140     {
    1141         RTTEST_CHECK(hTest, (cchActual == 255));
    1142         RTTEST_CHECK(hTest, (cchActual == strlen(sz)));
    1143         for (unsigned i = 0, j = 1; psz2[i] != '\0'; ++i, ++j)
    1144             if (psz2[i] != (char) j)
    1145             {
    1146                 RTTestFailed(hTest, "second conversion of g_szAll to Latin1 failed at position %u\n", i);
    1147                 break;
    1148             }
    1149     }
    1150     rc = RTStrToLatin1Ex(g_szAll, 129, &psz2, 128, &cchActual);
    1151     RTTEST_CHECK_RC(hTest, rc, VERR_BUFFER_OVERFLOW);
    1152     RTTEST_CHECK_MSG(hTest, cchActual == 128,
    1153                      (hTest, "cchActual=%lu\n", cchActual));
    1154     rc = RTStrToLatin1Ex(g_szAll, 383, &psz, 0, &cchActual);
    1155     RTTEST_CHECK_RC_OK(hTest, rc);
    1156     if (RT_SUCCESS(rc))
    1157     {
    1158         RTTEST_CHECK(hTest, (cchActual == 255));
    1159         RTTEST_CHECK(hTest, (cchActual == strlen(psz)));
    1160         for (unsigned i = 0, j = 1; psz[i] != '\0'; ++i, ++j)
    1161             if (   ((j < 0x100) && (psz[i] != (char) j))
    1162                 || ((j > 0xff) && psz[i] != '?'))
    1163             {
    1164                 RTTestFailed(hTest, "third conversion of g_szAll to Latin1 failed at position %u\n", i);
    1165                 break;
    1166             }
    1167     }
    1168     const char *pszBad = "Hello\xDC\xD8";
    1169     rc = RTStrToLatin1Ex(pszBad, RTSTR_MAX, &psz2, sizeof(sz),
    1170                            &cchActual);
    1171     RTTEST_CHECK_RC(hTest, rc, VERR_INVALID_UTF8_ENCODING);
    1172     RTStrFree(psz);
    1173 
    1174     /* Test Latin1 -> Utf8 */
    1175     const char *pszLat1 = "\x01\x20\x40\x80\x81";
    1176     RTTEST_CHECK(hTest, RTLatin1CalcUtf8Len(pszLat1) == 7);
    1177     rc = RTLatin1CalcUtf8LenEx(pszLat1, 3, &cchActual);
    1178     RTTEST_CHECK_RC_OK(hTest, rc);
    1179     if (RT_SUCCESS(rc))
    1180         RTTEST_CHECK(hTest, cchActual == 3);
    1181     rc = RTLatin1CalcUtf8LenEx(pszLat1, RTSTR_MAX, &cchActual);
    1182     RTTEST_CHECK_RC_OK(hTest, rc);
    1183     if (RT_SUCCESS(rc))
    1184         RTTEST_CHECK(hTest, cchActual == 7);
    1185     char *pch = NULL;
    1186     char ch[8];
    1187     char *pch2 = &ch[0];
    1188     cchActual = 0;
    1189     rc = RTLatin1ToUtf8(pszLat1, &pch);
    1190     RTTEST_CHECK_RC_OK(hTest, rc);
    1191     if (RT_SUCCESS(rc))
    1192         RTTEST_CHECK(hTest, !strcmp(pch, "\x01\x20\x40\xC2\x80\xC2\x81"));
    1193     RTStrFree(pch);
    1194     rc = RTLatin1ToUtf8Ex(pszLat1, RTSTR_MAX, &pch, 0, &cchActual);
    1195     RTTEST_CHECK_RC_OK(hTest, rc);
    1196     if (RT_SUCCESS(rc))
    1197     {
    1198         RTTEST_CHECK(hTest, (cchActual == 7));
    1199         RTTEST_CHECK(hTest, !strcmp(pch, "\x01\x20\x40\xC2\x80\xC2\x81"));
    1200     }
    1201     RTStrFree(pch);
    1202     rc = RTLatin1ToUtf8Ex(pszLat1, RTSTR_MAX, &pch, 0, NULL);
    1203     RTTEST_CHECK_RC_OK(hTest, rc);
    1204     if (RT_SUCCESS(rc))
    1205         RTTEST_CHECK(hTest, !strcmp(pch, "\x01\x20\x40\xC2\x80\xC2\x81"));
    1206     RTStrFree(pch);
    1207     rc = RTLatin1ToUtf8Ex(pszLat1, RTSTR_MAX, &pch2, RT_ELEMENTS(ch),
    1208                           &cchActual);
    1209     RTTEST_CHECK_RC_OK(hTest, rc);
    1210     if (RT_SUCCESS(rc))
    1211     {
    1212         RTTEST_CHECK(hTest, (cchActual == 7));
    1213         RTTEST_CHECK(hTest, !strcmp(pch2, "\x01\x20\x40\xC2\x80\xC2\x81"));
    1214     }
    1215     rc = RTLatin1ToUtf8Ex(pszLat1, 3, &pch2, RT_ELEMENTS(ch),
    1216                            &cchActual);
    1217     RTTEST_CHECK_RC_OK(hTest, rc);
    1218     if (RT_SUCCESS(rc))
    1219     {
    1220         RTTEST_CHECK(hTest, (cchActual == 3));
    1221         RTTEST_CHECK(hTest, !strcmp(pch2, "\x01\x20\x40"));
    1222     }
    1223     rc = RTLatin1ToUtf8Ex(pszLat1, RTSTR_MAX, &pch2, RT_ELEMENTS(ch) - 1,
    1224                           &cchActual);
    1225     RTTEST_CHECK_RC(hTest, rc, VERR_BUFFER_OVERFLOW);
    1226     RTTEST_CHECK(hTest, (cchActual == 7));
    1227     RTTestSubDone(hTest);
     145    for (size_t off = 0; off < cch; off++)
     146        if (psz1[off] != psz2[off])
     147        {
     148            RTTestIFailed("off=%#x  psz1=%.*Rhxs  psz2=%.*Rhxs\n", off,
     149                          RT_MIN(cch - off, 8), &psz1[off],
     150                          RT_MIN(cch - off, 8), &psz2[off]);
     151            return psz1[off] > psz2[off] ? 1 : -1;
     152        }
     153    return 0;
    1228154}
    1229155
    1230 
    1231 void testUtf16Latin1(RTTEST hTest)
     156static void test2(RTTEST hTest)
    1232157{
    1233     RTTestSub(hTest, "Latin-1 <-> Utf-16 conversion functions");
    1234 
    1235     /* Test Utf16 -> Latin1 */
    1236     size_t cch_szAll = 0;
    1237     size_t cbShort = RTUtf16CalcLatin1Len(g_wszAll);
    1238     RTTEST_CHECK(hTest, cbShort == 0);
    1239     int rc = RTUtf16CalcLatin1LenEx(g_wszAll, 255, &cch_szAll);
    1240     RTTEST_CHECK(hTest, (cch_szAll == 255));
    1241     rc = RTUtf16CalcLatin1LenEx(g_wszAll, RTSTR_MAX, &cch_szAll);
    1242     RTTEST_CHECK_RC(hTest, rc, VERR_NO_TRANSLATION);
    1243     char *psz = NULL;
    1244     RTUTF16 wszShort[256] = { 0 };
    1245     for (unsigned i = 0; i < 255; ++i)
    1246         wszShort[i] = i + 1;
    1247     cbShort = RTUtf16CalcLatin1Len(wszShort);
    1248     RTTEST_CHECK(hTest, cbShort == 255);
    1249     rc = RTUtf16ToLatin1(wszShort, &psz);
    1250     RTTEST_CHECK_RC_OK(hTest, rc);
    1251     if (RT_SUCCESS(rc))
    1252     {
    1253         RTTEST_CHECK(hTest, (strlen(psz) == 255));
    1254         for (unsigned i = 0, j = 1; psz[i] != '\0'; ++i, ++j)
    1255             if (psz[i] != (char) j)
    1256             {
    1257                 RTTestFailed(hTest, "conversion of g_wszAll to Latin1 failed at position %u\n", i);
    1258                 break;
    1259             }
    1260     }
    1261     RTStrFree(psz);
    1262     rc = RTUtf16ToLatin1(g_wszAll, &psz);
    1263     RTTEST_CHECK_RC(hTest, rc, VERR_NO_TRANSLATION);
    1264     char sz[512];
    1265     char *psz2 = &sz[0];
    1266     size_t cchActual = 0;
    1267     rc = RTUtf16ToLatin1Ex(g_wszAll, sizeof(sz) - 1, &psz2, sizeof(sz),
    1268                            &cchActual);
    1269     RTTEST_CHECK_RC(hTest, rc, VERR_NO_TRANSLATION);
    1270     RTTEST_CHECK_MSG(hTest, cchActual == 0,
    1271                      (hTest, "cchActual=%lu\n", cchActual));
    1272     rc = RTUtf16ToLatin1Ex(g_wszAll, 255, &psz2, sizeof(sz),
    1273                            &cchActual);
    1274     RTTEST_CHECK_RC_OK(hTest, rc);
    1275     if (RT_SUCCESS(rc))
    1276     {
    1277         RTTEST_CHECK(hTest, (cchActual == 255));
    1278         RTTEST_CHECK(hTest, (cchActual == strlen(sz)));
    1279         for (unsigned i = 0, j = 1; psz2[i] != '\0'; ++i, ++j)
    1280             if (psz2[i] != (char) j)
    1281             {
    1282                 RTTestFailed(hTest, "second conversion of g_wszAll to Latin1 failed at position %u\n", i);
    1283                 break;
    1284             }
    1285     }
    1286     rc = RTUtf16ToLatin1Ex(g_wszAll, 128, &psz2, 128, &cchActual);
    1287     RTTEST_CHECK_RC(hTest, rc, VERR_BUFFER_OVERFLOW);
    1288     RTTEST_CHECK_MSG(hTest, cchActual == 128,
    1289                      (hTest, "cchActual=%lu\n", cchActual));
    1290     rc = RTUtf16ToLatin1Ex(g_wszAll, 255, &psz, 0, &cchActual);
    1291     RTTEST_CHECK_RC_OK(hTest, rc);
    1292     if (RT_SUCCESS(rc))
    1293     {
    1294         RTTEST_CHECK(hTest, (cchActual == 255));
    1295         RTTEST_CHECK(hTest, (cchActual == strlen(psz)));
    1296         for (unsigned i = 0, j = 1; psz[i] != '\0'; ++i, ++j)
    1297             if (   ((j < 0x100) && (psz[i] != (char) j))
    1298                 || ((j > 0xff) && psz[i] != '?'))
    1299             {
    1300                 RTTestFailed(hTest, "third conversion of g_wszAll to Latin1 failed at position %u\n", i);
    1301                 break;
    1302             }
    1303     }
    1304     const char *pszBad = "H\0e\0l\0l\0o\0\0\xDC\0\xD8\0";
    1305     rc = RTUtf16ToLatin1Ex((RTUTF16 *) pszBad, RTSTR_MAX, &psz2, sizeof(sz),
    1306                            &cchActual);
    1307     RTTEST_CHECK_RC(hTest, rc, VERR_INVALID_UTF16_ENCODING);
    1308     RTStrFree(psz);
    1309 
    1310     /* Test Latin1 -> Utf16 */
    1311     const char *pszLat1 = "\x01\x20\x40\x80\x81";
    1312     RTTEST_CHECK(hTest, RTLatin1CalcUtf16Len(pszLat1) == 5);
    1313     rc = RTLatin1CalcUtf16LenEx(pszLat1, 3, &cchActual);
    1314     RTTEST_CHECK_RC_OK(hTest, rc);
    1315     if (RT_SUCCESS(rc))
    1316         RTTEST_CHECK(hTest, cchActual == 3);
    1317     rc = RTLatin1CalcUtf16LenEx(pszLat1, RTSTR_MAX, &cchActual);
    1318     RTTEST_CHECK_RC_OK(hTest, rc);
    1319     if (RT_SUCCESS(rc))
    1320         RTTEST_CHECK(hTest, cchActual == 5);
    1321     RTUTF16 *pwc = NULL;
    1322     RTUTF16 wc[6];
    1323     RTUTF16 *pwc2 = &wc[0];
    1324     size_t cwActual = 0;
    1325     rc = RTLatin1ToUtf16(pszLat1, &pwc);
    1326     RTTEST_CHECK_RC_OK(hTest, rc);
    1327     if (RT_SUCCESS(rc))
    1328         RTTEST_CHECK(hTest,    (pwc[0] == 1) && (pwc[1] == 0x20)
    1329                             && (pwc[2] == 0x40) && (pwc[3] == 0x80)
    1330                             && (pwc[4] == 0x81) && (pwc[5] == '\0'));
    1331     RTUtf16Free(pwc);
    1332     rc = RTLatin1ToUtf16Ex(pszLat1, RTSTR_MAX, &pwc, 0, &cwActual);
    1333     RTTEST_CHECK_RC_OK(hTest, rc);
    1334     if (RT_SUCCESS(rc))
    1335     {
    1336         RTTEST_CHECK(hTest, (cwActual == 5));
    1337         RTTEST_CHECK(hTest,    (pwc[0] == 1) && (pwc[1] == 0x20)
    1338                             && (pwc[2] == 0x40) && (pwc[3] == 0x80)
    1339                             && (pwc[4] == 0x81) && (pwc[5] == '\0'));
    1340     }
    1341     RTUtf16Free(pwc);
    1342     rc = RTLatin1ToUtf16Ex(pszLat1, RTSTR_MAX, &pwc, 0, NULL);
    1343     RTTEST_CHECK_RC_OK(hTest, rc);
    1344     if (RT_SUCCESS(rc))
    1345         RTTEST_CHECK(hTest,    (pwc[0] == 1) && (pwc[1] == 0x20)
    1346                             && (pwc[2] == 0x40) && (pwc[3] == 0x80)
    1347                             && (pwc[4] == 0x81) && (pwc[5] == '\0'));
    1348     RTUtf16Free(pwc);
    1349     rc = RTLatin1ToUtf16Ex(pszLat1, RTSTR_MAX, &pwc2, RT_ELEMENTS(wc),
    1350                            &cwActual);
    1351     RTTEST_CHECK_RC_OK(hTest, rc);
    1352     if (RT_SUCCESS(rc))
    1353     {
    1354         RTTEST_CHECK(hTest, (cwActual == 5));
    1355         RTTEST_CHECK(hTest,    (wc[0] == 1) && (wc[1] == 0x20)
    1356                             && (wc[2] == 0x40) && (wc[3] == 0x80)
    1357                             && (wc[4] == 0x81) && (wc[5] == '\0'));
    1358     }
    1359     rc = RTLatin1ToUtf16Ex(pszLat1, 3, &pwc2, RT_ELEMENTS(wc),
    1360                            &cwActual);
    1361     RTTEST_CHECK_RC_OK(hTest, rc);
    1362     if (RT_SUCCESS(rc))
    1363     {
    1364         RTTEST_CHECK(hTest, (cwActual == 3));
    1365         RTTEST_CHECK(hTest,    (wc[0] == 1) && (wc[1] == 0x20)
    1366                             && (wc[2] == 0x40) && (wc[3] == '\0'));
    1367     }
    1368     rc = RTLatin1ToUtf16Ex(pszLat1, RTSTR_MAX, &pwc2, RT_ELEMENTS(wc) - 1,
    1369                            &cwActual);
    1370     RTTEST_CHECK_RC(hTest, rc, VERR_BUFFER_OVERFLOW);
    1371     RTTEST_CHECK(hTest, (cwActual == 5));
    1372     RTTestSubDone(hTest);
    1373 }
    1374 
    1375 
    1376 static void testNoTransation(RTTEST hTest)
    1377 {
    1378 
    1379     /*
    1380      * Try trigger a VERR_NO_TRANSLATION error in convert to
    1381      * current CP to latin-1.
    1382      */
    1383     const RTUTF16 s_swzTest1[] = { 0x2358, 0x2242, 0x2357, 0x2359,  0x22f9, 0x2c4e, 0x0030, 0x0060,
    1384                                    0x0092, 0x00c1, 0x00f2, 0x1f80,  0x0088, 0x2c38, 0x2c30, 0x0000 };
    1385     char *pszTest1;
    1386     int rc = RTUtf16ToUtf8(s_swzTest1, &pszTest1);
    1387     RTTESTI_CHECK_RC_RETV(rc, VINF_SUCCESS);
    1388 
    1389     RTTestSub(hTest, "VERR_NO_TRANSLATION/RTStrUtf8ToCurrentCP");
    1390     char *pszOut;
    1391     rc = RTStrUtf8ToCurrentCP(&pszOut, pszTest1);
    1392     if (RT_SUCCESS(rc))
    1393     {
    1394         RTTESTI_CHECK(!strcmp(pszOut, pszTest1));
    1395         RTTestIPrintf(RTTESTLVL_ALWAYS, "CurrentCP is UTF-8 or similar\n");
    1396         RTStrFree(pszOut);
    1397     }
    1398     else
    1399         RTTESTI_CHECK_RC(rc, VERR_NO_TRANSLATION);
    1400 
    1401     RTTestSub(hTest, "VERR_NO_TRANSLATION/RTUtf16ToLatin1");
    1402     rc = RTUtf16ToLatin1(s_swzTest1, &pszOut);
    1403     RTTESTI_CHECK_RC(rc, VERR_NO_TRANSLATION);
    1404     if (RT_SUCCESS(rc))
    1405         RTStrFree(pszOut);
    1406 
    1407     RTStrFree(pszTest1);
    1408     RTTestSubDone(hTest);
     158    RTTestSub(hTest, "UTF-8 upper/lower encoding assumption");
     159
     160#define CHECK_EQUAL(str1, str2) \
     161    do \
     162    { \
     163        RTTESTI_CHECK(strlen((str1).c_str()) == (str1).length()); \
     164        RTTESTI_CHECK((str1).length() == (str2).length()); \
     165        RTTESTI_CHECK(mymemcmp((str1).c_str(), (str2).c_str(), (str2).length() + 1) == 0); \
     166    } while (0)
     167
     168    iprt::MiniString strTmp;
     169    char szDst[16];
     170
     171    /* Collect all upper and lower case code points. */
     172    iprt::MiniString strLower("");
     173    strLower.reserve(_4M);
     174
     175    iprt::MiniString strUpper("");
     176    strUpper.reserve(_4M);
     177
     178    for (RTUNICP uc = 1; uc <= 0x10fffd; uc++)
     179    {
     180        if (RTUniCpIsLower(uc))
     181        {
     182            RTTESTI_CHECK_MSG(uc < 0xd800 || (uc > 0xdfff && uc != 0xfffe && uc != 0xffff), ("%#x\n", uc));
     183            strLower.appendCodePoint(uc);
     184        }
     185        if (RTUniCpIsUpper(uc))
     186        {
     187            RTTESTI_CHECK_MSG(uc < 0xd800 || (uc > 0xdfff && uc != 0xfffe && uc != 0xffff), ("%#x\n", uc));
     188            strUpper.appendCodePoint(uc);
     189        }
     190    }
     191    RTTESTI_CHECK(strlen(strLower.c_str()) == strLower.length());
     192    RTTESTI_CHECK(strlen(strUpper.c_str()) == strUpper.length());
     193
     194    /* Fold each code point in the lower case string and check that it encodes
     195       into the same or less number of bytes. */
     196    size_t      cch    = 0;
     197    const char *pszCur = strLower.c_str();
     198    iprt::MiniString    strUpper2("");
     199    strUpper2.reserve(strLower.length() + 64);
     200    for (;;)
     201    {
     202        RTUNICP             ucLower;
     203        const char * const  pszPrev   = pszCur;
     204        RTTESTI_CHECK_RC_BREAK(RTStrGetCpEx(&pszCur, &ucLower), VINF_SUCCESS);
     205        size_t const        cchSrc    = pszCur - pszPrev;
     206        if (!ucLower)
     207            break;
     208
     209        RTUNICP const       ucUpper   = RTUniCpToUpper(ucLower);
     210        const char         *pszDstEnd = RTStrPutCp(szDst, ucUpper);
     211        size_t const        cchDst    = pszDstEnd - &szDst[0];
     212        RTTESTI_CHECK_MSG(cchSrc >= cchDst,
     213                          ("ucLower=%#x %u bytes;  ucUpper=%#x %u bytes\n",
     214                           ucLower, cchSrc, ucUpper, cchDst));
     215        cch += cchDst;
     216        strUpper2.appendCodePoint(ucUpper);
     217
     218        /* roundtrip stability */
     219        RTUNICP const       ucUpper2  = RTUniCpToUpper(ucUpper);
     220        RTTESTI_CHECK_MSG(ucUpper2 == ucUpper, ("ucUpper2=%#x ucUpper=%#x\n", ucUpper2, ucUpper));
     221
     222        RTUNICP const       ucLower2  = RTUniCpToLower(ucUpper);
     223        RTUNICP const       ucUpper3  = RTUniCpToUpper(ucLower2);
     224        RTTESTI_CHECK_MSG(ucUpper3 == ucUpper, ("ucUpper3=%#x ucUpper=%#x\n", ucUpper3, ucUpper));
     225
     226        pszDstEnd = RTStrPutCp(szDst, ucLower2);
     227        size_t const        cchLower2 = pszDstEnd - &szDst[0];
     228        RTTESTI_CHECK_MSG(cchDst == cchLower2,
     229                          ("ucLower2=%#x %u bytes;  ucUpper=%#x %u bytes\n",
     230                           ucLower2, cchLower2, ucUpper, cchDst));
     231    }
     232    RTTESTI_CHECK(strlen(strUpper2.c_str()) == strUpper2.length());
     233    RTTESTI_CHECK_MSG(cch == strUpper2.length(), ("cch=%u length()=%u\n", cch, strUpper2.length()));
     234
     235    /* the toUpper method shall do the same thing. */
     236    strTmp = strLower;      CHECK_EQUAL(strTmp, strLower);
     237    strTmp.toUpper();       CHECK_EQUAL(strTmp, strUpper2);
     238
     239    /* Ditto for the upper case string. */
     240    cch    = 0;
     241    pszCur = strUpper.c_str();
     242    iprt::MiniString    strLower2("");
     243    strLower2.reserve(strUpper.length() + 64);
     244    for (;;)
     245    {
     246        RTUNICP             ucUpper;
     247        const char * const  pszPrev   = pszCur;
     248        RTTESTI_CHECK_RC_BREAK(RTStrGetCpEx(&pszCur, &ucUpper), VINF_SUCCESS);
     249        size_t const        cchSrc    = pszCur - pszPrev;
     250        if (!ucUpper)
     251            break;
     252
     253        RTUNICP const       ucLower   = RTUniCpToLower(ucUpper);
     254        const char         *pszDstEnd = RTStrPutCp(szDst, ucLower);
     255        size_t const        cchDst    = pszDstEnd - &szDst[0];
     256        RTTESTI_CHECK_MSG(cchSrc >= cchDst,
     257                          ("ucUpper=%#x %u bytes;  ucLower=%#x %u bytes\n",
     258                           ucUpper, cchSrc, ucLower, cchDst));
     259
     260        cch += cchDst;
     261        strLower2.appendCodePoint(ucLower);
     262
     263        /* roundtrip stability */
     264        RTUNICP const       ucLower2  = RTUniCpToLower(ucLower);
     265        RTTESTI_CHECK_MSG(ucLower2 == ucLower, ("ucLower2=%#x ucLower=%#x\n", ucLower2, ucLower));
     266
     267        RTUNICP const       ucUpper2  = RTUniCpToUpper(ucLower);
     268        RTUNICP const       ucLower3  = RTUniCpToLower(ucUpper2);
     269        RTTESTI_CHECK_MSG(ucLower3 == ucLower, ("ucLower3=%#x ucLower=%#x\n", ucLower3, ucLower));
     270
     271        pszDstEnd = RTStrPutCp(szDst, ucUpper2);
     272        size_t const        cchUpper2 = pszDstEnd - &szDst[0];
     273        RTTESTI_CHECK_MSG(cchDst == cchUpper2,
     274                          ("ucUpper2=%#x %u bytes;  ucLower=%#x %u bytes\n",
     275                           ucUpper2, cchUpper2, ucLower, cchDst));
     276    }
     277    RTTESTI_CHECK(strlen(strLower2.c_str()) == strLower2.length());
     278    RTTESTI_CHECK_MSG(cch == strLower2.length(), ("cch=%u length()=%u\n", cch, strLower2.length()));
     279
     280    strTmp = strUpper;      CHECK_EQUAL(strTmp, strUpper);
     281    strTmp.toLower();       CHECK_EQUAL(strTmp, strLower2);
     282
     283    /* Checks of folding stability when nothing shall change. */
     284    strTmp = strUpper;      CHECK_EQUAL(strTmp, strUpper);
     285    strTmp.toUpper();       CHECK_EQUAL(strTmp, strUpper);
     286    strTmp.toUpper();       CHECK_EQUAL(strTmp, strUpper);
     287    strTmp.toUpper();       CHECK_EQUAL(strTmp, strUpper);
     288
     289    strTmp = strUpper2;     CHECK_EQUAL(strTmp, strUpper2);
     290    strTmp.toUpper();       CHECK_EQUAL(strTmp, strUpper2);
     291    strTmp.toUpper();       CHECK_EQUAL(strTmp, strUpper2);
     292    strTmp.toUpper();       CHECK_EQUAL(strTmp, strUpper2);
     293
     294    strTmp = strLower;      CHECK_EQUAL(strTmp, strLower);
     295    strTmp.toLower();       CHECK_EQUAL(strTmp, strLower);
     296    strTmp.toLower();       CHECK_EQUAL(strTmp, strLower);
     297    strTmp.toLower();       CHECK_EQUAL(strTmp, strLower);
     298
     299    strTmp = strLower2;     CHECK_EQUAL(strTmp, strLower2);
     300    strTmp.toLower();       CHECK_EQUAL(strTmp, strLower2);
     301    strTmp.toLower();       CHECK_EQUAL(strTmp, strLower2);
     302    strTmp.toLower();       CHECK_EQUAL(strTmp, strLower2);
     303
     304    /* Check folding stability for roundtrips. */
     305    strTmp = strUpper;      CHECK_EQUAL(strTmp, strUpper);
     306    strTmp.toLower();       CHECK_EQUAL(strTmp, strLower2);
     307    strTmp.toUpper();
     308    strTmp.toLower();       CHECK_EQUAL(strTmp, strLower2);
     309    strTmp.toUpper();
     310    strTmp.toLower();       CHECK_EQUAL(strTmp, strLower2);
     311
     312    strTmp = strLower;      CHECK_EQUAL(strTmp, strLower);
     313    strTmp.toUpper();       CHECK_EQUAL(strTmp, strUpper2);
     314    strTmp.toLower();
     315    strTmp.toUpper();       CHECK_EQUAL(strTmp, strUpper2);
     316    strTmp.toLower();
     317    strTmp.toUpper();       CHECK_EQUAL(strTmp, strUpper2);
    1409318}
    1410319
     
    1412321int main()
    1413322{
    1414     /*
    1415      * Init the runtime, test and say hello.
    1416      */
    1417     RTTEST hTest;
    1418     int rc = RTTestInitAndCreate("tstUtf8", &hTest);
    1419     if (rc)
    1420         return rc;
    1421     RTTestBanner(hTest);
    1422 
    1423     /*
    1424      * Run the test.
    1425      */
    1426     InitStrings();
    1427     test1(hTest);
    1428     test2(hTest);
    1429     test3(hTest);
    1430     TstRTStrXCmp(hTest);
    1431     TstRTStrPurgeEncoding(hTest);
    1432     testStrEnd(hTest);
    1433     testStrStr(hTest);
    1434     testMinistring(hTest);
    1435     testUtf8Latin1(hTest);
    1436     testUtf16Latin1(hTest);
    1437     testNoTransation(hTest);
    1438 
    1439     Benchmarks(hTest);
    1440 
    1441     /*
    1442      * Summary
    1443      */
    1444     return RTTestSummaryAndDestroy(hTest);
     323    RTTEST      hTest;
     324    RTEXITCODE  rcExit = RTTestInitAndCreate("tstIprtMiniString", &hTest);
     325    if (rcExit == RTEXITCODE_SUCCESS)
     326    {
     327        RTTestBanner(hTest);
     328
     329        test1(hTest);
     330        test2(hTest);
     331
     332        rcExit = RTTestSummaryAndDestroy(hTest);
     333    }
     334    return rcExit;
    1445335}
    1446336
  • trunk/src/VBox/Runtime/testcase/tstUtf8.cpp

    r33540 r33563  
    2929*******************************************************************************/
    3030#include <iprt/string.h>
     31
    3132#include <iprt/uni.h>
    32 #include <iprt/initterm.h>
    3333#include <iprt/uuid.h>
    3434#include <iprt/time.h>
     
    3737#include <iprt/assert.h>
    3838#include <iprt/err.h>
     39#include <iprt/rand.h>
    3940#include <iprt/test.h>
    40 #include <iprt/cpp/ministring.h>
    41 
    42 #include <stdlib.h> /** @todo use our random. */
    4341
    4442
     
    5250    do
    5351    {
    54         wc = (RTUTF16)((long long)rand() * 0xffff / RAND_MAX);
    55     } while ((wc >= 0xd800 && wc <= 0xdfff) || wc == 0);
     52        wc = (RTUTF16)RTRandU32Ex(1, 0xffff);
     53    } while (wc >= 0xd800 && wc <= 0xdfff);
    5654    return wc;
    5755}
     
    8785    RTTestSub(hTest, "Rand UTF-16 -> UTF-8 -> CP -> UTF-8");
    8886    pwszRand = (PRTUTF16)RTMemAlloc(31 * sizeof(*pwsz));
    89     srand((unsigned)RTTimeNanoTS());
    9087    for (int i = 0; i < 30; i++)
    9188        pwszRand[i] = GetRandUtf16();
     
    120117    RTTestSub(hTest, "Random UTF-16 -> UTF-8 -> UTF-16");
    121118    pwszRand = (PRTUTF16)RTMemAlloc(31 * sizeof(*pwsz));
    122     srand((unsigned)RTTimeNanoTS());
    123119    for (int i = 0; i < 30; i++)
    124120        pwszRand[i] = GetRandUtf16();
     
    154150    RTTestSub(hTest, "Random RTUtf16ToUtf8Ex + RTStrToUtf16");
    155151    pwszRand = (PRTUTF16)RTMemAlloc(31 * sizeof(*pwsz));
    156     srand((unsigned)RTTimeNanoTS());
    157152    for (int i = 0; i < 30; i++)
    158153        pwszRand[i] = GetRandUtf16();
     
    189184    RTTestSub(hTest, "Random RTUtf16ToUtf8 + RTStrToUtf16Ex");
    190185    pwszRand = (PRTUTF16)RTMemAlloc(31 * sizeof(*pwsz));
    191     srand((unsigned)RTTimeNanoTS());
    192186    for (int i = 0; i < 30; i++)
    193187        pwszRand[i] = GetRandUtf16();
     
    220214                     __LINE__, rc);
    221215    pwszRand = (PRTUTF16)RTMemAlloc(31 * sizeof(*pwsz));
    222     srand((unsigned)RTTimeNanoTS());
    223216    for (int i = 0; i < 30; i++)
    224217        pwszRand[i] = GetRandUtf16();
     
    237230    RTTestSub(hTest, "Random RTUtf16ToUtf8 + RTStrToUtf16Ex");
    238231    pwszRand = (PRTUTF16)RTMemAlloc(31 * sizeof(*pwsz));
    239     srand((unsigned)RTTimeNanoTS());
    240232    for (int i = 0; i < 30; i++)
    241233        pwszRand[i] = GetRandUtf16();
     
    998990
    999991
    1000 void testMinistring(RTTEST hTest)
    1001 {
    1002     RTTestSub(hTest, "class iprt::MiniString");
    1003 
    1004 #define CHECK(expr) \
    1005     do { \
    1006         if (!(expr)) \
    1007             RTTestFailed(hTest, "%d: FAILED %s", __LINE__, #expr); \
    1008     } while (0)
    1009 
    1010 #define CHECK_DUMP(expr, value) \
    1011     do { \
    1012         if (!(expr)) \
    1013             RTTestFailed(hTest, "%d: FAILED %s, got \"%s\"", __LINE__, #expr, value); \
    1014     } while (0)
    1015 
    1016 #define CHECK_DUMP_I(expr) \
    1017     do { \
    1018         if (!(expr)) \
    1019             RTTestFailed(hTest, "%d: FAILED %s, got \"%d\"", __LINE__, #expr, expr); \
    1020     } while (0)
    1021 
    1022     iprt::MiniString empty;
    1023     CHECK(empty.length() == 0);
    1024     CHECK(empty.capacity() == 0);
    1025 
    1026     iprt::MiniString sixbytes("12345");
    1027     CHECK(sixbytes.length() == 5);
    1028     CHECK(sixbytes.capacity() == 6);
    1029 
    1030     sixbytes.append(iprt::MiniString("678"));
    1031     CHECK(sixbytes.length() == 8);
    1032     CHECK(sixbytes.capacity() == 9);
    1033 
    1034     sixbytes.append("9a");
    1035     CHECK(sixbytes.length() == 10);
    1036     CHECK(sixbytes.capacity() == 11);
    1037 
    1038     char *psz = sixbytes.mutableRaw();
    1039         // 123456789a
    1040         //       ^
    1041         // 0123456
    1042     psz[6] = '\0';
    1043     sixbytes.jolt();
    1044     CHECK(sixbytes.length() == 6);
    1045     CHECK(sixbytes.capacity() == 7);
    1046 
    1047     iprt::MiniString morebytes("tobereplaced");
    1048     morebytes = "newstring ";
    1049     morebytes.append(sixbytes);
    1050 
    1051     CHECK_DUMP(morebytes == "newstring 123456", morebytes.c_str());
    1052 
    1053     iprt::MiniString third(morebytes);
    1054     third.reserve(100 * 1024);      // 100 KB
    1055     CHECK_DUMP(third == "newstring 123456", morebytes.c_str() );
    1056     CHECK(third.capacity() == 100 * 1024);
    1057     CHECK(third.length() == morebytes.length());          // must not have changed
    1058 
    1059     iprt::MiniString copy1(morebytes);
    1060     iprt::MiniString copy2 = morebytes;
    1061     CHECK(copy1 == copy2);
    1062 
    1063     copy1 = NULL;
    1064     CHECK(copy1.length() == 0);
    1065 
    1066     copy1 = "";
    1067     CHECK(copy1.length() == 0);
    1068 
    1069     CHECK(iprt::MiniString("abc") <  iprt::MiniString("def"));
    1070     CHECK(iprt::MiniString("abc") != iprt::MiniString("def"));
    1071     CHECK_DUMP_I(iprt::MiniString("def") > iprt::MiniString("abc"));
    1072     CHECK(iprt::MiniString("abc") == iprt::MiniString("abc"));
    1073 
    1074     copy2.setNull();
    1075     for (int i = 0; i < 100; ++i)
    1076     {
    1077         copy2.reserve(50);      // should be ignored after 50 loops
    1078         copy2.append("1");
    1079     }
    1080     CHECK(copy2.length() == 100);
    1081 
    1082     copy2.setNull();
    1083     for (int i = 0; i < 100; ++i)
    1084     {
    1085         copy2.reserve(50);      // should be ignored after 50 loops
    1086         copy2.append('1');
    1087     }
    1088     CHECK(copy2.length() == 100);
    1089 
    1090 #undef CHECK
    1091 #undef CHECK_DUMP
    1092 #undef CHECK_DUMP_I
    1093 }
    1094 
    1095 
    1096992void testUtf8Latin1(RTTEST hTest)
    1097993{
     
    13761272static void testNoTransation(RTTEST hTest)
    13771273{
    1378 
    13791274    /*
    13801275     * Try trigger a VERR_NO_TRANSLATION error in convert to
     
    14091304}
    14101305
     1306static void testGetPut(RTTEST hTest)
     1307{
     1308    /*
     1309     * Test RTStrPutCp, RTStrGetCp and RTStrGetCpEx.
     1310     */
     1311    RTTestSub(hTest, "RTStrPutCp, RTStrGetCp and RTStrGetCpEx");
     1312
     1313    RTUNICP uc = 0;
     1314    while (uc <= 0x10fffd)
     1315    {
     1316        /* Figure the range - skip illegal ranges. */
     1317        RTUNICP ucFirst = uc;
     1318        if (ucFirst - UINT32_C(0xd800) <= 0x7ff)
     1319            ucFirst = 0xe000;
     1320        else if (ucFirst == UINT32_C(0xfffe) || ucFirst == UINT32_C(0xffff))
     1321            ucFirst = 0x10000;
     1322
     1323        RTUNICP ucLast  = ucFirst + 1023;
     1324        if (ucLast - UINT32_C(0xd800) <= 0x7ff)
     1325            ucLast = 0xd7ff;
     1326        else if (ucLast == UINT32_C(0xfffe) || ucLast == UINT32_C(0xffff))
     1327            ucLast = 0xfffd;
     1328
     1329        /* Encode the range into a string, decode each code point as we go along. */
     1330        char sz1[8192];
     1331        char *pszDst = sz1;
     1332        for (uc = ucFirst; uc <= ucLast; uc++)
     1333        {
     1334            char *pszBefore = pszDst;
     1335            pszDst = RTStrPutCp(pszDst, uc);
     1336            RTTESTI_CHECK(pszBefore - pszDst < 6);
     1337
     1338            RTUNICP uc2 = RTStrGetCp(pszBefore);
     1339            RTTESTI_CHECK_MSG(uc2 == uc, ("uc2=%#x uc=%#x\n", uc2, uc));
     1340
     1341            const char *pszSrc = pszBefore;
     1342            RTUNICP uc3 = 42;
     1343            RTTESTI_CHECK_RC(RTStrGetCpEx(&pszSrc, &uc3), VINF_SUCCESS);
     1344            RTTESTI_CHECK_MSG(uc3 == uc, ("uc3=%#x uc=%#x\n", uc3, uc));
     1345            RTTESTI_CHECK_MSG(pszSrc == pszDst, ("pszSrc=%p pszDst=%p\n", pszSrc, pszDst));
     1346        }
     1347
     1348        /* Decode and re-encode it. */
     1349        const char *pszSrc = pszDst = sz1;
     1350        for (uc = ucFirst; uc <= ucLast; uc++)
     1351        {
     1352            RTUNICP uc2 = RTStrGetCp(pszSrc);
     1353            RTTESTI_CHECK_MSG(uc2 == uc, ("uc2=%#x uc=%#x\n", uc2, uc));
     1354
     1355            RTUNICP uc3 = 42;
     1356            RTTESTI_CHECK_RC(RTStrGetCpEx(&pszSrc, &uc3), VINF_SUCCESS);
     1357            RTTESTI_CHECK_MSG(uc3 == uc, ("uc3=%#x uc=%#x\n", uc3, uc));
     1358
     1359            pszDst = RTStrPutCp(pszDst, uc);
     1360            RTTESTI_CHECK_MSG(pszSrc == pszDst, ("pszSrc=%p pszDst=%p\n", pszSrc, pszDst));
     1361            pszSrc = pszDst;
     1362        }
     1363
     1364        /* Decode and wipe it (checking compiler optimizations). */
     1365        pszSrc = pszDst = sz1;
     1366        for (uc = ucFirst; uc <= ucLast; uc++)
     1367        {
     1368            RTUNICP uc2 = RTStrGetCp(pszSrc);
     1369            RTTESTI_CHECK_MSG(uc2 == uc, ("uc2=%#x uc=%#x\n", uc2, uc));
     1370
     1371            RTUNICP uc3 = 42;
     1372            RTTESTI_CHECK_RC(RTStrGetCpEx(&pszSrc, &uc3), VINF_SUCCESS);
     1373            RTTESTI_CHECK_MSG(uc3 == uc, ("uc3=%#x uc=%#x\n", uc3, uc));
     1374
     1375            pszDst = RTStrPutCp(pszDst, 0);
     1376        }
     1377
     1378        /* advance */
     1379        uc = ucLast + 1;
     1380    }
     1381
     1382}
     1383
    14111384
    14121385int main()
     
    14161389     */
    14171390    RTTEST hTest;
    1418     int rc = RTTestInitAndCreate("tstUtf8", &hTest);
    1419     if (rc)
    1420         return rc;
     1391    RTEXITCODE rcExit = RTTestInitAndCreate("tstUtf8", &hTest);
     1392    if (rcExit != RTEXITCODE_SUCCESS)
     1393        return rcExit;
    14211394    RTTestBanner(hTest);
    14221395
    14231396    /*
    1424      * Run the test.
     1397     * Run the tests.
    14251398     */
    14261399    InitStrings();
     
    14321405    testStrEnd(hTest);
    14331406    testStrStr(hTest);
    1434     testMinistring(hTest);
    14351407    testUtf8Latin1(hTest);
    14361408    testUtf16Latin1(hTest);
    14371409    testNoTransation(hTest);
     1410    testGetPut(hTest);
    14381411
    14391412    Benchmarks(hTest);
Note: See TracChangeset for help on using the changeset viewer.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette