VirtualBox

Changeset 79562 in vbox for trunk/src/VBox


Ignore:
Timestamp:
Jul 5, 2019 8:37:19 PM (6 years ago)
Author:
vboxsync
Message:

IPRT: Added RTSTRCONVERTHEXBYTES_F_SEP_COLON as well as a RTStrConvertHexBytesEx variant. bugref:9288

Location:
trunk/src/VBox/Runtime
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Runtime/common/string/strtonum.cpp

    r76553 r79562  
    4040*   Global Variables                                                                                                             *
    4141*********************************************************************************************************************************/
    42 /** 8-bit char -> digit. */
     42/** 8-bit char -> digit.
     43 * Non-digits have values 255 (most), 254 (zero), 253 (colon) and 252 (space).
     44 */
    4345static const unsigned char g_auchDigits[256] =
    4446{
    45     255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
    46     255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9,255,255,255,255,255,255,
     47    254,255,255,255,255,255,255,255,255,252,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
     48    252,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9,253,255,255,255,255,255,
    4749    255, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,255,255,255,255,255,
    4850    255, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,255,255,255,255,255,
     
    5254    255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255
    5355};
     56
    5457/** Approximated overflow shift checks. */
    5558static const char g_auchShift[36] =
     
    7578        else if (i >= 'A' && i <= 'Z')
    7679            ch = i - 'A' + 10;
     80        else if (i == 0)
     81            ch = 254;
     82        else if (i == ':')
     83            ch = 253;
     84        else if (i == ' ' || i == '\t')
     85            ch = 252;
    7786        if (i == 0)
    7887            printf("\n    %3d", ch);
     
    973982
    974983
     984RTDECL(int) RTStrConvertHexBytesEx(char const *pszHex, void *pv, size_t cb, uint32_t fFlags,
     985                                   const char **ppszNext, size_t *pcbReturned)
     986{
     987    size_t               cbDst  = cb;
     988    uint8_t             *pbDst  = (uint8_t *)pv;
     989    const unsigned char *pszSrc = (const unsigned char *)pszHex;
     990    unsigned char        uchDigit;
     991
     992    if (pcbReturned)
     993        *pcbReturned = 0;
     994    if (ppszNext)
     995        *ppszNext = NULL;
     996    AssertPtrReturn(pszHex, VERR_INVALID_POINTER);
     997    AssertReturn(!(fFlags & ~RTSTRCONVERTHEXBYTES_F_SEP_COLON), VERR_INVALID_FLAGS);
     998
     999    if (fFlags & RTSTRCONVERTHEXBYTES_F_SEP_COLON)
     1000    {
     1001        /*
     1002         * Optional colon separators.
     1003         */
     1004        bool fPrevColon = true; /* leading colon is taken to mean leading zero byte */
     1005        for (;;)
     1006        {
     1007            /* Pick the next two digit from the string. */
     1008            uchDigit = g_auchDigits[*pszSrc++];
     1009            if (uchDigit >= 16)
     1010            {
     1011                if (uchDigit == 253 /* colon */)
     1012                {
     1013                    Assert(pszSrc[-1] == ':');
     1014                    if (!fPrevColon)
     1015                        fPrevColon = true;
     1016                    /* Add zero byte if there is room. */
     1017                    else if (cbDst > 0)
     1018                    {
     1019                        cbDst--;
     1020                        *pbDst++ = 0;
     1021                    }
     1022                    else
     1023                    {
     1024                        if (pcbReturned)
     1025                            *pcbReturned = pbDst - (uint8_t *)pv;
     1026                        if (ppszNext)
     1027                            *ppszNext = (const char *)pszSrc - 1;
     1028                        return VERR_BUFFER_OVERFLOW;
     1029                    }
     1030                    continue;
     1031                }
     1032                else
     1033                    break;
     1034            }
     1035            else
     1036            {
     1037                /* Got one digit, check what comes next: */
     1038                unsigned char const uchDigit2 = g_auchDigits[*pszSrc++];
     1039                if (uchDigit2 < 16)
     1040                {
     1041                    if (cbDst > 0)
     1042                    {
     1043                        *pbDst++ = (uchDigit << 4) | uchDigit2;
     1044                        cbDst--;
     1045                        fPrevColon = false;
     1046                    }
     1047                    else
     1048                    {
     1049                        if (pcbReturned)
     1050                            *pcbReturned = pbDst - (uint8_t *)pv;
     1051                        if (ppszNext)
     1052                            *ppszNext = (const char *)pszSrc - 1;
     1053                        return VERR_BUFFER_OVERFLOW;
     1054                    }
     1055                }
     1056                /* Lone digits are only allowed if following a colon or at the very start, because
     1057                   if there is more than one byte it ambigious whether it is the lead or tail byte
     1058                   that only has one digit in it.
     1059                   Note! This also ensures better compatibility with the no-separator variant
     1060                         (except for single digit strings, which are accepted here but not below). */
     1061                else if (fPrevColon)
     1062                {
     1063                    if (cbDst > 0)
     1064                    {
     1065                        *pbDst++ = uchDigit;
     1066                        cbDst--;
     1067                    }
     1068                    else
     1069                    {
     1070                        if (pcbReturned)
     1071                            *pcbReturned = pbDst - (uint8_t *)pv;
     1072                        if (ppszNext)
     1073                            *ppszNext = (const char *)pszSrc - 1;
     1074                        return VERR_BUFFER_OVERFLOW;
     1075                    }
     1076                    if (uchDigit2 == 253 /* colon */)
     1077                    {
     1078                        Assert(pszSrc[-1] == ':');
     1079                        fPrevColon = true;
     1080                    }
     1081                    else
     1082                    {
     1083                        fPrevColon = false;
     1084                        uchDigit = uchDigit2;
     1085                        break;
     1086                    }
     1087                }
     1088                else
     1089                {
     1090                    if (pcbReturned)
     1091                        *pcbReturned = pbDst - (uint8_t *)pv;
     1092                    if (ppszNext)
     1093                        *ppszNext = (const char *)pszSrc - 2;
     1094                    return VERR_UNEVEN_INPUT;
     1095                }
     1096            }
     1097        }
     1098
     1099        /* Trailing colon means trailing zero byte: */
     1100        if (fPrevColon)
     1101        {
     1102            if (cbDst > 0)
     1103            {
     1104                *pbDst++ = 0;
     1105                cbDst--;
     1106            }
     1107            else
     1108            {
     1109                if (pcbReturned)
     1110                    *pcbReturned = pbDst - (uint8_t *)pv;
     1111                if (ppszNext)
     1112                    *ppszNext = (const char *)pszSrc - 1;
     1113                return VERR_BUFFER_OVERFLOW;
     1114            }
     1115        }
     1116    }
     1117    else
     1118    {
     1119        /*
     1120         * No separators.
     1121         */
     1122        for (;;)
     1123        {
     1124            /* Pick the next two digit from the string. */
     1125            uchDigit = g_auchDigits[*pszSrc++];
     1126            if (uchDigit < 16)
     1127            {
     1128                unsigned char const uchDigit2 = g_auchDigits[*pszSrc++];
     1129                if (uchDigit2 < 16)
     1130                {
     1131                    /* Add the byte to the output buffer. */
     1132                    if (cbDst)
     1133                    {
     1134                        cbDst--;
     1135                        *pbDst++ = (uchDigit << 4) | uchDigit2;
     1136                    }
     1137                    else
     1138                    {
     1139                        if (pcbReturned)
     1140                            *pcbReturned = pbDst - (uint8_t *)pv;
     1141                        if (ppszNext)
     1142                            *ppszNext = (const char *)pszSrc - 2;
     1143                        return VERR_BUFFER_OVERFLOW;
     1144                    }
     1145                }
     1146                else
     1147                {
     1148                    if (pcbReturned)
     1149                        *pcbReturned = pbDst - (uint8_t *)pv;
     1150                    if (ppszNext)
     1151                        *ppszNext = (const char *)pszSrc - 2;
     1152                    return VERR_UNEVEN_INPUT;
     1153                }
     1154            }
     1155            else
     1156                break;
     1157        }
     1158    }
     1159
     1160    /*
     1161     * End of hex bytes, look what comes next and figure out what to return.
     1162     */
     1163    if (pcbReturned)
     1164        *pcbReturned = pbDst - (uint8_t *)pv;
     1165    if (ppszNext)
     1166        *ppszNext = (const char *)pszSrc - 1;
     1167
     1168    if (uchDigit == 254)
     1169    {
     1170        Assert(pszSrc[-1] == '\0');
     1171        if (cbDst == 0)
     1172            return VINF_SUCCESS;
     1173        return pcbReturned ? VINF_BUFFER_UNDERFLOW : VERR_BUFFER_UNDERFLOW;
     1174    }
     1175    Assert(pszSrc[-1] != '\0');
     1176
     1177    if (cbDst != 0 && !pcbReturned)
     1178        return VERR_BUFFER_UNDERFLOW;
     1179
     1180    while (uchDigit == 252)
     1181    {
     1182        Assert(pszSrc[-1] == ' ' || pszSrc[-1] == '\t');
     1183        uchDigit = g_auchDigits[*pszSrc++];
     1184    }
     1185
     1186    Assert(pszSrc[-1] == '\0' ? uchDigit == 254 : uchDigit != 254);
     1187    return uchDigit == 254 ? VWRN_TRAILING_CHARS : VWRN_TRAILING_SPACES;
     1188
     1189}
     1190RT_EXPORT_SYMBOL(RTStrConvertHexBytesEx);
     1191
     1192
    9751193RTDECL(int) RTStrConvertHexBytes(char const *pszHex, void *pv, size_t cb, uint32_t fFlags)
    9761194{
    977     size_t      cbDst;
    978     uint8_t    *pbDst;
    979     const char *pszSrc;
    980 
    981     AssertPtrReturn(pszHex, VERR_INVALID_POINTER);
    982     AssertReturn(!fFlags, VERR_INVALID_PARAMETER);
    983 
    984     cbDst  = cb;
    985     pbDst  = (uint8_t *)pv;
    986     pszSrc = pszHex;
    987     for (;;)
    988     {
    989         /* Pick the next two digit from the string. */
    990         char ch = *pszSrc++;
    991         unsigned char uchDigit1 = g_auchDigits[(unsigned char)ch];
    992         unsigned char uchDigit2;
    993         if (uchDigit1 >= 16)
    994         {
    995             if (!ch)
    996                 return cbDst == 0 ? VINF_SUCCESS : VERR_BUFFER_UNDERFLOW;
    997 
    998             while (ch == ' ' || ch == '\t')
    999                 ch = *pszSrc++;
    1000             return ch ? VWRN_TRAILING_CHARS : VWRN_TRAILING_SPACES;
    1001         }
    1002 
    1003         ch = *pszSrc++;
    1004         uchDigit2 = g_auchDigits[(unsigned char)ch];
    1005         if (uchDigit2 >= 16)
    1006             return VERR_UNEVEN_INPUT;
    1007 
    1008         /* Add the byte to the output buffer. */
    1009         if (!cbDst)
    1010             return VERR_BUFFER_OVERFLOW;
    1011         cbDst--;
    1012         *pbDst++ = (uchDigit1 << 4) | uchDigit2;
    1013     }
     1195    return RTStrConvertHexBytesEx(pszHex, pv, cb, fFlags, NULL /*ppszNext*/, NULL /*pcbReturned*/);
     1196
    10141197}
    10151198RT_EXPORT_SYMBOL(RTStrConvertHexBytes);
  • trunk/src/VBox/Runtime/testcase/tstStrToNum.cpp

    r76553 r79562  
    2525 */
    2626
    27 #include <iprt/initterm.h>
     27
     28/*********************************************************************************************************************************
     29*   Header Files                                                                                                                 *
     30*********************************************************************************************************************************/
     31#include <iprt/test.h>
    2832#include <iprt/string.h>
    2933#include <iprt/stream.h>
     
    6973        int rc = Fun(Test.psz, NULL, Test.uBase, &Result); \
    7074        if (Result != Test.Result) \
    71         { \
    72             RTPrintf("failure: '%s' -> " Fmt " expected " Fmt ". (%s/%u)\n", Test.psz, Result, Test.Result, #Fun, iTest); \
    73             cErrors++; \
    74         } \
     75            RTTestIFailed("'%s' -> " Fmt " expected " Fmt ". (%s/%u)\n", Test.psz, Result, Test.Result, #Fun, iTest); \
    7576        else if (rc != Test.rc) \
    76         { \
    77             RTPrintf("failure: '%s' -> rc=%Rrc expected %Rrc. (%s/%u)\n", Test.psz, rc, Test.rc, #Fun, iTest); \
    78             cErrors++; \
    79         } \
     77            RTTestIFailed("'%s' -> rc=%Rrc expected %Rrc. (%s/%u)\n", Test.psz, rc, Test.rc, #Fun, iTest); \
    8078    } while (0)
    8179
     
    9290int main()
    9391{
    94     RTR3InitExeNoArguments(0);
    95 
    96     int cErrors = 0;
     92    RTTEST     hTest;
     93    RTEXITCODE rcExit = RTTestInitAndCreate("tstRTStrToNum", &hTest);
     94    if (rcExit != RTEXITCODE_SUCCESS)
     95        return rcExit;
     96
    9797    static const struct TstU64 aTstU64[] =
    9898    {
     
    159159
    160160
    161 
    162161    static const struct TstI32 aTstI32[] =
    163162    {
     
    223222    RUN_TESTS(aTstU32, uint32_t, "%#x", RTStrToUInt32Ex);
    224223
     224
     225    /*
     226     * Test the some hex stuff too.
     227     */
     228    static const struct
     229    {
     230        const char *pszHex;
     231        size_t      cbOut;
     232        size_t      offNext;
     233        uint8_t     bLast;
     234        bool        fColon;
     235        int         rc;
     236    } s_aConvertHexTests[] =
     237    {
     238        { "00",          1,  2, 0x00,  true, VINF_SUCCESS },
     239        { "00",          1,  2, 0x00, false, VINF_SUCCESS },
     240        { "000102",      3,  6, 0x02,  true, VINF_SUCCESS },
     241        { "00019",       2,  4, 0x01, false, VERR_UNEVEN_INPUT },
     242        { "00019",       2,  4, 0x01,  true, VERR_UNEVEN_INPUT },
     243        { "0001:9",      3,  6, 0x09,  true, VINF_SUCCESS},
     244        { "000102",      3,  6, 0x02, false, VINF_SUCCESS },
     245        { "0:1",         2,  3, 0x01,  true, VINF_SUCCESS },
     246        { ":",           2,  1, 0x00,  true, VINF_SUCCESS },
     247        { "0:01",        2,  4, 0x01,  true, VINF_SUCCESS },
     248        { "00:01",       2,  5, 0x01,  true, VINF_SUCCESS },
     249        { ":1:2:3:4:5",  6, 10, 0x05,  true, VINF_SUCCESS },
     250        { ":1:2:3::5",   6,  9, 0x05,  true, VINF_SUCCESS },
     251        { ":1:2:3:4:",   6,  9, 0x00,  true, VINF_SUCCESS },
     252    };
     253    for (unsigned i = 0; i < RT_ELEMENTS(s_aConvertHexTests); i++)
     254    {
     255        uint8_t abBuf[1024];
     256        memset(abBuf, 0xf6, sizeof(abBuf));
     257        const char *pszExpectNext = &s_aConvertHexTests[i].pszHex[s_aConvertHexTests[i].offNext];
     258        const char *pszNext       = "";
     259        size_t      cbReturned    = 77777;
     260        int rc = RTStrConvertHexBytesEx(s_aConvertHexTests[i].pszHex, abBuf, s_aConvertHexTests[i].cbOut,
     261                                        s_aConvertHexTests[i].fColon ? RTSTRCONVERTHEXBYTES_F_SEP_COLON : 0,
     262                                        &pszNext, &cbReturned);
     263        if (   rc      != s_aConvertHexTests[i].rc
     264            || pszNext != pszExpectNext
     265            || abBuf[s_aConvertHexTests[i].cbOut - 1] != s_aConvertHexTests[i].bLast
     266            )
     267            RTTestFailed(hTest, "RTStrConvertHexBytesEx/#%u %s -> %Rrc %p %#zx %#02x, expected %Rrc %p %#zx %#02x\n",
     268                         i, s_aConvertHexTests[i].pszHex,
     269                         rc, pszNext, cbReturned, abBuf[s_aConvertHexTests[i].cbOut - 1],
     270                         s_aConvertHexTests[i].rc, pszExpectNext, s_aConvertHexTests[i].cbOut, s_aConvertHexTests[i].bLast);
     271    }
     272
     273
    225274    /*
    226275     * Summary.
    227276     */
    228     if (!cErrors)
    229         RTPrintf("tstStrToNum: SUCCESS\n");
    230     else
    231         RTPrintf("tstStrToNum: FAILURE - %d errors\n", cErrors);
    232     return !!cErrors;
     277    return RTTestSummaryAndDestroy(hTest);
    233278}
Note: See TracChangeset for help on using the changeset viewer.

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