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;
}