static STRING_HANDLE Base64_Encode_Internal()

in src/azure_base64.c [236:364]


static STRING_HANDLE Base64_Encode_Internal(const unsigned char* source, size_t size)
{
    STRING_HANDLE result;
    size_t neededSize = 0;
    bool isBufferOverflow = false;
    char* encoded;
    size_t currentPosition = 0;
    neededSize = safe_add_size_t(neededSize, (size == 0) ? (0) : safe_multiply_size_t(safe_add_size_t(((safe_subtract_size_t(size, 1)) / 3), 1), 4));
    neededSize = safe_add_size_t(neededSize, 1);  /*+1 because \0 at the end of the string*/

    if (neededSize == 0 || neededSize == SIZE_MAX)
    {
        result = NULL;
        LogError("Azure_Base64_Encode:: Invalid size parameter, neededSize:%zu.", neededSize);
    }
    /*Codes_SRS_BASE64_06_006: [If when allocating memory to produce the encoding a failure occurs then Azure_Base64_Encode shall return NULL.]*/
    else if ((encoded = (char*)malloc(neededSize)) == NULL)
    {
        result = NULL;
        LogError("Azure_Base64_Encode:: Allocation failed.");
    }
    else
    {
        /*b0            b1(+1)          b2(+2)
        7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0
        |----c1---| |----c2---| |----c3---| |----c4---|
        */

        size_t destinationPosition = 0;
        while (size - currentPosition >= 3)
        {
            char c1 = base64char(source[currentPosition] >> 2);
            char c2 = base64char(
                ((source[currentPosition] & 3) << 4) |
                    (source[currentPosition + 1] >> 4)
            );
            char c3 = base64char(
                ((source[currentPosition + 1] & 0x0F) << 2) |
                    ((source[currentPosition + 2] >> 6) & 3)
            );
            char c4 = base64char(
                source[currentPosition + 2] & 0x3F
            );
            currentPosition += 3;

            if ((destinationPosition + 4) > neededSize)
            {
                LogError("Azure_Base64_Encode:: Invalid buffer size.");
                isBufferOverflow = true;
                break;
            }
            encoded[destinationPosition++] = c1;
            encoded[destinationPosition++] = c2;
            encoded[destinationPosition++] = c3;
            encoded[destinationPosition++] = c4;

        }

        if (!isBufferOverflow && size - currentPosition == 2)
        {
            if ((destinationPosition + 4) > neededSize)
            {
                LogError("Azure_Base64_Encode:: Invalid buffer size.");
                isBufferOverflow = true;
            }
            else
            {
                char c1 = base64char(source[currentPosition] >> 2);
                char c2 = base64char(
                    ((source[currentPosition] & 0x03) << 4) |
                    (source[currentPosition + 1] >> 4)
                );
                char c3 = base64b16(source[currentPosition + 1] & 0x0F);
                encoded[destinationPosition++] = c1;
                encoded[destinationPosition++] = c2;
                encoded[destinationPosition++] = c3;
                encoded[destinationPosition++] = '=';
            }
        }
        else if (!isBufferOverflow && size - currentPosition == 1)
        {
            if ((destinationPosition + 4) > neededSize)
            {
                LogError("Azure_Base64_Encode:: Invalid buffer size.");
                isBufferOverflow = true;
            }
            else
            {
                char c1 = base64char(source[currentPosition] >> 2);
                char c2 = base64b8(source[currentPosition] & 0x03);
                encoded[destinationPosition++] = c1;
                encoded[destinationPosition++] = c2;
                encoded[destinationPosition++] = '=';
                encoded[destinationPosition++] = '=';
            }
        }

        /*null terminating the string*/
        if (!isBufferOverflow)
        {
            if ((destinationPosition + 1) > neededSize)
            {
                LogError("Azure_Base64_Encode:: Invalid buffer size.");
                isBufferOverflow = true;
            }
            else
            {
                encoded[destinationPosition] = '\0';
            }
        }

        if (isBufferOverflow)
        {
            free(encoded);
            result = NULL;
        }
        else
        {
            /*Codes_SRS_BASE64_06_007: [Otherwise Azure_Base64_Encode shall return a pointer to STRING, that string contains the base 64 encoding of input.]*/
            result = STRING_new_with_memory(encoded);
            if (result == NULL)
            {
                free(encoded);
                LogError("Azure_Base64_Encode:: Allocation failed for return value.");
            }
        }
    }
    return result;
}