Index: trunk/src/VBox/Main/glue/string.cpp
===================================================================
--- trunk/src/VBox/Main/glue/string.cpp	(revision 33562)
+++ trunk/src/VBox/Main/glue/string.cpp	(revision 33563)
@@ -115,5 +115,5 @@
                                   &m_psz,           // char **ppsz: output buffer
                                   0,                // size_t cch: if 0, func allocates buffer in *ppsz
-                                  &m_cbLength);     // size_t *pcch: receives the size of the output string, excluding the terminator.
+                                  &m_cch);          // size_t *pcch: receives the size of the output string, excluding the terminator.
         if (RT_FAILURE(vrc))
         {
@@ -124,14 +124,14 @@
 
             // @todo what do we do with bad input strings? throw also? for now just keep an empty string
-            m_cbLength = 0;
+            m_cch = 0;
             m_cbAllocated = 0;
             m_psz = NULL;
         }
         else
-            m_cbAllocated = m_cbLength + 1;
+            m_cbAllocated = m_cch + 1;
     }
     else
     {
-        m_cbLength = 0;
+        m_cch = 0;
         m_cbAllocated = 0;
         m_psz = NULL;
@@ -143,5 +143,5 @@
     if (!format || !*format)
     {
-        m_cbLength = 0;
+        m_cch = 0;
         m_cbAllocated = 0;
         m_psz = NULL;
@@ -149,6 +149,6 @@
     else
     {
-        m_cbLength = RTStrAPrintfV(&m_psz, format, args);
-        m_cbAllocated = m_cbLength + 1;
+        m_cch = RTStrAPrintfV(&m_psz, format, args);
+        m_cbAllocated = m_cch + 1;
     }
 }
Index: trunk/src/VBox/Runtime/common/string/ministring.cpp
===================================================================
--- trunk/src/VBox/Runtime/common/string/ministring.cpp	(revision 33562)
+++ trunk/src/VBox/Runtime/common/string/ministring.cpp	(revision 33563)
@@ -8,5 +8,5 @@
 
 /*
- * Copyright (C) 2007-2009 Oracle Corporation
+ * Copyright (C) 2007-2010 Oracle Corporation
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
@@ -28,27 +28,44 @@
  */
 
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
 #include <iprt/cpp/ministring.h>
-
 using namespace iprt;
 
+
+/*******************************************************************************
+*   Global Variables                                                           *
+*******************************************************************************/
 const size_t MiniString::npos = ~(size_t)0;
 
+/*******************************************************************************
+*   Defined Constants And Macros                                               *
+*******************************************************************************/
+/** Allocation block alignment used when appending bytes to a string. */
+#define IPRT_MINISTRING_APPEND_ALIGNMENT    64
+
+
 MiniString &MiniString::append(const MiniString &that)
 {
-    size_t lenThat = that.length();
-    if (lenThat)
-    {
-        size_t lenThis = length();
-        size_t cbBoth = lenThis + lenThat + 1;
-
-        reserve(cbBoth);
-            // calls realloc(cbBoth) and sets m_cbAllocated; may throw bad_alloc.
-#ifndef RT_EXCEPTIONS_ENABLED
-        AssertRelease(capacity() >= cbBoth);
-#endif
-
-        memcpy(m_psz + lenThis, that.m_psz, lenThat);
-        m_psz[lenThis + lenThat] = '\0';
-        m_cbLength = cbBoth - 1;
+    size_t cchThat = that.length();
+    if (cchThat)
+    {
+        size_t cchThis = length();
+        size_t cchBoth = cchThis + cchThat;
+
+        if (cchBoth >= m_cbAllocated)
+        {
+            reserve(RT_ALIGN_Z(cchBoth + 1, IPRT_MINISTRING_APPEND_ALIGNMENT));
+            // calls realloc(cchBoth + 1) and sets m_cbAllocated; may throw bad_alloc.
+#ifndef RT_EXCEPTIONS_ENABLED
+            AssertRelease(capacity() > cchBoth);
+#endif
+        }
+
+        memcpy(m_psz + cchThis, that.m_psz, cchThat);
+        m_psz[cchBoth] = '\0';
+        m_cch = cchBoth;
     }
     return *this;
@@ -61,37 +78,70 @@
     {
         size_t cchThis = length();
-        size_t cbBoth = cchThis + cchThat + 1;
-
-        reserve(cbBoth);
+        size_t cchBoth = cchThis + cchThat;
+
+        if (cchBoth >= m_cbAllocated)
+        {
+            reserve(RT_ALIGN_Z(cchBoth + 1, IPRT_MINISTRING_APPEND_ALIGNMENT));
+            // calls realloc(cchBoth + 1) and sets m_cbAllocated; may throw bad_alloc.
+#ifndef RT_EXCEPTIONS_ENABLED
+            AssertRelease(capacity() > cchBoth);
+#endif
+        }
+
+        memcpy(&m_psz[cchThis], pszThat, cchThat);
+        m_psz[cchBoth] = '\0';
+        m_cch = cchBoth;
+    }
+    return *this;
+}
+
+MiniString& MiniString::append(char ch)
+{
+    Assert((unsigned char)ch < 0x80);                  /* Don't create invalid UTF-8. */
+    if (ch)
+    {
+        // allocate in chunks of 20 in case this gets called several times
+        if (m_cch + 1 >= m_cbAllocated)
+        {
+            reserve(RT_ALIGN_Z(m_cch + 2, IPRT_MINISTRING_APPEND_ALIGNMENT));
             // calls realloc(cbBoth) and sets m_cbAllocated; may throw bad_alloc.
 #ifndef RT_EXCEPTIONS_ENABLED
-        AssertRelease(capacity() >= cbBoth);
-#endif
-
-        memcpy(m_psz + cchThis, pszThat, cchThat);
-        m_psz[cbBoth - 1] = '\0';
-        m_cbLength = cbBoth - 1;
-    }
-    return *this;
-}
-
-MiniString& MiniString::append(char c)
-{
-    if (c)
-    {
-        // allocate in chunks of 20 in case this gets called several times
-        if (m_cbLength + 1 >= m_cbAllocated)
-        {
-            reserve(m_cbLength + 10);
-            // calls realloc(cbBoth) and sets m_cbAllocated; may throw bad_alloc.
-#ifndef RT_EXCEPTIONS_ENABLED
-            AssertRelease(capacity() >= m_cbLength + 1);
-#endif
-        }
-
-        m_psz[m_cbLength] = c;
-        m_psz[m_cbLength + 1] = '\0';
-        ++m_cbLength;
-    }
+            AssertRelease(capacity() > m_cch + 1);
+#endif
+        }
+
+        m_psz[m_cch] = ch;
+        m_psz[++m_cch] = '\0';
+    }
+    return *this;
+}
+
+MiniString &MiniString::appendCodePoint(RTUNICP uc)
+{
+    /*
+     * Single byte encoding.
+     */
+    if (uc < 0x80)
+        return MiniString::append((char)uc);
+
+    /*
+     * Multibyte encoding.
+     * Assume max encoding length when resizing the string, that's simpler.
+     */
+    AssertReturn(uc <= UINT32_C(0x7fffffff), *this);
+
+    if (m_cch + 6 >= m_cbAllocated)
+    {
+        reserve(RT_ALIGN_Z(m_cch + 6 + 1, IPRT_MINISTRING_APPEND_ALIGNMENT));
+        // calls realloc(cbBoth) and sets m_cbAllocated; may throw bad_alloc.
+#ifndef RT_EXCEPTIONS_ENABLED
+        AssertRelease(capacity() > m_cch + 6);
+#endif
+    }
+
+    char *pszNext = RTStrPutCp(&m_psz[m_cch], uc);
+    m_cch = pszNext - m_psz;
+    *pszNext = '\0';
+
     return *this;
 }
@@ -148,5 +198,5 @@
 #endif
                 memcpy(ret.m_psz, pFirst, cbCopy);
-                ret.m_cbLength = cbCopy;
+                ret.m_cch = cbCopy;
                 ret.m_psz[cbCopy] = '\0';
             }
