Nigel Rantor / azure_c_shared_utility

Fork of azure_c_shared_utility by Azure IoT

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers urlencode.c Source File

urlencode.c

00001 // Copyright (c) Microsoft. All rights reserved.
00002 // Licensed under the MIT license. See LICENSE file in the project root for full license information.
00003 
00004 #include <stdlib.h>
00005 #include <stddef.h>
00006 #include <string.h>
00007 #include "azure_c_shared_utility/gballoc.h"
00008 #include "azure_c_shared_utility/urlencode.h"
00009 #include "azure_c_shared_utility/xlogging.h"
00010 #include "azure_c_shared_utility/strings.h"
00011 
00012 #define NIBBLE_STR(c) (char)(c < 10 ? c + '0' : c - 10 + 'a')
00013 #define IS_PRINTABLE(c) (                           \
00014     (c == 0) ||                                     \
00015     (c == '!') ||                                   \
00016     (c == '(') || (c == ')') || (c == '*') ||       \
00017     (c == '-') || (c == '.') ||                     \
00018     ((c >= '0') && (c <= '9')) ||                   \
00019     ((c >= 'A') && (c <= 'Z')) ||                   \
00020     (c == '_') ||                                   \
00021     ((c >= 'a') && (c <= 'z'))                      \
00022 )
00023 
00024 static size_t URL_PrintableChar(unsigned char charVal, char* buffer)
00025 {
00026     size_t size;
00027     if (IS_PRINTABLE(charVal))
00028     {
00029         buffer[0] = (char)charVal;
00030         size = 1;
00031     }
00032     else
00033     {
00034         char bigNibbleStr;
00035         char littleNibbleStr;
00036         unsigned char bigNibbleVal = charVal >> 4;
00037         unsigned char littleNibbleVal = charVal & 0x0F;
00038 
00039         if (bigNibbleVal >= 0x0C)
00040         {
00041             bigNibbleVal -= 0x04;
00042         }
00043 
00044         bigNibbleStr = NIBBLE_STR(bigNibbleVal);
00045         littleNibbleStr = NIBBLE_STR(littleNibbleVal);
00046 
00047         buffer[0] = '%';
00048 
00049         if (charVal < 0x80)
00050         {
00051             buffer[1] = bigNibbleStr;
00052             buffer[2] = littleNibbleStr;
00053             size = 3;
00054         }
00055         else
00056         {
00057             buffer[1] = 'c';
00058             buffer[3] = '%';
00059             buffer[4] = bigNibbleStr;
00060             buffer[5] = littleNibbleStr;
00061             if (charVal < 0xC0)
00062             {
00063                 buffer[2] = '2';
00064             }
00065             else
00066             {
00067                 buffer[2] = '3';
00068             }
00069             size = 6;
00070         }
00071     }
00072 
00073     return size;
00074 }
00075 
00076 static size_t URL_PrintableCharSize(unsigned char charVal)
00077 {
00078     size_t size;
00079     if (IS_PRINTABLE(charVal))
00080     {
00081         size = 1;
00082     }
00083     else
00084     {
00085         if (charVal < 0x80)
00086         {
00087             size = 3;
00088         }
00089         else
00090         {
00091             size = 6;
00092         }
00093     }
00094     return size;
00095 }
00096 
00097 STRING_HANDLE URL_EncodeString(const char* textEncode)
00098 {
00099     STRING_HANDLE result;
00100     if (textEncode == NULL)
00101     {
00102         result = NULL;
00103     }
00104     else
00105     {
00106         STRING_HANDLE tempString = STRING_construct(textEncode);
00107         if (tempString == NULL)
00108         {
00109             result = NULL;
00110         }
00111         else
00112         {
00113             result = URL_Encode(tempString);
00114             STRING_delete(tempString);
00115         }
00116     }
00117     return result;
00118 }
00119 
00120 STRING_HANDLE URL_Encode(STRING_HANDLE input)
00121 {
00122     STRING_HANDLE result;
00123     if (input == NULL)
00124     {
00125         /*Codes_SRS_URL_ENCODE_06_001: [If input is NULL then URL_Encode will return NULL.]*/
00126         result = NULL;
00127         LogError("URL_Encode:: NULL input");
00128     }
00129     else
00130     {
00131         size_t lengthOfResult = 0;
00132         char* encodedURL;
00133         const char* currentInput;
00134         unsigned char currentUnsignedChar;
00135         currentInput = STRING_c_str(input);
00136         /*Codes_SRS_URL_ENCODE_06_003: [If input is a zero length string then URL_Encode will return a zero length string.]*/
00137         do
00138         {
00139             currentUnsignedChar = (unsigned char)(*currentInput++);
00140             lengthOfResult += URL_PrintableCharSize(currentUnsignedChar);
00141         } while (currentUnsignedChar != 0);
00142         if ((encodedURL = (char*)malloc(lengthOfResult)) == NULL)
00143         {
00144             /*Codes_SRS_URL_ENCODE_06_002: [If an error occurs during the encoding of input then URL_Encode will return NULL.]*/
00145             result = NULL;
00146             LogError("URL_Encode:: MALLOC failure on encode.");
00147         }
00148         else
00149         {
00150             size_t currentEncodePosition = 0;
00151             currentInput = STRING_c_str(input);
00152             do
00153             {
00154                 currentUnsignedChar = (unsigned char)(*currentInput++);
00155                 currentEncodePosition += URL_PrintableChar(currentUnsignedChar, &encodedURL[currentEncodePosition]);
00156             } while (currentUnsignedChar != 0);
00157 
00158             result = STRING_new_with_memory(encodedURL);
00159             if (result == NULL)
00160             {
00161                 LogError("URL_Encode:: MALLOC failure on encode.");
00162                 free(encodedURL);
00163             }
00164         }
00165     }
00166     return result;
00167 }