b64_fuzzer.cpp:_ZN4crow7utilityL12base64encodeENSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEmPKc:
  608|    393|        {
  609|    393|            return base64encode((const unsigned char*)data.c_str(), size, key);
  610|    393|        }
b64_fuzzer.cpp:_ZN4crow7utilityL12base64encodeEPKhmPKc:
  572|    393|        {
  573|    393|            std::string ret;
  574|    393|            ret.resize((size + 2) / 3 * 4);
  575|    393|            auto it = ret.begin();
  576|  7.38M|            while (size >= 3)
  ------------------
  |  Branch (576:20): [True: 7.38M, False: 393]
  ------------------
  577|  7.38M|            {
  578|  7.38M|                *it++ = key[(static_cast<unsigned char>(*data) & 0xFC) >> 2];
  579|  7.38M|                unsigned char h = (static_cast<unsigned char>(*data++) & 0x03) << 4;
  580|  7.38M|                *it++ = key[h | ((static_cast<unsigned char>(*data) & 0xF0) >> 4)];
  581|  7.38M|                h = (static_cast<unsigned char>(*data++) & 0x0F) << 2;
  582|  7.38M|                *it++ = key[h | ((static_cast<unsigned char>(*data) & 0xC0) >> 6)];
  583|  7.38M|                *it++ = key[static_cast<unsigned char>(*data++) & 0x3F];
  584|       |
  585|  7.38M|                size -= 3;
  586|  7.38M|            }
  587|    393|            if (size == 1)
  ------------------
  |  Branch (587:17): [True: 100, False: 293]
  ------------------
  588|    100|            {
  589|    100|                *it++ = key[(static_cast<unsigned char>(*data) & 0xFC) >> 2];
  590|    100|                unsigned char h = (static_cast<unsigned char>(*data++) & 0x03) << 4;
  591|    100|                *it++ = key[h];
  592|    100|                *it++ = '=';
  593|    100|                *it++ = '=';
  594|    100|            }
  595|    293|            else if (size == 2)
  ------------------
  |  Branch (595:22): [True: 103, False: 190]
  ------------------
  596|    103|            {
  597|    103|                *it++ = key[(static_cast<unsigned char>(*data) & 0xFC) >> 2];
  598|    103|                unsigned char h = (static_cast<unsigned char>(*data++) & 0x03) << 4;
  599|    103|                *it++ = key[h | ((static_cast<unsigned char>(*data) & 0xF0) >> 4)];
  600|    103|                h = (static_cast<unsigned char>(*data++) & 0x0F) << 2;
  601|    103|                *it++ = key[h];
  602|    103|                *it++ = '=';
  603|    103|            }
  604|    393|            return ret;
  605|    393|        }
b64_fuzzer.cpp:_ZN4crow7utilityL12base64decodeERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEm:
  698|    393|        {
  699|    393|            return base64decode(data.data(), size);
  700|    393|        }
