Index: trunk/include/iprt/string.h
===================================================================
--- trunk/include/iprt/string.h	(revision 7420)
+++ trunk/include/iprt/string.h	(revision 7421)
@@ -1104,4 +1104,10 @@
  * as they are used in some languages, just simple upper & lower case compares.
  *
+ * The result is the difference between the mismatching codepoints after they
+ * both have been lower cased.
+ *
+ * If the string encoding is invalid the function will assert (strict builds)
+ * and use RTStrCmp for the remainder of the string.
+ *
  * @returns < 0 if the first string less than the second string.
  * @returns 0 if the first string identical to the second string.
Index: trunk/src/VBox/Runtime/common/string/utf-8.cpp
===================================================================
--- trunk/src/VBox/Runtime/common/string/utf-8.cpp	(revision 7420)
+++ trunk/src/VBox/Runtime/common/string/utf-8.cpp	(revision 7421)
@@ -996,4 +996,10 @@
  * as they are used in some languages, just simple upper & lower case compares.
  *
+ * The result is the difference between the mismatching codepoints after they
+ * both have been lower cased.
+ *
+ * If the string encoding is invalid the function will assert (strict builds)
+ * and use RTStrCmp for the remainder of the string.
+ *
  * @returns < 0 if the first string less than the second string.
  * @returns 0 if the first string identical to the second string.
@@ -1011,5 +1017,49 @@
         return 1;
 
-    /** @todo implement proper UTF-8 case-insensitive string comparison. */
+#if 1 /* new */
+    const char *pszStart1 = psz1;
+    for (;;)
+    {
+        /* Get the codepoints */
+        RTUNICP cp1;
+        int rc = RTStrGetCpEx(&psz1, &cp1);
+        if (RT_FAILURE(rc))
+        {
+            AssertRC(rc);
+            psz1--;
+            break;
+        }
+
+        RTUNICP cp2;
+        rc = RTStrGetCpEx(&psz2, &cp2);
+        if (RT_FAILURE(rc))
+        {
+            AssertRC(rc);
+            psz2--;
+            psz1 = RTStrPrevCp(pszStart1, psz1);
+            break;
+        }
+
+        /* compare */
+        int iDiff = cp1 - cp2;
+        if (iDiff)
+        {
+            iDiff = RTUniCpToUpper(cp1) != RTUniCpToUpper(cp2);
+            if (iDiff)
+            {
+                iDiff = RTUniCpToLower(cp1) - RTUniCpToLower(cp2); /* lower case diff last! */
+                if (iDiff)
+                    return iDiff;
+            }
+        }
+
+        /* hit the terminator? */
+        if (!cp1)
+            return 0;
+    }
+
+    /* Hit some bad encoding, continue in case insensitive mode. */
+    return RTStrCmp(psz1, psz2);
+#else /* old */
 #ifdef RT_OS_WINDOWS
     return stricmp(psz1, psz2);
@@ -1017,3 +1067,4 @@
     return strcasecmp(psz1, psz2);
 #endif /* !RT_OS_WINDOWS */
-}
+#endif
+}
Index: trunk/src/VBox/Runtime/testcase/tstUtf8.cpp
===================================================================
--- trunk/src/VBox/Runtime/testcase/tstUtf8.cpp	(revision 7420)
+++ trunk/src/VBox/Runtime/testcase/tstUtf8.cpp	(revision 7421)
@@ -795,4 +795,57 @@
 
 /**
+ * Test the RTStr*Cmp functions.
+ */
+void TstRTStrXCmp(void)
+{
+    RTPrintf("tstUtf8: TESTING RTStr*Cmp\n");
+#define CHECK_DIFF(expr, op) \
+    do \
+    { \
+        int iDiff = expr; \
+        if (!(iDiff op 0)) \
+        { \
+            RTPrintf("tstUtf8(%d): failure - %d " #op " 0: %s\n", __LINE__, iDiff, #expr); \
+            g_cErrors++; \
+        } \
+    } while (0)
+
+/** @todo test the non-ascii bits. */
+
+    CHECK_DIFF(RTStrCmp(NULL, NULL), == );
+    CHECK_DIFF(RTStrCmp(NULL, ""), < );
+    CHECK_DIFF(RTStrCmp("", NULL), > );
+    CHECK_DIFF(RTStrCmp("", ""), == );
+    CHECK_DIFF(RTStrCmp("abcdef", "abcdef"), == );
+    CHECK_DIFF(RTStrCmp("abcdef", "abcde"), > );
+    CHECK_DIFF(RTStrCmp("abcde", "abcdef"), < );
+    CHECK_DIFF(RTStrCmp("abcdeg", "abcdef"), > );
+    CHECK_DIFF(RTStrCmp("abcdef", "abcdeg"), < );
+    CHECK_DIFF(RTStrCmp("abcdeF", "abcdef"), < );
+    CHECK_DIFF(RTStrCmp("abcdef", "abcdeF"), > );
+
+
+    CHECK_DIFF(RTStrICmp(NULL, NULL), == );
+    CHECK_DIFF(RTStrICmp(NULL, ""), < );
+    CHECK_DIFF(RTStrICmp("", NULL), > );
+    CHECK_DIFF(RTStrICmp("", ""), == );
+    CHECK_DIFF(RTStrICmp("abcdef", "abcdef"), == );
+    CHECK_DIFF(RTStrICmp("abcdef", "abcde"), > );
+    CHECK_DIFF(RTStrICmp("abcde", "abcdef"), < );
+    CHECK_DIFF(RTStrICmp("abcdeg", "abcdef"), > );
+    CHECK_DIFF(RTStrICmp("abcdef", "abcdeg"), < );
+
+    CHECK_DIFF(RTStrICmp("abcdeF", "abcdef"), == );
+    CHECK_DIFF(RTStrICmp("abcdef", "abcdeF"), ==);
+    CHECK_DIFF(RTStrICmp("ABCDEF", "abcdef"), ==);
+    CHECK_DIFF(RTStrICmp("abcdef", "ABCDEF"), ==);
+    CHECK_DIFF(RTStrICmp("AbCdEf", "aBcDeF"), ==);
+    CHECK_DIFF(RTStrICmp("AbCdEg", "aBcDeF"), > );
+    CHECK_DIFF(RTStrICmp("AbCdEG", "aBcDef"), > ); /* diff performed on the lower case cp. */
+}
+
+
+
+/**
  * Benchmark stuff.
  */
@@ -855,4 +908,5 @@
     test2();
     test3();
+    TstRTStrXCmp();
     Benchmarks();
 