Index: trunk/src/VBox/Runtime/testcase/Makefile.kmk
===================================================================
--- trunk/src/VBox/Runtime/testcase/Makefile.kmk	(revision 33562)
+++ trunk/src/VBox/Runtime/testcase/Makefile.kmk	(revision 33563)
@@ -68,4 +68,5 @@
 	tstRTHeapSimple \
 	tstRTInlineAsm \
+	tstIprtMiniString \
 	tstLdr \
 	tstLdrLoad \
@@ -257,4 +258,7 @@
 tstRTInlineAsmPIC3_DEFS = PIC
 
+tstIprtMiniString_TEMPLATE = VBOXR3TSTEXE
+tstIprtMiniString_SOURCES = tstIprtMiniString.cpp
+
 tstLdr_SOURCES = tstLdr.cpp
 
Index: trunk/src/VBox/Runtime/testcase/tstIprtMiniString.cpp
===================================================================
--- trunk/src/VBox/Runtime/testcase/tstIprtMiniString.cpp	(revision 33563)
+++ trunk/src/VBox/Runtime/testcase/tstIprtMiniString.cpp	(revision 33563)
@@ -0,0 +1,336 @@
+/* $Id$ */
+/** @file
+ * IPRT Testcase - iprt::MiniString.
+ */
+
+/*
+ * Copyright (C) 2006-2010 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include <iprt/cpp/ministring.h>
+
+#include <iprt/err.h>
+#include <iprt/mem.h>
+#include <iprt/string.h>
+#include <iprt/test.h>
+#include <iprt/uni.h>
+
+
+
+static void test1(RTTEST hTest)
+{
+    RTTestSub(hTest, "Basics");
+
+#define CHECK(expr) RTTESTI_CHECK(expr)
+#define CHECK_DUMP(expr, value) \
+    do { \
+        if (!(expr)) \
+            RTTestFailed(hTest, "%d: FAILED %s, got \"%s\"", __LINE__, #expr, value); \
+    } while (0)
+
+#define CHECK_DUMP_I(expr) \
+    do { \
+        if (!(expr)) \
+            RTTestFailed(hTest, "%d: FAILED %s, got \"%d\"", __LINE__, #expr, expr); \
+    } while (0)
+
+    iprt::MiniString empty;
+    CHECK(empty.length() == 0);
+    CHECK(empty.capacity() == 0);
+
+    iprt::MiniString sixbytes("12345");
+    CHECK(sixbytes.length() == 5);
+    CHECK(sixbytes.capacity() == 6);
+
+    sixbytes.append(iprt::MiniString("678"));
+    CHECK(sixbytes.length() == 8);
+    CHECK(sixbytes.capacity() >= 9);
+
+    sixbytes.append("9a");
+    CHECK(sixbytes.length() == 10);
+    CHECK(sixbytes.capacity() >= 11);
+
+    char *psz = sixbytes.mutableRaw();
+        // 123456789a
+        //       ^
+        // 0123456
+    psz[6] = '\0';
+    sixbytes.jolt();
+    CHECK(sixbytes.length() == 6);
+    CHECK(sixbytes.capacity() == 7);
+
+    iprt::MiniString morebytes("tobereplaced");
+    morebytes = "newstring ";
+    morebytes.append(sixbytes);
+
+    CHECK_DUMP(morebytes == "newstring 123456", morebytes.c_str());
+
+    iprt::MiniString third(morebytes);
+    third.reserve(100 * 1024);      // 100 KB
+    CHECK_DUMP(third == "newstring 123456", morebytes.c_str() );
+    CHECK(third.capacity() == 100 * 1024);
+    CHECK(third.length() == morebytes.length());          // must not have changed
+
+    iprt::MiniString copy1(morebytes);
+    iprt::MiniString copy2 = morebytes;
+    CHECK(copy1 == copy2);
+
+    copy1 = NULL;
+    CHECK(copy1.length() == 0);
+
+    copy1 = "";
+    CHECK(copy1.length() == 0);
+
+    CHECK(iprt::MiniString("abc") <  iprt::MiniString("def"));
+    CHECK(iprt::MiniString("abc") != iprt::MiniString("def"));
+    CHECK_DUMP_I(iprt::MiniString("def") > iprt::MiniString("abc"));
+    CHECK(iprt::MiniString("abc") == iprt::MiniString("abc"));
+
+    CHECK(iprt::MiniString("abc") <  "def");
+    CHECK(iprt::MiniString("abc") != "def");
+    CHECK_DUMP_I(iprt::MiniString("def") > "abc");
+    CHECK(iprt::MiniString("abc") == "abc");
+
+    CHECK(iprt::MiniString("abc").equals("abc"));
+    CHECK(!iprt::MiniString("abc").equals("def"));
+    CHECK(iprt::MiniString("abc").equalsIgnoreCase("Abc"));
+    CHECK(iprt::MiniString("abc").equalsIgnoreCase("ABc"));
+    CHECK(iprt::MiniString("abc").equalsIgnoreCase("ABC"));
+    CHECK(!iprt::MiniString("abc").equalsIgnoreCase("dBC"));
+
+    copy2.setNull();
+    for (int i = 0; i < 100; ++i)
+    {
+        copy2.reserve(50);      // should be ignored after 50 loops
+        copy2.append("1");
+    }
+    CHECK(copy2.length() == 100);
+
+    copy2.setNull();
+    for (int i = 0; i < 100; ++i)
+    {
+        copy2.reserve(50);      // should be ignored after 50 loops
+        copy2.append('1');
+    }
+    CHECK(copy2.length() == 100);
+
+#undef CHECK
+#undef CHECK_DUMP
+#undef CHECK_DUMP_I
+}
+
+
+static int mymemcmp(const char *psz1, const char *psz2, size_t cch)
+{
+    for (size_t off = 0; off < cch; off++)
+        if (psz1[off] != psz2[off])
+        {
+            RTTestIFailed("off=%#x  psz1=%.*Rhxs  psz2=%.*Rhxs\n", off,
+                          RT_MIN(cch - off, 8), &psz1[off],
+                          RT_MIN(cch - off, 8), &psz2[off]);
+            return psz1[off] > psz2[off] ? 1 : -1;
+        }
+    return 0;
+}
+
+static void test2(RTTEST hTest)
+{
+    RTTestSub(hTest, "UTF-8 upper/lower encoding assumption");
+
+#define CHECK_EQUAL(str1, str2) \
+    do \
+    { \
+        RTTESTI_CHECK(strlen((str1).c_str()) == (str1).length()); \
+        RTTESTI_CHECK((str1).length() == (str2).length()); \
+        RTTESTI_CHECK(mymemcmp((str1).c_str(), (str2).c_str(), (str2).length() + 1) == 0); \
+    } while (0)
+
+    iprt::MiniString strTmp;
+    char szDst[16];
+
+    /* Collect all upper and lower case code points. */
+    iprt::MiniString strLower("");
+    strLower.reserve(_4M);
+
+    iprt::MiniString strUpper("");
+    strUpper.reserve(_4M);
+
+    for (RTUNICP uc = 1; uc <= 0x10fffd; uc++)
+    {
+        if (RTUniCpIsLower(uc))
+        {
+            RTTESTI_CHECK_MSG(uc < 0xd800 || (uc > 0xdfff && uc != 0xfffe && uc != 0xffff), ("%#x\n", uc));
+            strLower.appendCodePoint(uc);
+        }
+        if (RTUniCpIsUpper(uc))
+        {
+            RTTESTI_CHECK_MSG(uc < 0xd800 || (uc > 0xdfff && uc != 0xfffe && uc != 0xffff), ("%#x\n", uc));
+            strUpper.appendCodePoint(uc);
+        }
+    }
+    RTTESTI_CHECK(strlen(strLower.c_str()) == strLower.length());
+    RTTESTI_CHECK(strlen(strUpper.c_str()) == strUpper.length());
+
+    /* Fold each code point in the lower case string and check that it encodes
+       into the same or less number of bytes. */
+    size_t      cch    = 0;
+    const char *pszCur = strLower.c_str();
+    iprt::MiniString    strUpper2("");
+    strUpper2.reserve(strLower.length() + 64);
+    for (;;)
+    {
+        RTUNICP             ucLower;
+        const char * const  pszPrev   = pszCur;
+        RTTESTI_CHECK_RC_BREAK(RTStrGetCpEx(&pszCur, &ucLower), VINF_SUCCESS);
+        size_t const        cchSrc    = pszCur - pszPrev;
+        if (!ucLower)
+            break;
+
+        RTUNICP const       ucUpper   = RTUniCpToUpper(ucLower);
+        const char         *pszDstEnd = RTStrPutCp(szDst, ucUpper);
+        size_t const        cchDst    = pszDstEnd - &szDst[0];
+        RTTESTI_CHECK_MSG(cchSrc >= cchDst,
+                          ("ucLower=%#x %u bytes;  ucUpper=%#x %u bytes\n",
+                           ucLower, cchSrc, ucUpper, cchDst));
+        cch += cchDst;
+        strUpper2.appendCodePoint(ucUpper);
+
+        /* roundtrip stability */
+        RTUNICP const       ucUpper2  = RTUniCpToUpper(ucUpper);
+        RTTESTI_CHECK_MSG(ucUpper2 == ucUpper, ("ucUpper2=%#x ucUpper=%#x\n", ucUpper2, ucUpper));
+
+        RTUNICP const       ucLower2  = RTUniCpToLower(ucUpper);
+        RTUNICP const       ucUpper3  = RTUniCpToUpper(ucLower2);
+        RTTESTI_CHECK_MSG(ucUpper3 == ucUpper, ("ucUpper3=%#x ucUpper=%#x\n", ucUpper3, ucUpper));
+
+        pszDstEnd = RTStrPutCp(szDst, ucLower2);
+        size_t const        cchLower2 = pszDstEnd - &szDst[0];
+        RTTESTI_CHECK_MSG(cchDst == cchLower2,
+                          ("ucLower2=%#x %u bytes;  ucUpper=%#x %u bytes\n",
+                           ucLower2, cchLower2, ucUpper, cchDst));
+    }
+    RTTESTI_CHECK(strlen(strUpper2.c_str()) == strUpper2.length());
+    RTTESTI_CHECK_MSG(cch == strUpper2.length(), ("cch=%u length()=%u\n", cch, strUpper2.length()));
+
+    /* the toUpper method shall do the same thing. */
+    strTmp = strLower;      CHECK_EQUAL(strTmp, strLower);
+    strTmp.toUpper();       CHECK_EQUAL(strTmp, strUpper2);
+
+    /* Ditto for the upper case string. */
+    cch    = 0;
+    pszCur = strUpper.c_str();
+    iprt::MiniString    strLower2("");
+    strLower2.reserve(strUpper.length() + 64);
+    for (;;)
+    {
+        RTUNICP             ucUpper;
+        const char * const  pszPrev   = pszCur;
+        RTTESTI_CHECK_RC_BREAK(RTStrGetCpEx(&pszCur, &ucUpper), VINF_SUCCESS);
+        size_t const        cchSrc    = pszCur - pszPrev;
+        if (!ucUpper)
+            break;
+
+        RTUNICP const       ucLower   = RTUniCpToLower(ucUpper);
+        const char         *pszDstEnd = RTStrPutCp(szDst, ucLower);
+        size_t const        cchDst    = pszDstEnd - &szDst[0];
+        RTTESTI_CHECK_MSG(cchSrc >= cchDst,
+                          ("ucUpper=%#x %u bytes;  ucLower=%#x %u bytes\n",
+                           ucUpper, cchSrc, ucLower, cchDst));
+
+        cch += cchDst;
+        strLower2.appendCodePoint(ucLower);
+
+        /* roundtrip stability */
+        RTUNICP const       ucLower2  = RTUniCpToLower(ucLower);
+        RTTESTI_CHECK_MSG(ucLower2 == ucLower, ("ucLower2=%#x ucLower=%#x\n", ucLower2, ucLower));
+
+        RTUNICP const       ucUpper2  = RTUniCpToUpper(ucLower);
+        RTUNICP const       ucLower3  = RTUniCpToLower(ucUpper2);
+        RTTESTI_CHECK_MSG(ucLower3 == ucLower, ("ucLower3=%#x ucLower=%#x\n", ucLower3, ucLower));
+
+        pszDstEnd = RTStrPutCp(szDst, ucUpper2);
+        size_t const        cchUpper2 = pszDstEnd - &szDst[0];
+        RTTESTI_CHECK_MSG(cchDst == cchUpper2,
+                          ("ucUpper2=%#x %u bytes;  ucLower=%#x %u bytes\n",
+                           ucUpper2, cchUpper2, ucLower, cchDst));
+    }
+    RTTESTI_CHECK(strlen(strLower2.c_str()) == strLower2.length());
+    RTTESTI_CHECK_MSG(cch == strLower2.length(), ("cch=%u length()=%u\n", cch, strLower2.length()));
+
+    strTmp = strUpper;      CHECK_EQUAL(strTmp, strUpper);
+    strTmp.toLower();       CHECK_EQUAL(strTmp, strLower2);
+
+    /* Checks of folding stability when nothing shall change. */
+    strTmp = strUpper;      CHECK_EQUAL(strTmp, strUpper);
+    strTmp.toUpper();       CHECK_EQUAL(strTmp, strUpper);
+    strTmp.toUpper();       CHECK_EQUAL(strTmp, strUpper);
+    strTmp.toUpper();       CHECK_EQUAL(strTmp, strUpper);
+
+    strTmp = strUpper2;     CHECK_EQUAL(strTmp, strUpper2);
+    strTmp.toUpper();       CHECK_EQUAL(strTmp, strUpper2);
+    strTmp.toUpper();       CHECK_EQUAL(strTmp, strUpper2);
+    strTmp.toUpper();       CHECK_EQUAL(strTmp, strUpper2);
+
+    strTmp = strLower;      CHECK_EQUAL(strTmp, strLower);
+    strTmp.toLower();       CHECK_EQUAL(strTmp, strLower);
+    strTmp.toLower();       CHECK_EQUAL(strTmp, strLower);
+    strTmp.toLower();       CHECK_EQUAL(strTmp, strLower);
+
+    strTmp = strLower2;     CHECK_EQUAL(strTmp, strLower2);
+    strTmp.toLower();       CHECK_EQUAL(strTmp, strLower2);
+    strTmp.toLower();       CHECK_EQUAL(strTmp, strLower2);
+    strTmp.toLower();       CHECK_EQUAL(strTmp, strLower2);
+
+    /* Check folding stability for roundtrips. */
+    strTmp = strUpper;      CHECK_EQUAL(strTmp, strUpper);
+    strTmp.toLower();       CHECK_EQUAL(strTmp, strLower2);
+    strTmp.toUpper();
+    strTmp.toLower();       CHECK_EQUAL(strTmp, strLower2);
+    strTmp.toUpper();
+    strTmp.toLower();       CHECK_EQUAL(strTmp, strLower2);
+
+    strTmp = strLower;      CHECK_EQUAL(strTmp, strLower);
+    strTmp.toUpper();       CHECK_EQUAL(strTmp, strUpper2);
+    strTmp.toLower();
+    strTmp.toUpper();       CHECK_EQUAL(strTmp, strUpper2);
+    strTmp.toLower();
+    strTmp.toUpper();       CHECK_EQUAL(strTmp, strUpper2);
+}
+
+
+int main()
+{
+    RTTEST      hTest;
+    RTEXITCODE  rcExit = RTTestInitAndCreate("tstIprtMiniString", &hTest);
+    if (rcExit == RTEXITCODE_SUCCESS)
+    {
+        RTTestBanner(hTest);
+
+        test1(hTest);
+        test2(hTest);
+
+        rcExit = RTTestSummaryAndDestroy(hTest);
+    }
+    return rcExit;
+}
+
Index: trunk/src/VBox/Runtime/testcase/tstUtf8.cpp
===================================================================
--- trunk/src/VBox/Runtime/testcase/tstUtf8.cpp	(revision 33562)
+++ trunk/src/VBox/Runtime/testcase/tstUtf8.cpp	(revision 33563)
@@ -29,6 +29,6 @@
 *******************************************************************************/
 #include <iprt/string.h>
