STRING_HANDLE STRING_new_JSON()

in src/strings.c [268:409]


STRING_HANDLE STRING_new_JSON(const char* source)
{
    STRING* result;
    if (source == NULL)
    {
        /*Codes_SRS_STRING_02_011: [If source is NULL then STRING_new_JSON shall return NULL.] */
        result = NULL;
        LogError("invalid arg (NULL)");
    }
    else
    {
        size_t i;
        size_t nControlCharacters = 0; /*counts how many characters are to be expanded from 1 character to \uxxxx (6 characters)*/
        size_t nEscapeCharacters = 0;
        size_t vlen = strlen(source);

        for (i = 0; i < vlen; i++)
        {
            /*Codes_SRS_STRING_02_014: [If any character has the value outside [1...127] then STRING_new_JSON shall fail and return NULL.] */
            if ((unsigned char)source[i] >= 128) /*this be a UNICODE character begin*/
            {
                break;
            }
            else
            {
                if (source[i] <= 0x1F)
                {
                    nControlCharacters++;
                }
                else if (
                    (source[i] == '"') ||
                    (source[i] == '\\') ||
                    (source[i] == '/')
                    )
                {
                    nEscapeCharacters++;
                }
            }
        }

        if (i < vlen)
        {
            result = NULL;
            LogError("invalid character in input string");
        }
        else
        {
            if ((result = malloc(sizeof(STRING))) == NULL)
            {
                /*Codes_SRS_STRING_02_021: [If the complete JSON representation cannot be produced, then STRING_new_JSON shall fail and return NULL.] */
                LogError("failure in malloc(sizeof(STRING)=%zu)",
                    sizeof(STRING));
            }
            else
            {
                /*compute possible overflow of the value passed to malloc vlen + 5 * nControlCharacters + nEscapeCharacters + 3*/
                size_t size_to_alloc = 0;
                if (vlen > SIZE_MAX - 3)
                {
                    LogError("overflow: vlen=%zu + 3 exceeds SIZE_MAX=%zu", vlen, SIZE_MAX);
                }
                else
                {
                    size_to_alloc = vlen + 3;
                    if (SIZE_MAX - nEscapeCharacters < size_to_alloc)
                    {
                        LogError("overflow: nEscapeCharacters=%zu + size_to_alloc=%zu would exceed SIZE_MAX=%zu", nEscapeCharacters, size_to_alloc, SIZE_MAX);
                    }
                    else
                    {
                        size_to_alloc += nEscapeCharacters;
                        if ((SIZE_MAX - size_to_alloc) / 5 < nControlCharacters)
                        {
                            LogError("overflow: 5 * nControlCharacters=%zu + size_to_alloc=%zu would exceed SIZE_MAX=%zu", nControlCharacters, size_to_alloc, SIZE_MAX);
                        }
                        else
                        {
                            if ((result->s = malloc(vlen + 5 * nControlCharacters + nEscapeCharacters + 3)) == NULL)
                            {
                                /*Codes_SRS_STRING_02_021: [If the complete JSON representation cannot be produced, then STRING_new_JSON shall fail and return NULL.] */
                                LogError("failure in malloc(vlen=%zu + 5 * nControlCharacters=%zu + nEscapeCharacters=%zu + 3",
                                    vlen, nControlCharacters, nEscapeCharacters);
                            }
                            else
                            {
                                size_t pos = 0;
                                /*Codes_SRS_STRING_02_012: [The string shall begin with the quote character.] */
                                result->s[pos++] = '"';
                                for (i = 0; i < vlen; i++)
                                {
                                    if (source[i] <= 0x1F)
                                    {
                                        /*Codes_SRS_STRING_02_019: [If the character code is less than 0x20 then it shall be represented as \u00xx, where xx is the hex representation of the character code.]*/
                                        result->s[pos++] = '\\';
                                        result->s[pos++] = 'u';
                                        result->s[pos++] = '0';
                                        result->s[pos++] = '0';
                                        result->s[pos++] = hexToASCII[(source[i] & 0xF0) >> 4]; /*high nibble*/
                                        result->s[pos++] = hexToASCII[source[i] & 0x0F]; /*low nibble*/
                                    }
                                    else if (source[i] == '"')
                                    {
                                        /*Codes_SRS_STRING_02_016: [If the character is " (quote) then it shall be repsented as \".] */
                                        result->s[pos++] = '\\';
                                        result->s[pos++] = '"';
                                    }
                                    else if (source[i] == '\\')
                                    {
                                        /*Codes_SRS_STRING_02_017: [If the character is \ (backslash) then it shall represented as \\.] */
                                        result->s[pos++] = '\\';
                                        result->s[pos++] = '\\';
                                    }
                                    else if (source[i] == '/')
                                    {
                                        /*Codes_SRS_STRING_02_018: [If the character is / (slash) then it shall be represented as \/.] */
                                        result->s[pos++] = '\\';
                                        result->s[pos++] = '/';
                                    }
                                    else
                                    {
                                        /*Codes_SRS_STRING_02_013: [The string shall copy the characters of source "as they are" (until the '\0' character) with the following exceptions:] */
                                        result->s[pos++] = source[i];
                                    }
                                }
                                /*Codes_SRS_STRING_02_020: [The string shall end with " (quote).] */
                                result->s[pos++] = '"';
                                /*zero terminating it*/
                                result->s[pos] = '\0';
                                goto allok;
                            }
                        }
                    }
                }
                
            }
            free(result);
            result = NULL;
        }
    allok:;
    }
    return (STRING_HANDLE)result;
}