Index: /trunk/include/iprt/string.h
===================================================================
--- /trunk/include/iprt/string.h	(revision 73913)
+++ /trunk/include/iprt/string.h	(revision 73914)
@@ -1519,5 +1519,5 @@
  *
  *
- * Group 5, XML / HTML escapers:
+ * Group 5, XML / HTML, JSON and URI escapers:
  *      - \%RMas            - Takes a string pointer (const char *) and outputs
  *                            it as an attribute value with the proper escaping.
@@ -1526,4 +1526,7 @@
  *      - \%RMes            - Takes a string pointer (const char *) and outputs
  *                            it as an element with the necessary escaping.
+ *
+ *      - \%RMjs            - Takes a string pointer (const char *) and outputs
+ *                            it in quotes with proper JSON escaping.
  *
  *      - \%RMpf            - Takes a string pointer (const char *) and outputs
@@ -1541,10 +1544,5 @@
  *
  *
- * Group 6, JSON escapers:
- *      - \%RJs             - Takes a string pointer (const char *) and outputs
- *                            it in quotes with proper escaping.
- *
- *
- * Group 7, CPU Architecture Register dumpers:
+ * Group 6, CPU Architecture Register dumpers:
  *      - \%RAx86[reg]      - Takes a 64-bit register value if the register is
  *                            64-bit or smaller.  Check the code wrt which
Index: /trunk/src/VBox/Runtime/common/rest/rest-primary-object-types.cpp
===================================================================
--- /trunk/src/VBox/Runtime/common/rest/rest-primary-object-types.cpp	(revision 73913)
+++ /trunk/src/VBox/Runtime/common/rest/rest-primary-object-types.cpp	(revision 73914)
@@ -38,5 +38,4 @@
 
 
-
 /*********************************************************************************************************************************
 *   RTCRestObjectBase implementation                                                                                             *
@@ -621,5 +620,5 @@
 RTCRestOutputBase &RTCRestString::serializeAsJson(RTCRestOutputBase &a_rDst) const
 {
-    a_rDst.printf("%RJs", m_psz);
+    a_rDst.printf("%RMjs", m_psz);
     return a_rDst;
 }
Index: /trunk/src/VBox/Runtime/common/string/strformatrt.cpp
===================================================================
--- /trunk/src/VBox/Runtime/common/string/strformatrt.cpp	(revision 73913)
+++ /trunk/src/VBox/Runtime/common/string/strformatrt.cpp	(revision 73914)
@@ -1293,5 +1293,5 @@
 
             /*
-             * Group 5, XML / HTML escapers.
+             * Group 5, XML / HTML, JSON and URI escapers.
              */
             case 'M':
@@ -1300,4 +1300,5 @@
                 if (chWhat == 'a' || chWhat == 'e')
                 {
+                    /* XML attributes and element values. */
                     bool fAttr  = chWhat == 'a';
                     char chType = (*ppszFormat)[1];
@@ -1364,4 +1365,84 @@
                     }
                 }
+                else if (chWhat == 'j')
+                {
+                    /* JSON string escaping. */
+                    char const chType = (*ppszFormat)[1];
+                    *ppszFormat += 2;
+                    switch (chType)
+                    {
+                        case 's':
+                        {
+                            const char *pszStr = va_arg(*pArgs, char *);
+                            size_t      cchOutput;
+                            ssize_t     cchStr;
+                            ssize_t     offCur;
+                            ssize_t     offLast;
+
+                            if (!VALID_PTR(pszStr))
+                                pszStr = "<NULL>";
+                            cchStr = RTStrNLen(pszStr, (unsigned)cchPrecision);
+
+                            cchOutput = pfnOutput(pvArgOutput, "\"", 1);
+                            if (!(fFlags & RTSTR_F_LEFT))
+                                while (--cchWidth >= cchStr)
+                                    cchOutput += pfnOutput(pvArgOutput, " ", 1);
+
+                            offLast = offCur = 0;
+                            while (offCur < cchStr)
+                            {
+                                unsigned int const uch = pszStr[offCur];
+                                if (   uch >= 0x5d
+                                    || (uch >= 0x20 && uch != 0x22 && uch != 0x5c))
+                                    offCur++;
+                                else
+                                {
+                                    if (offLast < offCur)
+                                        cchOutput += pfnOutput(pvArgOutput, &pszStr[offLast], offCur - offLast);
+                                    switch ((char)uch)
+                                    {
+                                        case '"':   cchOutput += pfnOutput(pvArgOutput, "\\\"", 2); break;
+                                        case '\\':  cchOutput += pfnOutput(pvArgOutput, "\\\\", 2); break;
+                                        case '/':   cchOutput += pfnOutput(pvArgOutput, "\\/", 2); break;
+                                        case '\b':  cchOutput += pfnOutput(pvArgOutput, "\\b", 2); break;
+                                        case '\f':  cchOutput += pfnOutput(pvArgOutput, "\\f", 2); break;
+                                        case '\n':  cchOutput += pfnOutput(pvArgOutput, "\\n", 2); break;
+                                        case '\t':  cchOutput += pfnOutput(pvArgOutput, "\\t", 2); break;
+                                        default:
+                                        {
+                                            RTUNICP     uc     = 0xfffd; /* replacement character */
+                                            const char *pszCur = &pszStr[offCur];
+                                            int rc = RTStrGetCpEx(&pszCur, &uc);
+                                            if (RT_SUCCESS(rc))
+                                                offCur += pszCur - &pszStr[offCur] - 1;
+                                            if (uc >= 0xfffe)
+                                                uc = 0xfffd;             /* replacement character */
+                                            szBuf[0] = '\\';
+                                            szBuf[1] = 'u';
+                                            szBuf[2] = g_szHexDigits[(uc >> 12) & 0xf];
+                                            szBuf[3] = g_szHexDigits[(uc >>  8) & 0xf];
+                                            szBuf[4] = g_szHexDigits[(uc >>  4) & 0xf];
+                                            szBuf[5] = g_szHexDigits[ uc        & 0xf];
+                                            szBuf[6] = '\0';
+                                            cchOutput += pfnOutput(pvArgOutput, szBuf, 6);
+                                            break;
+                                        }
+                                    }
+                                    offLast = ++offCur;
+                                }
+                            }
+                            if (offLast < offCur)
+                                cchOutput += pfnOutput(pvArgOutput, &pszStr[offLast], offCur - offLast);
+
+                            while (--cchWidth >= cchStr)
+                                cchOutput += pfnOutput(pvArgOutput, " ", 1);
+                            cchOutput += pfnOutput(pvArgOutput, "\"", 1);
+                            return cchOutput;
+                        }
+
+                        default:
+                            AssertMsgFailed(("Invalid IPRT format type '%.10s'!\n", pszFormatOrg));
+                    }
+                }
                 else if (chWhat == 'p')
                 {
@@ -1429,78 +1510,8 @@
             }
 