+
 #include <iprt/uni.h>
-#include <iprt/initterm.h>
 #include <iprt/uuid.h>
 #include <iprt/time.h>
@@ -37,8 +37,6 @@
 #include <iprt/assert.h>
 #include <iprt/err.h>
+#include <iprt/rand.h>
 #include <iprt/test.h>
-#include <iprt/cpp/ministring.h>
-
-#include <stdlib.h> /** @todo use our random. */
 
 
@@ -52,6 +50,6 @@
     do
     {
-        wc = (RTUTF16)((long long)rand() * 0xffff / RAND_MAX);
-    } while ((wc >= 0xd800 && wc <= 0xdfff) || wc == 0);
+        wc = (RTUTF16)RTRandU32Ex(1, 0xffff);
+    } while (wc >= 0xd800 && wc <= 0xdfff);
     return wc;
 }
@@ -87,5 +85,4 @@
     RTTestSub(hTest, "Rand UTF-16 -> UTF-8 -> CP -> UTF-8");
     pwszRand = (PRTUTF16)RTMemAlloc(31 * sizeof(*pwsz));
-    srand((unsigned)RTTimeNanoTS());
     for (int i = 0; i < 30; i++)
         pwszRand[i] = GetRandUtf16();
@@ -120,5 +117,4 @@
     RTTestSub(hTest, "Random UTF-16 -> UTF-8 -> UTF-16");
     pwszRand = (PRTUTF16)RTMemAlloc(31 * sizeof(*pwsz));