b64_fuzzer.cpp:_ZN4crow7utilityL12base64decodeEPKcm:
  623|    393|        {
  624|       |            // We accept both regular and url encoding here, as there does not seem to be any downside to that.
  625|       |            // If we want to distinguish that we should use +/ for non-url and -_ for url.
  626|       |
  627|       |            // Mapping logic from characters to [0-63]
  628|    393|            auto key = [](char c) -> unsigned char {
  629|    393|                if ((c >= 'A') && (c <= 'Z')) return c - 'A';
  630|    393|                if ((c >= 'a') && (c <= 'z')) return c - 'a' + 26;
  631|    393|                if ((c >= '0') && (c <= '9')) return c - '0' + 52;
  632|    393|                if ((c == '+') || (c == '-')) return 62;
  633|    393|                if ((c == '/') || (c == '_')) return 63;
  634|    393|                return 0;
  635|    393|            };
  636|       |
  637|       |            // Not padded
  638|    393|            if (size % 4 == 2)             // missing last 2 characters
  ------------------
  |  Branch (638:17): [True: 0, False: 393]
  ------------------
  639|      0|                size = (size / 4 * 3) + 1; // Not subtracting extra characters because they're truncated in int division
  640|    393|            else if (size % 4 == 3)        // missing last character
  ------------------
  |  Branch (640:22): [True: 0, False: 393]
  ------------------
  641|      0|                size = (size / 4 * 3) + 2; // Not subtracting extra characters because they're truncated in int division
  642|       |
  643|       |            // Padded
  644|    393|            else if (size >= 2 && data[size - 2] == '=') // padded with '=='
  ------------------
  |  Branch (644:22): [True: 377, False: 16]
  |  Branch (644:35): [True: 100, False: 277]
  ------------------
  645|    100|                size = (size / 4 * 3) - 2;  // == padding means the last block only has 1 character instead of 3, hence the '-2'
  646|    293|            else if (size >= 1 && data[size - 1] == '=') // padded with '='
  ------------------
  |  Branch (646:22): [True: 277, False: 16]
  |  Branch (646:35): [True: 103, False: 174]
  ------------------
  647|    103|                size = (size / 4 * 3) - 1;  // = padding means the last block only has 2 character instead of 3, hence the '-1'
  648|       |
  649|       |            // Padding not needed
  650|    190|            else
  651|    190|                size = size / 4 * 3;
  652|       |
  653|    393|            std::string ret;
  654|    393|            ret.resize(size);
  655|    393|            auto it = ret.begin();
  656|       |
  657|       |            // These will be used to decode 1 character at a time
  658|    393|            unsigned char odd;  // char1 and char3
  659|    393|            unsigned char even; // char2 and char4
  660|       |
  661|       |            // Take 4 character blocks to turn into 3
  662|  7.38M|            while (size >= 3)
  ------------------
  |  Branch (662:20): [True: 7.38M, False: 393]
  ------------------
  663|  7.38M|            {
  664|       |                // dec_char1 = (char1 shifted 2 bits to the left) OR ((char2 AND 00110000) shifted 4 bits to the right))
  665|  7.38M|                odd = key(*data++);
  666|  7.38M|                even = key(*data++);
  667|  7.38M|                *it++ = (odd << 2) | ((even & 0x30) >> 4);
  668|       |                // dec_char2 = ((char2 AND 00001111) shifted 4 bits left) OR ((char3 AND 00111100) shifted 2 bits right))
  669|  7.38M|                odd = key(*data++);
  670|  7.38M|                *it++ = ((even & 0x0F) << 4) | ((odd & 0x3C) >> 2);
  671|       |                // dec_char3 = ((char3 AND 00000011) shifted 6 bits left) OR (char4)
  672|  7.38M|                even = key(*data++);
  673|  7.38M|                *it++ = ((odd & 0x03) << 6) | (even);
  674|       |
  675|  7.38M|                size -= 3;
  676|  7.38M|            }
  677|    393|            if (size == 2)
  ------------------
  |  Branch (677:17): [True: 103, False: 290]
  ------------------
  678|    103|            {
  679|       |                // d_char1 = (char1 shifted 2 bits to the left) OR ((char2 AND 00110000) shifted 4 bits to the right))
  680|    103|                odd = key(*data++);
  681|    103|                even = key(*data++);
  682|    103|                *it++ = (odd << 2) | ((even & 0x30) >> 4);
  683|       |                // d_char2 = ((char2 AND 00001111) shifted 4 bits left) OR ((char3 AND 00111100) shifted 2 bits right))
  684|    103|                odd = key(*data++);
  685|    103|                *it++ = ((even & 0x0F) << 4) | ((odd & 0x3C) >> 2);
  686|    103|            }
  687|    290|            else if (size == 1)
  ------------------
  |  Branch (687:22): [True: 100, False: 190]
  ------------------
  688|    100|            {
  689|       |                // d_char1 = (char1 shifted 2 bits to the left) OR ((char2 AND 00110000) shifted 4 bits to the right))
  690|    100|                odd = key(*data++);
  691|    100|                even = key(*data++);
  692|    100|                *it++ = (odd << 2) | ((even & 0x30) >> 4);
  693|    100|            }
  694|    393|            return ret;
  695|    393|        }
b64_fuzzer.cpp:_ZZN4crow7utilityL12base64decodeEPKcmENKUlcE_clEc:
  628|  29.5M|            auto key = [](char c) -> unsigned char {
  629|  29.5M|                if ((c >= 'A') && (c <= 'Z')) return c - 'A';
  ------------------
  |  Branch (629:21): [True: 22.0M, False: 7.46M]
  |  Branch (629:35): [True: 20.7M, False: 1.35M]
  ------------------
  630|  8.81M|                if ((c >= 'a') && (c <= 'z')) return c - 'a' + 26;
  ------------------
  |  Branch (630:21): [True: 1.35M, False: 7.46M]
  |  Branch (630:35): [True: 1.35M, False: 0]
  ------------------
  631|  7.46M|                if ((c >= '0') && (c <= '9')) return c - '0' + 52;
  ------------------
  |  Branch (631:21): [True: 2.19M, False: 5.26M]
  |  Branch (631:35): [True: 2.19M, False: 0]
  ------------------
  632|  5.26M|                if ((c == '+') || (c == '-')) return 62;
  ------------------
  |  Branch (632:21): [True: 28.4k, False: 5.23M]
  |  Branch (632:35): [True: 0, False: 5.23M]
  ------------------
  633|  5.23M|                if ((c == '/') || (c == '_')) return 63;
  ------------------
  |  Branch (633:21): [True: 5.23M, False: 0]
  |  Branch (633:35): [True: 0, False: 0]
  ------------------
  634|      0|                return 0;
  635|  5.23M|            };

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

