b64_fuzzer.cpp:_ZN4crow7utilityL12base64encodeENSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEmPKc:
  597|    453|        {
  598|    453|            return base64encode((const unsigned char*)data.c_str(), size, key);
  599|    453|        }
b64_fuzzer.cpp:_ZN4crow7utilityL12base64encodeEPKhmPKc:
  561|    453|        {
  562|    453|            std::string ret;
  563|    453|            ret.resize((size + 2) / 3 * 4);
  564|    453|            auto it = ret.begin();
  565|  12.2M|            while (size >= 3)
  ------------------
  |  Branch (565:20): [True: 12.2M, False: 453]
  ------------------
  566|  12.2M|            {
  567|  12.2M|                *it++ = key[(static_cast<unsigned char>(*data) & 0xFC) >> 2];
  568|  12.2M|                unsigned char h = (static_cast<unsigned char>(*data++) & 0x03) << 4;
  569|  12.2M|                *it++ = key[h | ((static_cast<unsigned char>(*data) & 0xF0) >> 4)];
  570|  12.2M|                h = (static_cast<unsigned char>(*data++) & 0x0F) << 2;
  571|  12.2M|                *it++ = key[h | ((static_cast<unsigned char>(*data) & 0xC0) >> 6)];
  572|  12.2M|                *it++ = key[static_cast<unsigned char>(*data++) & 0x3F];
  573|       |
  574|  12.2M|                size -= 3;
  575|  12.2M|            }
  576|    453|            if (size == 1)
  ------------------
  |  Branch (576:17): [True: 117, False: 336]
  ------------------
  577|    117|            {
  578|    117|                *it++ = key[(static_cast<unsigned char>(*data) & 0xFC) >> 2];
  579|    117|                unsigned char h = (static_cast<unsigned char>(*data++) & 0x03) << 4;
  580|    117|                *it++ = key[h];
  581|    117|                *it++ = '=';
  582|    117|                *it++ = '=';
  583|    117|            }
  584|    336|            else if (size == 2)
  ------------------
  |  Branch (584:22): [True: 125, False: 211]
  ------------------
  585|    125|            {
  586|    125|                *it++ = key[(static_cast<unsigned char>(*data) & 0xFC) >> 2];
  587|    125|                unsigned char h = (static_cast<unsigned char>(*data++) & 0x03) << 4;
  588|    125|                *it++ = key[h | ((static_cast<unsigned char>(*data) & 0xF0) >> 4)];
  589|    125|                h = (static_cast<unsigned char>(*data++) & 0x0F) << 2;
  590|    125|                *it++ = key[h];
  591|    125|                *it++ = '=';
  592|    125|            }
  593|    453|            return ret;
  594|    453|        }
b64_fuzzer.cpp:_ZN4crow7utilityL12base64decodeERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEm:
  687|    453|        {
  688|    453|            return base64decode(data.data(), size);
  689|    453|        }