-    srand((unsigned)RTTimeNanoTS());
     for (int i = 0; i < 30; i++)
         pwszRand[i] = GetRandUtf16();
@@ -154,5 +150,4 @@
     RTTestSub(hTest, "Random RTUtf16ToUtf8Ex + RTStrToUtf16");
     pwszRand = (PRTUTF16)RTMemAlloc(31 * sizeof(*pwsz));
-    srand((unsigned)RTTimeNanoTS());
     for (int i = 0; i < 30; i++)
         pwszRand[i] = GetRandUtf16();
@@ -189,5 +184,4 @@
     RTTestSub(hTest, "Random RTUtf16ToUtf8 + RTStrToUtf16Ex");
     pwszRand = (PRTUTF16)RTMemAlloc(31 * sizeof(*pwsz));
-    srand((unsigned)RTTimeNanoTS());
     for (int i = 0; i < 30; i++)
         pwszRand[i] = GetRandUtf16();
@@ -220,5 +214,4 @@
                      __LINE__, rc);
     pwszRand = (PRTUTF16)RTMemAlloc(31 * sizeof(*pwsz));
-    srand((unsigned)RTTimeNanoTS());
     for (int i = 0; i < 30; i++)
         pwszRand[i] = GetRandUtf16();
@@ -237,5 +230,4 @@
     RTTestSub(hTest, "Random RTUtf16ToUtf8 + RTStrToUtf16Ex");
     pwszRand = (PRTUTF16)RTMemAlloc(31 * sizeof(*pwsz));
