VirtualBox

Ignore:
Timestamp:
Sep 10, 2018 9:39:10 AM (6 years ago)
Author:
vboxsync
Message:

IPRT/json: Implemented handling of \uXXXX sequences. Reduced heap calls during string decoding. bugref:9167

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Runtime/common/misc/json.cpp

    r74170 r74173  
    367367DECLINLINE(char) rtJsonTokenizerPeekCh(PRTJSONTOKENIZER pTokenizer)
    368368{
    369     return   rtJsonTokenizerIsEos(pTokenizer)
    370            ? '\0'
    371            : pTokenizer->achBuf[pTokenizer->offBuf + 1]; /** @todo Read out of bounds */
     369    return   !rtJsonTokenizerIsEos(pTokenizer)
     370           ? pTokenizer->achBuf[pTokenizer->offBuf + 1] /** @todo Read out of bounds */
     371           : '\0';
    372372}
    373373
     
    383383    char ch;
    384384
    385     if (rtJsonTokenizerIsEos(pTokenizer))
     385    if (!rtJsonTokenizerIsEos(pTokenizer))
     386        ch = pTokenizer->achBuf[pTokenizer->offBuf];
     387    else
    386388        ch = '\0';
    387     else
    388         ch = pTokenizer->achBuf[pTokenizer->offBuf];
    389389
    390390    return ch;
     
    604604static int rtJsonTokenizerGetString(PRTJSONTOKENIZER pTokenizer, PRTJSONTOKEN pToken)
    605605{
    606     int rc = VINF_SUCCESS;
    607     size_t cchStr = 0;
    608     size_t cchStrMax = _4K;
    609     char *pszTmp = (char *)RTMemAllocZ(cchStrMax * sizeof(char));
    610     if (RT_UNLIKELY(!pszTmp))
    611         return VERR_NO_STR_MEMORY;
    612 
    613     RT_BZERO(pszTmp, cchStrMax);
     606    size_t cchStrMax = 64;
     607    char *pszDecoded = (char *)RTStrAlloc(cchStrMax);
     608    AssertReturn(pszDecoded, VERR_NO_STR_MEMORY);
    614609
    615610    Assert(rtJsonTokenizerGetCh(pTokenizer) == '\"');
     
    619614    pToken->Pos      = pTokenizer->Pos;
    620615
     616    size_t cchStr = 0;
    621617    char ch = rtJsonTokenizerGetCh(pTokenizer);
    622618    while (   ch != '\"'
    623            && ch != '\0'
    624            && RT_SUCCESS(rc))
    625     {
    626         if (ch == '\\')
     619           && ch != '\0')
     620    {
     621        if (ch != '\\')
     622        {
     623            pszDecoded[cchStr++] = ch;
     624            rtJsonTokenizerSkipCh(pTokenizer);
     625        }
     626        else
    627627        {
    628628            /* Escape sequence, check the next character  */
     
    632632            {
    633633                case '\"':
    634                     pszTmp[cchStr] = '\"';
     634                    pszDecoded[cchStr++] = '\"';
     635                    rtJsonTokenizerSkipCh(pTokenizer);
    635636                    break;
    636637                case '\\':
    637                     pszTmp[cchStr] = '\\';
     638                    pszDecoded[cchStr++] = '\\';
     639                    rtJsonTokenizerSkipCh(pTokenizer);
    638640                    break;
    639641                case '/':
    640                     pszTmp[cchStr] = '/';
     642                    pszDecoded[cchStr++] = '/';
     643                    rtJsonTokenizerSkipCh(pTokenizer);
    641644                    break;
    642645                case '\b':
    643                     pszTmp[cchStr] = '\b';
     646                    pszDecoded[cchStr++] = '\b';
     647                    rtJsonTokenizerSkipCh(pTokenizer);
    644648                    break;
    645649                case '\n':
    646                     pszTmp[cchStr] = '\n';
     650                    pszDecoded[cchStr++] = '\n';
     651                    rtJsonTokenizerSkipCh(pTokenizer);
    647652                    break;
    648653                case '\f':
    649                     pszTmp[cchStr] = '\f';
     654                    pszDecoded[cchStr++] = '\f';
     655                    rtJsonTokenizerSkipCh(pTokenizer);
    650656                    break;
    651657                case '\r':
    652                     pszTmp[cchStr] = '\r';
     658                    pszDecoded[cchStr++] = '\r';
     659                    rtJsonTokenizerSkipCh(pTokenizer);
    653660                    break;
    654661                case '\t':
    655                     pszTmp[cchStr] = '\t';
     662                    pszDecoded[cchStr++] = '\t';
     663                    rtJsonTokenizerSkipCh(pTokenizer);
    656664                    break;
    657665                case 'u':
    658                     rc = VERR_NOT_SUPPORTED;
    659                     break;
     666                {
     667                    /* \uXXXX */
     668                    int rc = VERR_JSON_INVALID_UTF16_ESCAPE_SEQUENCE;
     669                    rtJsonTokenizerSkipCh(pTokenizer);
     670                    char chX1 = rtJsonTokenizerGetCh(pTokenizer);
     671                    if (RT_C_IS_XDIGIT(chX1))
     672                    {
     673                        rtJsonTokenizerSkipCh(pTokenizer);
     674                        char chX2 = rtJsonTokenizerGetCh(pTokenizer);
     675                        if (RT_C_IS_XDIGIT(chX2))
     676                        {
     677                            rtJsonTokenizerSkipCh(pTokenizer);
     678                            char chX3 = rtJsonTokenizerGetCh(pTokenizer);
     679                            if (RT_C_IS_XDIGIT(chX3))
     680                            {
     681                                rtJsonTokenizerSkipCh(pTokenizer);
     682                                char chX4 = rtJsonTokenizerGetCh(pTokenizer);
     683                                if (RT_C_IS_XDIGIT(chX4))
     684                                {
     685                                    rtJsonTokenizerSkipCh(pTokenizer);
     686
     687                                    RTUNICP uc = ((RTUTF16)(chX1 <= '9' ? chX1 - '0' : (chX1 & 7) + 9) << 12)
     688                                               | ((RTUTF16)(chX2 <= '9' ? chX2 - '0' : (chX2 & 7) + 9) <<  8)
     689                                               | ((RTUTF16)(chX3 <= '9' ? chX3 - '0' : (chX3 & 7) + 9) <<  4)
     690                                               | ((RTUTF16)(chX4 <= '9' ? chX4 - '0' : (chX4 & 7) + 9));
     691                                    if (   !RTUtf16IsHighSurrogate((RTUTF16)uc)
     692                                        && !RTUtf16IsLowSurrogate((RTUTF16)uc))
     693                                        rc = VINF_SUCCESS;
     694                                    else if (RTUtf16IsHighSurrogate((RTUTF16)uc))
     695                                    {
     696                                        /* The must be a low surrogate pair following the high one: */
     697                                        ch = rtJsonTokenizerGetCh(pTokenizer);
     698                                        if (ch == '\\')
     699                                            rtJsonTokenizerSkipCh(pTokenizer);
     700                                        else
     701                                            rc = VERR_JSON_MISSING_SURROGATE_PAIR;
     702                                        ch = rtJsonTokenizerGetCh(pTokenizer);
     703                                        if (ch == 'u')
     704                                            rtJsonTokenizerSkipCh(pTokenizer);
     705                                        else
     706                                            rc = VERR_JSON_MISSING_SURROGATE_PAIR;
     707                                        chX1 = rtJsonTokenizerGetCh(pTokenizer);
     708                                        if (RT_C_IS_XDIGIT(chX1))
     709                                            rtJsonTokenizerSkipCh(pTokenizer);
     710                                        else if (RT_SUCCESS_NP(rc))
     711                                            rc = VERR_JSON_INVALID_UTF16_ESCAPE_SEQUENCE;
     712                                        chX2 = rtJsonTokenizerGetCh(pTokenizer);
     713                                        if (RT_C_IS_XDIGIT(chX2))
     714                                            rtJsonTokenizerSkipCh(pTokenizer);
     715                                        else if (RT_SUCCESS_NP(rc))
     716                                            rc = VERR_JSON_INVALID_UTF16_ESCAPE_SEQUENCE;
     717                                        chX3 = rtJsonTokenizerGetCh(pTokenizer);
     718                                        if (RT_C_IS_XDIGIT(chX3))
     719                                            rtJsonTokenizerSkipCh(pTokenizer);
     720                                        else if (RT_SUCCESS_NP(rc))
     721                                            rc = VERR_JSON_INVALID_UTF16_ESCAPE_SEQUENCE;
     722                                        chX4 = rtJsonTokenizerGetCh(pTokenizer);
     723                                        if (RT_C_IS_XDIGIT(chX4))
     724                                            rtJsonTokenizerSkipCh(pTokenizer);
     725                                        else if (RT_SUCCESS_NP(rc))
     726                                            rc = VERR_JSON_INVALID_UTF16_ESCAPE_SEQUENCE;
     727                                        if (RT_SUCCESS(rc))
     728                                        {
     729                                            RTUTF16 wc2 = ((RTUTF16)(chX1 <= '9' ? chX1 - '0' : (chX1 & 7) + 9) << 12)
     730                                                        | ((RTUTF16)(chX2 <= '9' ? chX2 - '0' : (chX2 & 7) + 9) <<  8)
     731                                                        | ((RTUTF16)(chX3 <= '9' ? chX3 - '0' : (chX3 & 7) + 9) <<  4)
     732                                                        | ((RTUTF16)(chX4 <= '9' ? chX4 - '0' : (chX4 & 7) + 9));
     733                                            if (RTUtf16IsLowSurrogate(wc2))
     734                                                uc = 0x10000 + (((uc & 0x3ff) << 10) | (wc2 & 0x3ff));
     735                                            else
     736                                                rc = VERR_JSON_BAD_SURROGATE_PAIR_SEQUENCE;
     737                                        }
     738                                    }
     739                                    else
     740                                        rc = VERR_JSON_BAD_SURROGATE_PAIR_SEQUENCE;
     741                                    if (RT_SUCCESS(rc))
     742                                    {
     743                                        Assert(cchStr + RTStrCpSize(uc) < cchStrMax);
     744                                        char *pszNext = RTStrPutCp(&pszDecoded[cchStr], uc);
     745                                        Assert((size_t)(pszNext - &pszDecoded[cchStr]) == RTStrCpSize(uc));
     746                                        cchStr += pszNext - &pszDecoded[cchStr];
     747                                        break;
     748                                    }
     749                                }
     750                            }
     751                        }
     752                    }
     753                    RTStrFree(pszDecoded);
     754                    if (rc == VERR_JSON_INVALID_UTF16_ESCAPE_SEQUENCE)
     755                        rc = RTErrInfoSetF(pTokenizer->pErrInfo, rc, "Invalid \u escape sequence (line %zu col %zu)",
     756                                           pTokenizer->Pos.iLine, pTokenizer->Pos.iChStart);
     757                    else if (rc == VERR_JSON_MISSING_SURROGATE_PAIR)
     758                        rc = RTErrInfoSetF(pTokenizer->pErrInfo, rc, "Missing UTF-16 surrogate pair (line %zu col %zu)",
     759                                           pTokenizer->Pos.iLine, pTokenizer->Pos.iChStart);
     760                    else
     761                        rc = RTErrInfoSetF(pTokenizer->pErrInfo, rc, "Invalid UTF-16 surrogate pair (line %zu col %zu)",
     762                                           pTokenizer->Pos.iLine, pTokenizer->Pos.iChStart);
     763                    return rc;
     764                }
     765
    660766                default:
    661                     rc = RTErrInfoSetF(pTokenizer->pErrInfo, VERR_JSON_MALFORMED, "bad escape sequence (line %zu col %zu)",
    662                                        pTokenizer->Pos.iLine, pTokenizer->Pos.iChStart);
    663                     break;
     767                    RTStrFree(pszDecoded);
     768                    return RTErrInfoSetF(pTokenizer->pErrInfo, VERR_JSON_MALFORMED, "bad escape sequence (line %zu col %zu)",
     769                                         pTokenizer->Pos.iLine, pTokenizer->Pos.iChStart);
    664770            }
    665771        }
     772
     773
     774        if (cchStr < cchStrMax - 4)
     775        { /* likely */ }
    666776        else
    667             pszTmp[cchStr] = ch;
    668 
    669         if (RT_FAILURE(rc))
    670             break;
    671 
    672         cchStr++;
    673         rtJsonTokenizerSkipCh(pTokenizer);
    674         if (cchStr == cchStrMax - 1)
    675777        {
    676778            /* Increase string space. */
    677             size_t cchStrMaxNew = cchStrMax + _4K;
    678             char *pszTmpNew = (char *)RTMemRealloc(pszTmp, cchStrMaxNew * sizeof(char));
    679             if (RT_UNLIKELY(!pszTmpNew))
     779            size_t cchStrMaxNew =  cchStrMax < _4K ? cchStrMax * 2 : cchStrMax + _4K;
     780            int rc = RTStrRealloc(&pszDecoded, cchStrMaxNew);
     781            if (RT_SUCCESS(rc))
     782                cchStrMax = cchStrMaxNew;
     783            else
    680784            {
    681                 rc = VERR_NO_STR_MEMORY;
    682                 break;
     785                RTStrFree(pszDecoded);
     786                return rc;
    683787            }
    684 
    685             RT_BZERO(&pszTmpNew[cchStr], _4K);
    686             pszTmp = pszTmpNew;
    687             cchStrMax = cchStrMaxNew;
    688788        }
    689789        ch = rtJsonTokenizerGetCh(pTokenizer);
    690790    }
    691791
    692     if (RT_SUCCESS(rc))
    693     {
    694         if (rtJsonTokenizerGetCh(pTokenizer) == '\"')
    695             rtJsonTokenizerSkipCh(pTokenizer); /* Skip closing " */
    696 
    697         pToken->Class.String.pszStr = RTStrDupN(pszTmp, cchStr);
    698         if (pToken->Class.String.pszStr)
    699             pToken->Pos.iChEnd += cchStr;
    700         else
    701             rc = VERR_NO_STR_MEMORY;
    702     }
    703 
    704     if (pszTmp)
    705         RTMemFree(pszTmp);
    706 
    707     return rc;
     792    if (ch == '\"')
     793        rtJsonTokenizerSkipCh(pTokenizer); /* Skip closing " */
     794
     795    Assert(cchStr < cchStrMax);
     796    pszDecoded[cchStr] = '\0';
     797    if (cchStrMax - cchStr >= cchStrMax / 2)
     798        RTStrRealloc(&pszDecoded, cchStr + 1);
     799    pToken->Class.String.pszStr = pszDecoded;
     800
     801    pToken->Pos.iChEnd = pTokenizer->Pos.iChEnd;
     802    return VINF_SUCCESS;
    708803}
    709804
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