LCOV - code coverage report
Current view: top level - src/plugins/base64 - base64_functions.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 55 57 96.5 %
Date: 2019-09-12 12:28:41 Functions: 2 2 100.0 %

          Line data    Source code
       1             : #include "base64_functions.h"
       2             : #include <kdbassert.h>
       3             : #include <kdberrors.h>
       4             : 
       5             : static const char alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
       6             : #define ALPHABET_LENGTH (sizeof (alphabet) - 1)
       7             : static const char padding = '=';
       8             : 
       9             : /**
      10             :  * @brief encodes arbitrary binary data using the Base64 encoding scheme (RFC4648)
      11             :  * @param input holds the data to be encoded
      12             :  * @param inputLength tells how many bytes the input buffer is holding.
      13             :  * @returns an allocated string holding the Base64 encoded input data or NULL if the string can not be allocated. Must be freed by the
      14             :             caller.
      15             :  */
      16          34 : char * base64Encode (const kdb_octet_t * input, const size_t inputLength)
      17             : #ifdef __llvm__
      18             :         __attribute__ ((annotate ("oclint:suppress[long method]")))
      19             : #endif
      20             : {
      21          34 :         size_t encodedLength = 0;
      22          34 :         if (inputLength % 3 == 0)
      23             :         {
      24          15 :                 encodedLength = (inputLength / 3 * 4) + 1;
      25             :         }
      26             :         else
      27             :         {
      28          19 :                 encodedLength = ((inputLength + (3 - (inputLength % 3))) / 3 * 4) + 1;
      29             :         }
      30             :         ELEKTRA_ASSERT (encodedLength > 0, "Base64 output array size smaller or equal to 0.");
      31             : 
      32          34 :         size_t out = 0;
      33          34 :         char * encoded = elektraMalloc (encodedLength);
      34          34 :         if (!encoded) return NULL;
      35             : 
      36         112 :         for (size_t i = 0; i < inputLength; i += 3)
      37             :         {
      38         112 :                 if (inputLength - i < 3)
      39             :                 {
      40             :                         // padding required
      41          19 :                         kdb_octet_t padded[3] = { 0 };
      42          19 :                         memcpy (padded, input + i, inputLength - i);
      43             : 
      44          19 :                         encoded[out++] = alphabet[padded[0] >> 2];
      45          19 :                         encoded[out++] = alphabet[((padded[0] << 4) + (padded[1] >> 4)) & 0x3f];
      46             : 
      47          19 :                         if (inputLength - i == 2)
      48             :                         {
      49             :                                 // 2 octets available in input
      50          14 :                                 encoded[out++] = alphabet[((padded[1] << 2) + (padded[2] >> 6)) & 0x3f];
      51          14 :                                 encoded[out++] = padding;
      52             :                         }
      53             :                         else
      54             :                         {
      55             :                                 // 1 octet available in input
      56           5 :                                 encoded[out++] = padding;
      57           5 :                                 encoded[out++] = padding;
      58             :                         }
      59             :                 }
      60             :                 else
      61             :                 {
      62             :                         // no padding required
      63          93 :                         encoded[out++] = alphabet[input[i] >> 2];
      64          93 :                         encoded[out++] = alphabet[((input[i] << 4) + (input[i + 1] >> 4)) & 0x3f];
      65          93 :                         encoded[out++] = alphabet[((input[i + 1] << 2) + (input[i + 2] >> 6)) & 0x3f];
      66          93 :                         encoded[out++] = alphabet[input[i + 2] & 0x3f];
      67             :                 }
      68             :         }
      69          34 :         encoded[out++] = '\0';
      70          34 :         return encoded;
      71             : }
      72             : 
      73             : /**
      74             :  * @brief lookup Base64 character in the alphabet and return the index.
      75             :  * @param character the character to look up
      76             :  * @param errorFlag set to 1 in case of error
      77             :  * @returns the index in the Base64 alphabet or 0 if the padding character was detected.
      78             :  */
      79             : static kdb_octet_t getBase64Index (const char character, int * errorFlag)
      80             : {
      81         716 :         if (character == padding) return 0;
      82             : 
      83       19907 :         for (kdb_octet_t i = 0; i < ALPHABET_LENGTH; i++)
      84             :         {
      85       20580 :                 if (alphabet[i] == character) return i;
      86             :         }
      87             :         *errorFlag = 1;
      88             :         return 0;
      89             : }
      90             : 
      91             : /**
      92             :  * @brief decodes Base64 encoded data.
      93             :  * @param input holds the Base64 encoded data string
      94             :  * @param output will be set to an allocated buffer holding the decoded data or NULL if the allocation failed. Must be freed by the caller
      95             :           on success.
      96             :  * @param outputLength will be set to the amount of decoded bytes.
      97             :  * @retval 1 on success
      98             :  * @retval -1 if the provided string has not been encoded with Base64
      99             :  * @retval -2 if the output buffer allocation failed
     100             :  */
     101          57 : int base64Decode (const char * input, kdb_octet_t ** output, size_t * outputLength)
     102             : #ifdef __llvm__
     103             :         __attribute__ ((annotate ("oclint:suppress[high ncss method]"), annotate ("oclint:suppress[high npath complexity]"),
     104             :                         annotate ("oclint:suppress[long method]"), annotate ("oclint:suppress[high cyclomatic complexity]")))
     105             : #endif
     106             : {
     107          57 :         const size_t inputLen = strlen (input);
     108          57 :         if (inputLen == 0 || (inputLen == 1 && input[0] == '\0'))
     109             :         {
     110          10 :                 *output = NULL;
     111          10 :                 *outputLength = 0;
     112          10 :                 return 1;
     113             :         }
     114             : 
     115          47 :         if (inputLen % 4 != 0)
     116             :         {
     117           0 :                 *output = NULL;
     118           0 :                 return -1;
     119             :         }
     120             : 
     121          47 :         *outputLength = inputLen / 4 * 3;
     122          47 :         if (input[inputLen - 1] == padding) (*outputLength)--;
     123          47 :         if (input[inputLen - 2] == padding) (*outputLength)--;
     124             : 
     125          47 :         *output = elektraMalloc (*outputLength);
     126          47 :         if (!(*output)) return -2;
     127             : 
     128             :         size_t position = 0;
     129             :         size_t outputIndex = 0;
     130             : 
     131         177 :         for (position = 0; position < inputLen; position += 4)
     132             :         {
     133         179 :                 int errorFlag = 0;
     134         358 :                 const kdb_octet_t byte0 = getBase64Index (input[position], &errorFlag);
     135         358 :                 const kdb_octet_t byte1 = getBase64Index (input[position + 1], &errorFlag);
     136         358 :                 const kdb_octet_t byte2 = getBase64Index (input[position + 2], &errorFlag);
     137         358 :                 const kdb_octet_t byte3 = getBase64Index (input[position + 3], &errorFlag);
     138             : 
     139         179 :                 if (errorFlag)
     140             :                 {
     141             :                         // invalid character detected in input string
     142           2 :                         elektraFree (*output);
     143           2 :                         *output = NULL;
     144           2 :                         return -1;
     145             :                 }
     146             : 
     147         177 :                 (*output)[outputIndex++] = (kdb_octet_t) (byte0 << 2) + (kdb_octet_t) (byte1 >> 4);
     148         177 :                 if (input[position + 2] != padding)
     149             :                 {
     150         171 :                         (*output)[outputIndex++] = (kdb_octet_t) (byte1 << 4) + (kdb_octet_t) (byte2 >> 2);
     151             :                 }
     152         177 :                 if (input[position + 3] != padding)
     153             :                 {
     154         148 :                         (*output)[outputIndex++] = (kdb_octet_t) (byte2 << 6) + (kdb_octet_t) byte3;
     155             :                 }
     156             :         }
     157             :         return 1;
     158             : }

Generated by: LCOV version 1.13