b64_fuzzer.cpp:_ZN4crow7utilityL12base64decodeEPKcm:
  612|    453|        {
  613|       |            // We accept both regular and url encoding here, as there does not seem to be any downside to that.
  614|       |            // If we want to distinguish that we should use +/ for non-url and -_ for url.
  615|       |
  616|       |            // Mapping logic from characters to [0-63]
  617|    453|            auto key = [](char c) -> unsigned char {
  618|    453|                if ((c >= 'A') && (c <= 'Z')) return c - 'A';
  619|    453|                if ((c >= 'a') && (c <= 'z')) return c - 'a' + 26;
  620|    453|                if ((c >= '0') && (c <= '9')) return c - '0' + 52;
  621|    453|                if ((c == '+') || (c == '-')) return 62;
  622|    453|                if ((c == '/') || (c == '_')) return 63;
  623|    453|                return 0;
  624|    453|            };
  625|       |
  626|       |            // Not padded
  627|    453|            if (size % 4 == 2)             // missing last 2 characters
  ------------------
  |  Branch (627:17): [True: 0, False: 453]
  ------------------
  628|      0|                size = (size / 4 * 3) + 1; // Not subtracting extra characters because they're truncated in int division
  629|    453|            else if (size % 4 == 3)        // missing last character
  ------------------
  |  Branch (629:22): [True: 0, False: 453]
  ------------------
  630|      0|                size = (size / 4 * 3) + 2; // Not subtracting extra characters because they're truncated in int division
  631|       |
  632|       |            // Padded
  633|    453|            else if (size >= 2 && data[size - 2] == '=') // padded with '=='
  ------------------
  |  Branch (633:22): [True: 438, False: 15]
  |  Branch (633:35): [True: 117, False: 321]
  ------------------
  634|    117|                size = (size / 4 * 3) - 2;               // == padding means the last block only has 1 character instead of 3, hence the '-2'
  635|    336|            else if (size >= 1 && data[size - 1] == '=') // padded with '='
  ------------------
  |  Branch (635:22): [True: 321, False: 15]
  |  Branch (635:35): [True: 125, False: 196]
  ------------------
  636|    125|                size = (size / 4 * 3) - 1;               // = padding means the last block only has 2 character instead of 3, hence the '-1'
  637|       |
  638|       |            // Padding not needed
  639|    211|            else
  640|    211|                size = size / 4 * 3;
  641|       |
  642|    453|            std::string ret;
  643|    453|            ret.resize(size);
  644|    453|            auto it = ret.begin();
  645|       |
  646|       |            // These will be used to decode 1 character at a time
  647|    453|            unsigned char odd;  // char1 and char3
  648|    453|            unsigned char even; // char2 and char4
  649|       |
  650|       |            // Take 4 character blocks to turn into 3
  651|  12.2M|            while (size >= 3)
  ------------------
  |  Branch (651:20): [True: 12.2M, False: 453]
  ------------------
  652|  12.2M|            {
  653|       |                // dec_char1 = (char1 shifted 2 bits to the left) OR ((char2 AND 00110000) shifted 4 bits to the right))
  654|  12.2M|                odd = key(*data++);
  655|  12.2M|                even = key(*data++);
  656|  12.2M|                *it++ = (odd << 2) | ((even & 0x30) >> 4);
  657|       |                // dec_char2 = ((char2 AND 00001111) shifted 4 bits left) OR ((char3 AND 00111100) shifted 2 bits right))
  658|  12.2M|                odd = key(*data++);
  659|  12.2M|                *it++ = ((even & 0x0F) << 4) | ((odd & 0x3C) >> 2);
  660|       |                // dec_char3 = ((char3 AND 00000011) shifted 6 bits left) OR (char4)
  661|  12.2M|                even = key(*data++);
  662|  12.2M|                *it++ = ((odd & 0x03) << 6) | (even);
  663|       |
  664|  12.2M|                size -= 3;
  665|  12.2M|            }
  666|    453|            if (size == 2)
  ------------------
  |  Branch (666:17): [True: 125, False: 328]
  ------------------
  667|    125|            {
  668|       |                // d_char1 = (char1 shifted 2 bits to the left) OR ((char2 AND 00110000) shifted 4 bits to the right))
  669|    125|                odd = key(*data++);
  670|    125|                even = key(*data++);
  671|    125|                *it++ = (odd << 2) | ((even & 0x30) >> 4);
  672|       |                // d_char2 = ((char2 AND 00001111) shifted 4 bits left) OR ((char3 AND 00111100) shifted 2 bits right))
  673|    125|                odd = key(*data++);
  674|    125|                *it++ = ((even & 0x0F) << 4) | ((odd & 0x3C) >> 2);
  675|    125|            }
  676|    328|            else if (size == 1)
  ------------------
  |  Branch (676:22): [True: 117, False: 211]
  ------------------
  677|    117|            {
  678|       |                // d_char1 = (char1 shifted 2 bits to the left) OR ((char2 AND 00110000) shifted 4 bits to the right))
  679|    117|                odd = key(*data++);
  680|    117|                even = key(*data++);
  681|    117|                *it++ = (odd << 2) | ((even & 0x30) >> 4);
  682|    117|            }
  683|    453|            return ret;
  684|    453|        }
b64_fuzzer.cpp:_ZZN4crow7utilityL12base64decodeEPKcmENKUlcE_clEc:
  617|  48.9M|            auto key = [](char c) -> unsigned char {
  618|  48.9M|                if ((c >= 'A') && (c <= 'Z')) return c - 'A';
  ------------------
  |  Branch (618:21): [True: 45.7M, False: 3.23M]
  |  Branch (618:35): [True: 43.7M, False: 2.00M]
  ------------------
  619|  5.23M|                if ((c >= 'a') && (c <= 'z')) return c - 'a' + 26;
  ------------------
  |  Branch (619:21): [True: 2.00M, False: 3.23M]
  |  Branch (619:35): [True: 2.00M, False: 0]
  ------------------
  620|  3.23M|                if ((c >= '0') && (c <= '9')) return c - '0' + 52;
  ------------------
  |  Branch (620:21): [True: 998k, False: 2.23M]
  |  Branch (620:35): [True: 998k, False: 0]
  ------------------
  621|  2.23M|                if ((c == '+') || (c == '-')) return 62;
  ------------------
  |  Branch (621:21): [True: 23.5k, False: 2.20M]
  |  Branch (621:35): [True: 0, False: 2.20M]
  ------------------
  622|  2.20M|                if ((c == '/') || (c == '_')) return 63;
  ------------------
  |  Branch (622:21): [True: 2.20M, False: 0]
  |  Branch (622:35): [True: 0, False: 0]
  ------------------
  623|      0|                return 0;
  624|  2.20M|            };

LLVMFuzzerTestOneInput:
   15|    453|{
   16|    453|    FuzzedDataProvider fdp{data, size};
   17|       |
   18|    453|    std::string plaintext = fdp.ConsumeRandomLengthString();
   19|    453|    std::string encoded = crow::utility::base64encode(plaintext, plaintext.size());
   20|    453|    std::string decoded = crow::utility::base64decode(encoded, encoded.size());
   21|       |
   22|    453|    if (plaintext != decoded)
  ------------------
  |  Branch (22:9): [True: 0, False: 453]
  ------------------
   23|      0|    {
   24|      0|        throw FuzzException();
   25|      0|    }
   26|    453|    return 0;
   27|    453|}

