VirtualBox

Ignore:
Timestamp:
Jun 15, 2016 9:54:26 AM (9 years ago)
Author:
vboxsync
Message:

Runtime/RTJson: Updates

File:
1 edited

Legend:

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

    r61695 r61704  
    3535#include <iprt/json.h>
    3636#include <iprt/mem.h>
     37#include <iprt/stream.h>
    3738#include <iprt/string.h>
    3839
     
    124125
    125126/**
     127 * Tokenizer read input callback.
     128 *
     129 * @returns IPRT status code.
     130 * @param   pvUser          Opaque user data for the callee.
     131 * @param   offInput        Start offset from the start of the input stream to read from.
     132 * @param   pvBuf           Where to store the read data.
     133 * @param   cbBuf           How much to read.
     134 * @param   pcbRead         Where to store the amount of data read on succcess.
     135 */
     136typedef DECLCALLBACK(int) FNRTJSONTOKENIZERREAD(void *pvUser, uint32_t offInput, void *pvBuf, size_t cbBuf,
     137                                                size_t *pcbRead);
     138/** Pointer to a tokenizer read buffer callback. */
     139typedef FNRTJSONTOKENIZERREAD *PFNRTJSONTOKENIZERREAD;
     140
     141/**
    126142 * Tokenizer state.
    127143 */
    128144typedef struct RTJSONTOKENIZER
    129145{
    130     /** Char buffer to read from. */
    131     const char              *pszInput;
     146    /** Read callback. */
     147    PFNRTJSONTOKENIZERREAD  pfnRead;
     148    /** Opaque user data. */
     149    void                    *pvUser;
     150    /** Current offset into the input stream. */
     151    uint32_t                offInput;
     152    /** Number of valid bytes in the input buffer. */
     153    size_t                  cbBuf;
     154    /* Current offset into the input buffer. */
     155    uint32_t                offBuf;
     156    /** Input cache buffer. */
     157    char                    achBuf[512];
    132158    /** Current position into the input stream. */
    133159    RTJSONPOS               Pos;
     
    205231typedef RTJSONITINT *PRTJSONITINT;
    206232
     233/**
     234 * Passing arguments for the read callbacks.
     235 */
     236typedef struct RTJSONREADERARGS
     237{
     238    /** Buffer/File size  */
     239    size_t                  cbData;
     240    /** Data specific for one callback. */
     241    union
     242    {
     243        PRTSTREAM           hStream;
     244        const uint8_t       *pbBuf;
     245    } u;
     246} RTJSONREADERARGS;
     247/** Pointer to a readers argument. */
     248typedef RTJSONREADERARGS *PRTJSONREADERARGS;
     249
    207250/*********************************************************************************************************************************
    208251*   Global variables                                                                                                             *
     
    213256
    214257/**
     258 * Fill the input buffer from the input stream.
     259 *
     260 * @returns IPRT status code.
     261 * @param   pTokenizer      The tokenizer state.
     262 */
     263static int rtJsonTokenizerRead(PRTJSONTOKENIZER pTokenizer)
     264{
     265    size_t cbRead = 0;
     266    int rc = pTokenizer->pfnRead(pTokenizer->pvUser, pTokenizer->offInput, &pTokenizer->achBuf[0],
     267                                 sizeof(pTokenizer->achBuf), &cbRead);
     268    if (RT_SUCCESS(rc))
     269    {
     270        pTokenizer->cbBuf    = cbRead;
     271        pTokenizer->offInput += cbRead;
     272        pTokenizer->offBuf   = 0;
     273        /* Validate UTF-8 encoding. */
     274        rc = RTStrValidateEncodingEx(&pTokenizer->achBuf[0], cbRead, 0 /* fFlags */);
     275        /* If we read less than requested we reached the end and fill the remainder with terminators. */
     276        if (cbRead < sizeof(pTokenizer->achBuf))
     277            memset(&pTokenizer->achBuf[cbRead], 0, sizeof(pTokenizer->achBuf) - cbRead);
     278    }
     279
     280    return rc;
     281}
     282
     283/**
     284 * Skips the given amount of characters in the input stream.
     285 *
     286 * @returns IPRT status code.
     287 * @param   pTokenizer      The tokenizer state.
     288 * @param   cchSkip         The amount of characters to skip.
     289 */
     290static int rtJsonTokenizerSkip(PRTJSONTOKENIZER pTokenizer, unsigned cchSkip)
     291{
     292    int rc = VINF_SUCCESS;
     293
     294    /*
     295     * In case we reached the end of the stream don't even attempt to read new data.
     296     * Safety precaution for possible bugs in the parser causing out of bounds reads
     297     */
     298    if (pTokenizer->achBuf[pTokenizer->offBuf] == '\0')
     299        return rc;
     300
     301    while (   cchSkip > 0
     302           && pTokenizer->offBuf < pTokenizer->cbBuf
     303           && RT_SUCCESS(rc))
     304    {
     305        unsigned cchThisSkip = RT_MIN(cchSkip, pTokenizer->cbBuf - pTokenizer->offBuf);
     306
     307        pTokenizer->offBuf += cchThisSkip;
     308        /* Read new data if required and we didn't reach the end yet. */
     309        if (   pTokenizer->offBuf == pTokenizer->cbBuf
     310            && pTokenizer->cbBuf == sizeof(pTokenizer->achBuf))
     311            rc = rtJsonTokenizerRead(pTokenizer);
     312
     313        cchSkip -= cchThisSkip;
     314    }
     315
     316    return rc;
     317}
     318
     319
     320/**
    215321 * Returns whether the tokenizer reached the end of the stream.
    216322 *
     
    221327DECLINLINE(bool) rtJsonTokenizerIsEos(PRTJSONTOKENIZER pTokenizer)
    222328{
    223     return *pTokenizer->pszInput == '\0';
     329    return pTokenizer->achBuf[pTokenizer->offBuf] == '\0';
    224330}
    225331
     
    232338DECLINLINE(void) rtJsonTokenizerSkipCh(PRTJSONTOKENIZER pTokenizer)
    233339{
    234     pTokenizer->pszInput++;
     340    rtJsonTokenizerSkip(pTokenizer, 1);
    235341    pTokenizer->Pos.iChStart++;
    236342    pTokenizer->Pos.iChEnd++;
     
    247353    return   rtJsonTokenizerIsEos(pTokenizer)
    248354           ? '\0'
    249            : *(pTokenizer->pszInput + 1);
     355           : pTokenizer->achBuf[pTokenizer->offBuf + 1]; /** @todo: Read out of bounds */
    250356}
    251357
     
    264370        ch = '\0';
    265371    else
    266         ch = *pTokenizer->pszInput;
     372        ch = pTokenizer->achBuf[pTokenizer->offBuf];
    267373
    268374    return ch;
     
    277383DECLINLINE(void) rtJsonTokenizerNewLine(PRTJSONTOKENIZER pTokenizer, unsigned cSkip)
    278384{
    279     pTokenizer->pszInput += cSkip;
     385    rtJsonTokenizerSkip(pTokenizer, cSkip);
    280386    pTokenizer->Pos.iLine++;
    281387    pTokenizer->Pos.iChStart = 1;
     
    384490    unsigned uBase = 10;
    385491    char *pszNext = NULL;
    386 
    387     Assert(RT_C_IS_DIGIT(rtJsonTokenizerGetCh(pTokenizer)));
    388 
    389     /* Let RTStrToInt64Ex() do all the work, looks compliant. */
     492    size_t cchNum = 0;
     493    char aszTmp[128]; /* Everything larger is not possible to display in signed 64bit. */
     494    RT_ZERO(aszTmp);
     495
    390496    pToken->enmClass = RTJSONTOKENCLASS_NUMBER;
    391     int rc = RTStrToInt64Ex(pTokenizer->pszInput, &pszNext, 0, &pToken->Class.Number.i64Num);
    392     Assert(RT_SUCCESS(rc) || rc == VWRN_TRAILING_CHARS || rc == VWRN_TRAILING_SPACES);
    393     /** @todo: Handle number to big, throw a warning */
    394 
    395     unsigned cchNumber = pszNext - pTokenizer->pszInput;
    396     for (unsigned i = 0; i < cchNumber; i++)
     497
     498    char ch = rtJsonTokenizerGetCh(pTokenizer);
     499    while (   RT_C_IS_DIGIT(ch)
     500           && cchNum < sizeof(aszTmp) - 1)
     501    {
     502        aszTmp[cchNum] = ch;
     503        cchNum++;
    397504        rtJsonTokenizerSkipCh(pTokenizer);
    398 
    399     return VINF_SUCCESS;
     505        ch = rtJsonTokenizerGetCh(pTokenizer);
     506    }
     507
     508    int rc = VINF_SUCCESS;
     509    if (RT_C_IS_DIGIT(ch) && cchNum == sizeof(aszTmp) - 1)
     510        rc = VERR_NUMBER_TOO_BIG;
     511    else
     512    {
     513        rc = RTStrToInt64Ex(&aszTmp[0], NULL, 0, &pToken->Class.Number.i64Num);
     514        Assert(RT_SUCCESS(rc) || rc == VWRN_NUMBER_TOO_BIG);
     515        if (rc == VWRN_NUMBER_TOO_BIG)
     516            rc = VERR_NUMBER_TOO_BIG;
     517    }
     518
     519    return rc;
    400520}
    401521
     
    422542    char ch = rtJsonTokenizerGetCh(pTokenizer);
    423543    while (   ch != '\"'
    424            && ch != '\0')
     544           && ch != '\0'
     545           && cchStr < sizeof(aszTmp) - 1)
    425546    {
    426547        if (ch == '\\')
     
    545666 * @returns IPRT status code.
    546667 * @param   pTokenizer      The tokenizer state to initialize.
    547  * @param   pszInput        The input to create the tokenizer for.
    548  */
    549 static int rtJsonTokenizerInit(PRTJSONTOKENIZER pTokenizer, const char *pszInput)
    550 {
    551     pTokenizer->pszInput     = pszInput;
     668 * @param   pfnRead         Read callback for the input stream.
     669 * @param   pvUser          Opaque user data to pass to the callback.
     670 */
     671static int rtJsonTokenizerInit(PRTJSONTOKENIZER pTokenizer, PFNRTJSONTOKENIZERREAD pfnRead, void *pvUser)
     672{
     673    pTokenizer->pfnRead      = pfnRead;
     674    pTokenizer->pvUser       = pvUser;
     675    pTokenizer->offInput     = 0;
     676    pTokenizer->cbBuf        = 0;
     677    pTokenizer->offBuf       = 0;
    552678    pTokenizer->Pos.iLine    = 1;
    553679    pTokenizer->Pos.iChStart = 1;
     
    555681    pTokenizer->pTokenCurr   = &pTokenizer->Token1;
    556682    pTokenizer->pTokenNext   = &pTokenizer->Token2;
     683
     684    RT_ZERO(pTokenizer->achBuf);
     685
     686    /* Fill the input buffer. */
     687    int rc = rtJsonTokenizerRead(pTokenizer);
     688
    557689    /* Fill the tokenizer with two first tokens. */
    558     int rc = rtJsonTokenizerReadNextToken(pTokenizer, pTokenizer->pTokenCurr);
     690    if (RT_SUCCESS(rc))
     691        rc = rtJsonTokenizerReadNextToken(pTokenizer, pTokenizer->pTokenCurr);
    559692    if (RT_SUCCESS(rc))
    560693        rc = rtJsonTokenizerReadNextToken(pTokenizer, pTokenizer->pTokenNext);
     
    846979}
    847980
     981/**
     982 * Entry point to parse a JSON document.
     983 *
     984 * @returns IPRT status code.
     985 * @param   pTokenizer      The tokenizer state.
     986 * @param   ppJsonVal       Where to store the root JSON value on success.
     987 * @param   pErrInfo        Where to store extended error info. Optional.
     988 */
     989static int rtJsonParse(PRTJSONTOKENIZER pTokenizer, PRTJSONVALINT *ppJsonVal,
     990                       PRTERRINFO pErrInfo)
     991{
     992    PRTJSONTOKEN pToken = NULL;
     993    int rc = rtJsonTokenizerGetToken(pTokenizer, &pToken);
     994    if (RT_SUCCESS(rc))
     995        rc = rtJsonParseValue(pTokenizer, pToken, ppJsonVal, pErrInfo);
     996
     997    return rc;
     998}
     999
     1000/**
     1001 * Read callback for RTJsonParseFromBuf().
     1002 */
     1003static DECLCALLBACK(int) rtJsonTokenizerParseFromBuf(void *pvUser, uint32_t offInput,
     1004                                                     void *pvBuf, size_t cbBuf,
     1005                                                     size_t *pcbRead)
     1006{
     1007    PRTJSONREADERARGS pArgs = (PRTJSONREADERARGS)pvUser;
     1008    size_t cbLeft = offInput < pArgs->cbData ? pArgs->cbData - offInput : 0;
     1009
     1010    if (cbLeft)
     1011        memcpy(pvBuf, &pArgs->u.pbBuf[offInput], RT_MIN(cbLeft, cbBuf));
     1012
     1013    *pcbRead = RT_MIN(cbLeft, cbBuf);
     1014
     1015    return VINF_SUCCESS;
     1016}
     1017
     1018/**
     1019 * Read callback for RTJsonParseFromString().
     1020 */
     1021static DECLCALLBACK(int) rtJsonTokenizerParseFromString(void *pvUser, uint32_t offInput,
     1022                                                        void *pvBuf, size_t cbBuf,
     1023                                                        size_t *pcbRead)
     1024{
     1025    const char *pszStr = (const char *)pvUser;
     1026    size_t cchStr = strlen(pszStr) + 1; /* Include zero terminator. */
     1027    size_t cbLeft = offInput < cchStr ? cchStr - offInput : 0;
     1028
     1029    if (cbLeft)
     1030        memcpy(pvBuf, &pszStr[offInput], RT_MIN(cbLeft, cbBuf));
     1031
     1032    *pcbRead = RT_MIN(cbLeft, cbBuf);
     1033
     1034    return VINF_SUCCESS;
     1035}
     1036
     1037/**
     1038 * Read callback for RTJsonParseFromFile().
     1039 */
     1040static DECLCALLBACK(int) rtJsonTokenizerParseFromFile(void *pvUser, uint32_t offInput,
     1041                                                      void *pvBuf, size_t cbBuf,
     1042                                                      size_t *pcbRead)
     1043{
     1044    int rc = VINF_SUCCESS;
     1045    PRTJSONREADERARGS pArgs = (PRTJSONREADERARGS)pvUser;
     1046    size_t cbRead = 0;
     1047
     1048    rc = RTStrmReadEx(pArgs->u.hStream, pvBuf, cbBuf, &cbRead);
     1049    if (RT_SUCCESS(rc))
     1050        *pcbRead = cbRead;
     1051
     1052    return rc;
     1053}
    8481054
    8491055RTDECL(int) RTJsonParseFromBuf(PRTJSONVAL phJsonVal, const uint8_t *pbBuf, size_t cbBuf,
    8501056                               PRTERRINFO pErrInfo)
    8511057{
    852     return VERR_NOT_IMPLEMENTED;
     1058    AssertPtrReturn(phJsonVal, VERR_INVALID_POINTER);
     1059    AssertPtrReturn(pbBuf, VERR_INVALID_POINTER);
     1060    AssertReturn(cbBuf > 0, VERR_INVALID_PARAMETER);
     1061
     1062    int rc = VINF_SUCCESS;
     1063    RTJSONREADERARGS Args;
     1064    RTJSONTOKENIZER Tokenizer;
     1065
     1066    Args.cbData  = cbBuf;
     1067    Args.u.pbBuf = pbBuf;
     1068
     1069    rc = rtJsonTokenizerInit(&Tokenizer, rtJsonTokenizerParseFromBuf, &Args);
     1070    if (RT_SUCCESS(rc))
     1071    {
     1072        rc = rtJsonParse(&Tokenizer, phJsonVal, pErrInfo);
     1073        rtJsonTokenizerDestroy(&Tokenizer);
     1074    }
     1075
     1076    return rc;
    8531077}
    8541078
    8551079RTDECL(int) RTJsonParseFromString(PRTJSONVAL phJsonVal, const char *pszStr, PRTERRINFO pErrInfo)
    8561080{
    857     return VERR_NOT_IMPLEMENTED;
     1081    AssertPtrReturn(phJsonVal, VERR_INVALID_POINTER);
     1082    AssertPtrReturn(pszStr, VERR_INVALID_POINTER);
     1083
     1084    int rc = VINF_SUCCESS;
     1085    RTJSONTOKENIZER Tokenizer;
     1086
     1087    rc = rtJsonTokenizerInit(&Tokenizer, rtJsonTokenizerParseFromString, (void *)pszStr);
     1088    if (RT_SUCCESS(rc))
     1089    {
     1090        rc = rtJsonParse(&Tokenizer, phJsonVal, pErrInfo);
     1091        rtJsonTokenizerDestroy(&Tokenizer);
     1092    }
     1093
     1094    return rc;
    8581095}
    8591096
    8601097RTDECL(int) RTJsonParseFromFile(PRTJSONVAL phJsonVal, const char *pszFilename, PRTERRINFO pErrInfo)
    8611098{
    862     return VERR_NOT_IMPLEMENTED;
     1099    AssertPtrReturn(phJsonVal, VERR_INVALID_POINTER);
     1100    AssertPtrReturn(pszFilename, VERR_INVALID_POINTER);
     1101
     1102    int rc = VINF_SUCCESS;
     1103    RTJSONREADERARGS Args;
     1104
     1105    Args.cbData  = 0;
     1106    rc = RTStrmOpen(pszFilename, "r", &Args.u.hStream);
     1107    if (RT_SUCCESS(rc))
     1108    {
     1109        RTJSONTOKENIZER Tokenizer;
     1110
     1111        rc = rtJsonTokenizerInit(&Tokenizer, rtJsonTokenizerParseFromFile, &Args);
     1112        if (RT_SUCCESS(rc))
     1113        {
     1114            rc = rtJsonParse(&Tokenizer, phJsonVal, pErrInfo);
     1115            rtJsonTokenizerDestroy(&Tokenizer);
     1116        }
     1117        RTStrmClose(Args.u.hStream);
     1118    }
     1119
     1120    return rc;
    8631121}
    8641122
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