-    srand((unsigned)RTTimeNanoTS());
     for (int i = 0; i < 30; i++)
         pwszRand[i] = GetRandUtf16();
@@ -998,100 +990,4 @@
 
 
-void testMinistring(RTTEST hTest)
-{
-    RTTestSub(hTest, "class iprt::MiniString");
-
-#define CHECK(expr) \
-    do { \
-        if (!(expr)) \
-            RTTestFailed(hTest, "%d: FAILED %s", __LINE__, #expr); \
-    } while (0)
-
-#define CHECK_DUMP(expr, value) \
-    do { \
-        if (!(expr)) \
-            RTTestFailed(hTest, "%d: FAILED %s, got \"%s\"", __LINE__, #expr, value); \
-    } while (0)
-
-#define CHECK_DUMP_I(expr) \
-    do { \
-        if (!(expr)) \
-            RTTestFailed(hTest, "%d: FAILED %s, got \"%d\"", __LINE__, #expr, expr); \
-    } while (0)
-
-    iprt::MiniString empty;
-    CHECK(empty.length() == 0);
-    CHECK(empty.capacity() == 0);
-
-    iprt::MiniString sixbytes("12345");
-    CHECK(sixbytes.length() == 5);
-    CHECK(sixbytes.capacity() == 6);
-
-    sixbytes.append(iprt::MiniString("678"));
-    CHECK(sixbytes.length() == 8);
-    CHECK(sixbytes.capacity() == 9);
-
-    sixbytes.append("9a");
-    CHECK(sixbytes.length() == 10);
-    CHECK(sixbytes.capacity() == 11);
-
-    char *psz = sixbytes.mutableRaw();
-        // 123456789a
-        //       ^
-        // 0123456
-    psz[6] = '\0';
-    sixbytes.jolt();
-    CHECK(sixbytes.length() == 6);
-    CHECK(sixbytes.capacity() == 7);
-
-    iprt::MiniString morebytes("tobereplaced");
-    morebytes = "newstring ";
-    morebytes.append(sixbytes);
-
-    CHECK_DUMP(morebytes == "newstring 123456", morebytes.c_str());
-
-    iprt::MiniString third(morebytes);
-    third.reserve(100 * 1024);      // 100 KB
-    CHECK_DUMP(third == "newstring 123456", morebytes.c_str() );
-    CHECK(third.capacity() == 100 * 1024);
-    CHECK(third.length() == morebytes.length());          // must not have changed
-
-    iprt::MiniString copy1(morebytes);
-    iprt::MiniString copy2 = morebytes;
-    CHECK(copy1 == copy2);
-
-    copy1 = NULL;
-    CHECK(copy1.length() == 0);
-
-    copy1 = "";
-    CHECK(copy1.length() == 0);
-
-    CHECK(iprt::MiniString("abc") <  iprt::MiniString("def"));
-    CHECK(iprt::MiniString("abc") != iprt::MiniString("def"));
-    CHECK_DUMP_I(iprt::MiniString("def") > iprt::MiniString("abc"));
-    CHECK(iprt::MiniString("abc") == iprt::MiniString("abc"));
-
-    copy2.setNull();
-    for (int i = 0; i < 100; ++i)
-    {
-        copy2.reserve(50);      // should be ignored after 50 loops
-        copy2.append("1");
-    }
-    CHECK(copy2.length() == 100);
-
-    copy2.setNull();
-    for (int i = 0; i < 100; ++i)
-    {
-        copy2.reserve(50);      // should be ignored after 50 loops
-        copy2.append('1');
-    }
-    CHECK(copy2.length() == 100);
-
-#undef CHECK
-#undef CHECK_DUMP
-#undef CHECK_DUMP_I
-}
-
-
 void testUtf8Latin1(RTTEST hTest)
 {
@@ -1376,5 +1272,4 @@
 static void testNoTransation(RTTEST hTest)
 {
-
     /*
      * Try trigger a VERR_NO_TRANSLATION error in convert to
@@ -1409,4 +1304,82 @@
 }
 
+static void testGetPut(RTTEST hTest)
+{
+    /*
+     * Test RTStrPutCp, RTStrGetCp and RTStrGetCpEx.
+     */
+    RTTestSub(hTest, "RTStrPutCp, RTStrGetCp and RTStrGetCpEx");
+
+    RTUNICP uc = 0;
+    while (uc <= 0x10fffd)
+    {
+        /* Figure the range - skip illegal ranges. */
+        RTUNICP ucFirst = uc;
+        if (ucFirst - UINT32_C(0xd800) <= 0x7ff)
+            ucFirst = 0xe000;
+        else if (ucFirst == UINT32_C(0xfffe) || ucFirst == UINT32_C(0xffff))
+            ucFirst = 0x10000;
+
+        RTUNICP ucLast  = ucFirst + 1023;
+        if (ucLast - UINT32_C(0xd800) <= 0x7ff)
+            ucLast = 0xd7ff;
+        else if (ucLast == UINT32_C(0xfffe) || ucLast == UINT32_C(0xffff))
+            ucLast = 0xfffd;
+
+        /* Encode the range into a string, decode each code point as we go along. */
+        char sz1[8192];
+        char *pszDst = sz1;
+        for (uc = ucFirst; uc <= ucLast; uc++)
+        {
+            char *pszBefore = pszDst;
+            pszDst = RTStrPutCp(pszDst, uc);
+            RTTESTI_CHECK(pszBefore - pszDst < 6);
+
+            RTUNICP uc2 = RTStrGetCp(pszBefore);
+            RTTESTI_CHECK_MSG(uc2 == uc, ("uc2=%#x uc=%#x\n", uc2, uc));
+
+            const char *pszSrc = pszBefore;
+            RTUNICP uc3 = 42;
+            RTTESTI_CHECK_RC(RTStrGetCpEx(&pszSrc, &uc3), VINF_SUCCESS);
+            RTTESTI_CHECK_MSG(uc3 == uc, ("uc3=%#x uc=%#x\n", uc3, uc));
+            RTTESTI_CHECK_MSG(pszSrc == pszDst, ("pszSrc=%p pszDst=%p\n", pszSrc, pszDst));
+        }
+
+        /* Decode and re-encode it. */
+        const char *pszSrc = pszDst = sz1;
+        for (uc = ucFirst; uc <= ucLast; uc++)
+        {
+            RTUNICP uc2 = RTStrGetCp(pszSrc);
+            RTTESTI_CHECK_MSG(uc2 == uc, ("uc2=%#x uc=%#x\n", uc2, uc));
+
+            RTUNICP uc3 = 42;
+            RTTESTI_CHECK_RC(RTStrGetCpEx(&pszSrc, &uc3), VINF_SUCCESS);
+            RTTESTI_CHECK_MSG(uc3 == uc, ("uc3=%#x uc=%#x\n", uc3, uc));
+
+            pszDst = RTStrPutCp(pszDst, uc);
+            RTTESTI_CHECK_MSG(pszSrc == pszDst, ("pszSrc=%p pszDst=%p\n", pszSrc, pszDst));
+            pszSrc = pszDst;
+        }
+
+        /* Decode and wipe it (checking compiler optimizations). */
+        pszSrc = pszDst = sz1;
+        for (uc = ucFirst; uc <= ucLast; uc++)
+        {
+            RTUNICP uc2 = RTStrGetCp(pszSrc);
+            RTTESTI_CHECK_MSG(uc2 == uc, ("uc2=%#x uc=%#x\n", uc2, uc));
+
+            RTUNICP uc3 = 42;
+            RTTESTI_CHECK_RC(RTStrGetCpEx(&pszSrc, &uc3), VINF_SUCCESS);
+            RTTESTI_CHECK_MSG(uc3 == uc, ("uc3=%#x uc=%#x\n", uc3, uc));
+
+            pszDst = RTStrPutCp(pszDst, 0);
+        }
+
+        /* advance */
+        uc = ucLast + 1;
+    }
+
+}
+
 
 int main()
@@ -1416,11 +1389,11 @@
      */
     RTTEST hTest;
-    int rc = RTTestInitAndCreate("tstUtf8", &hTest);
-    if (rc)
-        return rc;
+    RTEXITCODE rcExit = RTTestInitAndCreate("tstUtf8", &hTest);
+    if (rcExit != RTEXITCODE_SUCCESS)
+        return rcExit;
     RTTestBanner(hTest);
 
     /*
-     * Run the test.
+     * Run the tests.
      */
     InitStrings();
@@ -1432,8 +1405,8 @@
     testStrEnd(hTest);
     testStrStr(hTest);
-    testMinistring(hTest);
     testUtf8Latin1(hTest);
     testUtf16Latin1(hTest);
     testNoTransation(hTest);
+    testGetPut(hTest);
 
     Benchmarks(hTest);
