LCOV - code coverage report
Current view: top level - src/plugins/base64 - base64_functions.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 56 58 96.6 %
Date: 2022-05-21 16:19:22 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          53 : 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          53 :         size_t encodedLength = 0;
      22          53 :         if (inputLength % 3 == 0)
      23             :         {
      24          21 :                 encodedLength = (inputLength / 3 * 4) + 1;
      25             :         }
      26             :         else
      27             :         {
      28          32 :                 encodedLength = ((inputLength + (3 - (inputLength % 3))) / 3 * 4) + 1;
      29             :         }
      30          53 :         ELEKTRA_ASSERT (encodedLength > 0, "Base64 output array size smaller or equal to 0.");
      31             : 
      32          53 :         size_t out = 0;
      33          53 :         char * encoded = elektraMalloc (encodedLength);
      34          53 :         if (!encoded) return NULL;
      35             : 
      36         354 :         for (size_t i = 0; i < inputLength; i += 3)
      37             :         {
      38         301 :                 if (inputLength - i < 3)
      39             :                 {
      40             :                         // padding required
      41          32 :                         kdb_octet_t padded[3] = { 0 };
      42          32 :                         memcpy (padded, input + i, inputLength - i);
      43             : 
      44          32 :                         encoded[out++] = alphabet[padded[0] >> 2];
      45          32 :                         encoded[out++] = alphabet[((padded[0] << 4) + (padded[1] >> 4)) & 0x3f];
      46             : 
      47          32 :                         if (inputLength - i == 2)
      48             :                         {
      49             :                                 // 2 octets available in input
      50          23 :                                 encoded[out++] = alphabet[((padded[1] << 2) + (padded[2] >> 6)) & 0x3f];
      51          23 :                                 encoded[out++] = padding;
      52             :                         }
      53             :                         else
      54             :                         {
      55             :                                 // 1 octet available in input
      56           9 :                                 encoded[out++] = padding;
      57           9 :                                 encoded[out++] = padding;
      58             :                         }
      59             :                 }
      60             :                 else
      61             :                 {
      62             :                         // no padding required
      63         269 :                         encoded[out++] = alphabet[input[i] >> 2];
      64         269 :                         encoded[out++] = alphabet[((input[i] << 4) + (input[i + 1] >> 4)) & 0x3f];
      65         269 :                         encoded[out++] = alphabet[((input[i + 1] << 2) + (input[i + 2] >> 6)) & 0x3f];
      66         269 :                         encoded[out++] = alphabet[input[i + 2] & 0x3f];
      67             :                 }
      68             :         }
      69          53 :         encoded[out++] = '\0';
      70          53 :         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        2692 :         if (character == padding) return 0;
      82             : 
      83       81321 :         for (kdb_octet_t i = 0; i < ALPHABET_LENGTH; i++)
      84             :         {
      85       81309 :                 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          75 : 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          75 :         const size_t inputLen = strlen (input);
     108          75 :         if (inputLen == 0 || (inputLen == 1 && input[0] == '\0'))
     109             :         {
     110           6 :                 *output = NULL;
     111           6 :                 *outputLength = 0;
     112           6 :                 return 1;
     113             :         }
     114             : 
     115          69 :         if (inputLen % 4 != 0)
     116             :         {
     117           0 :                 *output = NULL;
     118           0 :                 return -1;
     119             :         }
     120             : 
     121          69 :         *outputLength = inputLen / 4 * 3;
     122          69 :         if (input[inputLen - 1] == padding) (*outputLength)--;
     123          69 :         if (input[inputLen - 2] == padding) (*outputLength)--;
     124             : 
     125          69 :         *output = elektraMalloc (*outputLength);
     126          69 :         if (!(*output)) return -2;
     127             : 
     128             :         size_t position = 0;
     129             :         size_t outputIndex = 0;
     130             : 
     131         739 :         for (position = 0; position < inputLen; position += 4)
     132             :         {
     133         673 :                 int errorFlag = 0;
     134         673 :                 const kdb_octet_t byte0 = getBase64Index (input[position], &errorFlag);
     135         673 :                 const kdb_octet_t byte1 = getBase64Index (input[position + 1], &errorFlag);
     136         673 :                 const kdb_octet_t byte2 = getBase64Index (input[position + 2], &errorFlag);
     137         673 :                 const kdb_octet_t byte3 = getBase64Index (input[position + 3], &errorFlag);
     138             : 
     139         673 :                 if (errorFlag)
     140             :                 {
     141             :                         // invalid character detected in input string
     142           3 :                         elektraFree (*output);
     143           3 :                         *output = NULL;
     144           3 :                         return -1;
     145             :                 }
     146             : 
     147         670 :                 (*output)[outputIndex++] = (kdb_octet_t) ((byte0 << 2) + (byte1 >> 4));
     148         670 :                 if (input[position + 2] != padding)
     149             :                 {
     150         648 :                         (*output)[outputIndex++] = (kdb_octet_t) ((byte1 << 4) + (byte2 >> 2));
     151             :                 }
     152         670 :                 if (input[position + 3] != padding)
     153             :                 {
     154         619 :                         (*output)[outputIndex++] = (kdb_octet_t) ((byte2 << 6) + byte3);
     155             :                 }
     156             :         }
     157             :         return 1;
     158             : }

Generated by: LCOV version 1.13