Azure IoT common library

Dependents:   STM32F746_iothub_client_sample_mqtt f767zi_mqtt iothub_client_sample_amqp iothub_client_sample_http ... more

Revision:
0:fa2de1b79154
Child:
1:9190c0f4d23a
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/base64.c	Fri Apr 08 12:01:36 2016 -0700
@@ -0,0 +1,349 @@
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+//
+// PUT NO INCLUDES BEFORE HERE !!!!
+//
+#include <stdlib.h>
+#ifdef _CRTDBG_MAP_ALLOC
+#include <crtdbg.h>
+#endif
+#include "azure_c_shared_utility/gballoc.h"
+
+#include <stddef.h>
+#include <string.h>
+//
+// PUT NO CLIENT LIBRARY INCLUDES BEFORE HERE !!!!
+//
+#include "azure_c_shared_utility/base64.h"
+#include "azure_c_shared_utility/iot_logging.h"
+
+static const char base64char[64] = {
+    'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
+    'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
+    'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd',
+    'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
+    'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x',
+    'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7',
+    '8', '9', '+', '/'
+};
+
+static const char base64b16[16] = {
+    'A', 'E', 'I', 'M', 'Q', 'U', 'Y', 'c', 'g', 'k',
+    'o', 's', 'w', '0', '4', '8'
+};
+
+static const char base64b8[4] = {
+    'A', 'Q', 'g', 'w'
+};
+
+static int base64toValue(char base64character, unsigned char* value)
+{
+    int result = 0;
+    if (('A' <= base64character) && (base64character <= 'Z'))
+    {
+        *value = base64character - 'A';
+    }
+    else if (('a' <= base64character) && (base64character <= 'z'))
+    {
+        *value = ('Z' - 'A') + 1 + (base64character - 'a');
+    }
+    else if (('0' <= base64character) && (base64character <= '9'))
+    {
+        *value = ('Z' - 'A') + 1 + ('z' - 'a') + 1 + (base64character - '0');
+    }
+    else if ('+' == base64character)
+    {
+        *value = 62;
+    }
+    else if ('/' == base64character)
+    {
+        *value = 63;
+    }
+    else
+    {
+        *value = 0;
+        result = -1;
+    }
+    return result;
+}
+
+static size_t numberOfBase64Characters(const char* encodedString)
+{
+    size_t length = 0;
+    unsigned char junkChar;
+    while (base64toValue(encodedString[length],&junkChar) != -1)
+    {
+        length++;
+    }
+    return length;
+}
+static size_t Base64decode_len(const char *encodedString)
+{
+    size_t absoluteLengthOfString;
+    size_t numberOfBytesToAdd = 0;
+
+    absoluteLengthOfString = strlen(encodedString);
+    if (absoluteLengthOfString)
+    {
+        if (encodedString[absoluteLengthOfString - 1] == '=')
+        {
+            // See if there are two.
+            absoluteLengthOfString--;
+            if (absoluteLengthOfString)
+            {
+                if (encodedString[absoluteLengthOfString - 1] == '=')
+                {
+                    absoluteLengthOfString--;
+                    numberOfBytesToAdd = 1;
+                }
+                else
+                {
+                    numberOfBytesToAdd = 2;
+                }
+            }
+            else
+            {
+                numberOfBytesToAdd = 2;
+            }
+        }
+    }
+    return ((absoluteLengthOfString / 4)*3) + numberOfBytesToAdd;
+}
+
+static void Base64decode(unsigned char *decodedString, const char *base64String)
+{
+
+    size_t numberOfEncodedChars;
+    size_t indexOfFirstEncodedChar;
+    size_t decodedIndex;
+
+    //
+    // We can only operate on individual bytes.  If we attempt to work
+    // on anything larger we could get an alignment fault on some
+    // architectures
+    //
+
+    numberOfEncodedChars = numberOfBase64Characters(base64String);
+    indexOfFirstEncodedChar = 0;
+    decodedIndex = 0;
+    while (numberOfEncodedChars >= 4)
+    {
+        unsigned char c1;
+        unsigned char c2;
+        unsigned char c3;
+        unsigned char c4;
+        (void)base64toValue(base64String[indexOfFirstEncodedChar], &c1);
+        (void)base64toValue(base64String[indexOfFirstEncodedChar + 1], &c2);
+        (void)base64toValue(base64String[indexOfFirstEncodedChar + 2], &c3);
+        (void)base64toValue(base64String[indexOfFirstEncodedChar + 3], &c4);
+        decodedString[decodedIndex] = (c1 << 2) | (c2 >> 4);
+        decodedIndex++;
+        decodedString[decodedIndex] = ((c2 & 0x0f) << 4) | (c3 >> 2);
+        decodedIndex++;
+        decodedString[decodedIndex] = ((c3 & 0x03) << 6) | c4;
+        decodedIndex++;
+        numberOfEncodedChars -= 4;
+        indexOfFirstEncodedChar += 4;
+
+    }
+
+    if (numberOfEncodedChars == 2)
+    {
+        unsigned char c1;
+        unsigned char c2;
+        (void)base64toValue(base64String[indexOfFirstEncodedChar], &c1);
+        (void)base64toValue(base64String[indexOfFirstEncodedChar + 1], &c2);
+        decodedString[decodedIndex] = (c1 << 2) | (c2 >> 4);
+    }
+    else if (numberOfEncodedChars == 3)
+    {
+        unsigned char c1;
+        unsigned char c2;
+        unsigned char c3;
+        (void)base64toValue(base64String[indexOfFirstEncodedChar], &c1);
+        (void)base64toValue(base64String[indexOfFirstEncodedChar + 1], &c2);
+        (void)base64toValue(base64String[indexOfFirstEncodedChar + 2], &c3);
+        decodedString[decodedIndex] = (c1 << 2) | (c2 >> 4);
+        decodedIndex++;
+        decodedString[decodedIndex] = ((c2 & 0x0f) << 4) | (c3 >> 2);
+    }
+}
+
+BUFFER_HANDLE Base64_Decoder(const char* source)
+{
+    BUFFER_HANDLE result = NULL;
+    /*Codes_SRS_BASE64_06_008: [If source is NULL then Base64_Decode shall return NULL.]*/
+    if (source)
+    {
+        size_t lengthOfSource = numberOfBase64Characters(source);
+        if ((lengthOfSource % 4) == 1)
+        {
+            /*Codes_SRS_BASE64_06_011: [If the source string has an invalid length for a base 64 encoded string then Base64_Decode shall return NULL.]*/
+            LogError("Invalid length Base64 string!\r\n");
+        }
+        else
+        {
+            if ((result = BUFFER_new()) == NULL)
+            {
+                /*Codes_SRS_BASE64_06_010: [If there is any memory allocation failure during the decode then Base64_Decode shall return NULL.]*/
+                LogError("Could not create a buffer to decoding.\r\n");
+            }
+            else
+            {
+                size_t sizeOfOutputBuffer = Base64decode_len(source);
+                /*Codes_SRS_BASE64_06_009: [If the string pointed to by source is zero length then the handle returned shall refer to a zero length buffer.]*/
+                if (sizeOfOutputBuffer > 0)
+                {
+                    if (BUFFER_pre_build(result, sizeOfOutputBuffer) != 0)
+                    {
+                        /*Codes_SRS_BASE64_06_010: [If there is any memory allocation failure during the decode then Base64_Decode shall return NULL.]*/
+                        LogError("Could not prebuild a buffer for base 64 decoding.\r\n");
+                        BUFFER_delete(result);
+                        result = NULL;
+                    }
+                    else
+                    {
+                        Base64decode(BUFFER_u_char(result), source);
+                    }
+                }
+            }
+        }
+    }
+    return result;
+}
+
+
+static STRING_HANDLE Base64_Encode_Internal(const unsigned char* source, size_t size)
+{
+    STRING_HANDLE result;
+    size_t neededSize = 0;
+    char* encoded;
+    size_t currentPosition = 0;
+    neededSize += (size == 0) ? (0) : ((((size - 1) / 3) + 1) * 4);
+    neededSize += 1; /*+1 because \0 at the end of the string*/
+    /*Codes_SRS_BASE64_06_006: [If when allocating memory to produce the encoding a failure occurs then Base64_Encode shall return NULL.]*/
+    encoded = (char*)malloc(neededSize);
+    if (encoded == NULL)
+    {
+        result = NULL;
+        LogError("Base64_Encode:: Allocation failed.\r\n");
+    }
+    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;
+            encoded[destinationPosition++] = c1;
+            encoded[destinationPosition++] = c2;
+            encoded[destinationPosition++] = c3;
+            encoded[destinationPosition++] = c4;
+
+        }
+        if (size - currentPosition == 2)
+        {
+            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 (size - currentPosition == 1)
+        {
+            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*/
+        encoded[destinationPosition] = '\0';
+        /*Codes_SRS_BASE64_06_007: [Otherwise 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("Base64_Encode:: Allocation failed for return value.\r\n");
+        }
+    }
+    return result;
+}
+
+STRING_HANDLE Base64_Encode_Bytes(const unsigned char* source, size_t size)
+{
+    STRING_HANDLE result;
+    /*Codes_SRS_BASE64_02_001: [If source is NULL then Base64_Encode_Bytes shall return NULL.] */
+    if (source == NULL)
+    {
+        result = NULL;
+    }
+    /*Codes_SRS_BASE64_02_002: [If source is not NULL and size is zero, then Base64_Encode_Bytes shall produce an empty STRING_HANDLE.] */
+    else if (size == 0)
+    {
+        result = STRING_new(); /*empty string*/
+    }
+    else
+    {
+        result = Base64_Encode_Internal(source, size);
+    }
+    return result;
+}
+
+STRING_HANDLE Base64_Encode(BUFFER_HANDLE input)
+{
+    STRING_HANDLE result;
+    /*the following will happen*/
+    /*1. the "data" of the binary shall be "eaten" 3 characters at a time and produce 4 base64 encoded characters for as long as there are more than 3 characters still to process*/
+    /*2. the remaining characters (1 or 2) shall be encoded.*/
+    /*there's a level of assumption that 'a' corresponds to 0b000000 and that '_' corresponds to 0b111111*/
+    /*the encoding will use the optional [=] or [==] at the end of the encoded string, so that other less standard aware libraries can do their work*/
+    /*these are the bits of the 3 normal bytes to be encoded*/
+
+    /*Codes_SRS_BASE64_06_001: [If input is NULL then Base64_Encode shall return NULL.]*/
+    if (input == NULL)
+    {
+        result = NULL;
+        LogError("Base64_Encode:: NULL input\r\n");
+    }
+    else
+    {
+        size_t inputSize;
+        const unsigned char* inputBinary;
+        if ((BUFFER_content(input, &inputBinary) != 0) ||
+            (BUFFER_size(input, &inputSize) != 0))
+        {
+            result = NULL;
+            LogError("Base64_Encode:: BUFFER_routines failure.\r\n");
+        }
+        else
+        {
+            result = Base64_Encode_Internal(inputBinary, inputSize);
+        }
+    }
+    return result;
+}