STRING_HANDLE STRING_new_JSON()

in src/strings.c [257:394]


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
        {
            //size_t malloc_len = vlen + 5 * nControlCharacters + nEscapeCharacters + 3;
            size_t malloc_len = safe_multiply_size_t(5, nControlCharacters);
            malloc_len = safe_add_size_t(malloc_len, vlen);
            malloc_len = safe_add_size_t(malloc_len, nEscapeCharacters);
            malloc_len = safe_add_size_t(malloc_len, 3);

            if (malloc_len == SIZE_MAX)
            {
                result = NULL;
                LogError("malloc len overflow");
            }
            else if ((result = (STRING*)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("malloc json failure");
            }
            else if ((result->s = (char*)malloc(malloc_len)) == NULL)
            {
                /*Codes_SRS_STRING_02_021: [If the complete JSON representation cannot be produced, then STRING_new_JSON shall fail and return NULL.] */
                free(result);
                result = NULL;
                LogError("malloc failed");
            }
            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) && ((pos + 6) <= malloc_len))
                    {
                        /*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] == '"') && ((pos + 2) <= malloc_len))
                    {
                        /*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] == '\\') && ((pos + 2) <= malloc_len))
                    {
                        /*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] == '/') && ((pos + 2) <= malloc_len))
                    {
                        /*Codes_SRS_STRING_02_018: [If the character is / (slash) then it shall be represented as \/.] */
                        result->s[pos++] = '\\';
                        result->s[pos++] = '/';
                    }
                    else if (pos < malloc_len)
                    {
                        /*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];
                    }
                    else
                    {
                        free(result->s);
                        free(result);
                        result = NULL;
                        break;
                    }
                }

                if ((pos + 1) < malloc_len)
                {
                    /*Codes_SRS_STRING_02_020: [The string shall end with " (quote).] */
                    result->s[pos++] = '"';
                    /*zero terminating it*/
                    result->s[pos] = '\0';
                }
                else
                {
                    free(result->s);
                    free(result);
                    result = NULL;
                }
            }
        }

    }
    return (STRING_HANDLE)result;
}