+#endif /* IN_RING3 */
+
             /*
-             * Groups 6 - JSON.
-             */
-            case 'J':
-            {
-                char chType = (*ppszFormat)[0];
-                *ppszFormat += 1;
-                switch (chType)
-                {
-                    case 's':
-                    {
-                        const char *pszStr = va_arg(*pArgs, char *);
-                        size_t      cchOutput;
-                        ssize_t     cchStr;
-                        ssize_t     offCur;
-                        ssize_t     offLast;
-
-                        if (!VALID_PTR(pszStr))
-                            pszStr = "<NULL>";
-                        cchStr = RTStrNLen(pszStr, (unsigned)cchPrecision);
-
-                        cchOutput = pfnOutput(pvArgOutput, "\"", 1);
-                        if (!(fFlags & RTSTR_F_LEFT))
-                            while (--cchWidth >= cchStr)
-                                cchOutput += pfnOutput(pvArgOutput, " ", 1);
-
-                        offLast = offCur = 0;
-                        while (offCur < cchStr)
-                        {
-                            unsigned int const uch = pszStr[offCur];
-                            if (   uch >= 0x5d
-                                || (uch >= 0x20 && uch != 0x22 && uch != 0x5c))
-                                offCur++;
-                            else
-                            {
-                                if (offLast < offCur)
-                                    cchOutput += pfnOutput(pvArgOutput, &pszStr[offLast], offCur - offLast);
-                                switch ((char)uch)
-                                {
-                                    case '"':   cchOutput += pfnOutput(pvArgOutput, "\\\"", 2); break;
-                                    case '\\':  cchOutput += pfnOutput(pvArgOutput, "\\\\", 2); break;
-                                    case '/':   cchOutput += pfnOutput(pvArgOutput, "\\/", 2); break;
-                                    case '\b':  cchOutput += pfnOutput(pvArgOutput, "\\b", 2); break;
-                                    case '\f':  cchOutput += pfnOutput(pvArgOutput, "\\f", 2); break;
-                                    case '\n':  cchOutput += pfnOutput(pvArgOutput, "\\n", 2); break;
-                                    case '\t':  cchOutput += pfnOutput(pvArgOutput, "\\t", 2); break;
-                                    default:
-                                        cchOutput += pfnOutput(pvArgOutput, "\\u00", 2);
-                                        cchOutput += pfnOutput(pvArgOutput, &g_szHexDigits[(uch >> 4) & 0xf], 1);
-                                        cchOutput += pfnOutput(pvArgOutput, &g_szHexDigits[uch & 0xf], 1);
-                                        break;
-                                }
-                                offLast = ++offCur;
-                            }
-                        }
-                        if (offLast < offCur)
-                            cchOutput += pfnOutput(pvArgOutput, &pszStr[offLast], offCur - offLast);
-
-                        while (--cchWidth >= cchStr)
-                            cchOutput += pfnOutput(pvArgOutput, " ", 1);
-                        cchOutput += pfnOutput(pvArgOutput, "\"", 1);
-                        return cchOutput;
-                    }
-
-                    default:
-                        AssertMsgFailed(("Invalid IPRT format type '%.10s'!\n", pszFormatOrg));
-                }
-                break;
-            }
-
-#endif /* IN_RING3 */
-
-            /*
-             * Groups 7 - CPU Architecture Register Formatters.
+             * Groups 6 - CPU Architecture Register Formatters.
              *            "%RAarch[reg]"
              */
