| 12033 | } |
| 12034 | |
| 12035 | bool url::parse_ipv4(std::string_view input) { |
| 12036 | ada_log("parse_ipv4 ", input, " [", input.size(), " bytes]"); |
| 12037 | if (input.back() == '.') { |
| 12038 | input.remove_suffix(1); |
| 12039 | } |
| 12040 | size_t digit_count{0}; |
| 12041 | int pure_decimal_count = 0; // entries that are decimal |
| 12042 | std::string_view original_input = |
| 12043 | input; // we might use this if pure_decimal_count == 4. |
| 12044 | uint64_t ipv4{0}; |
| 12045 | // we could unroll for better performance? |
| 12046 | for (; (digit_count < 4) && !(input.empty()); digit_count++) { |
| 12047 | uint32_t |
| 12048 | segment_result{}; // If any number exceeds 32 bits, we have an error. |
| 12049 | bool is_hex = checkers::has_hex_prefix(input); |
| 12050 | if (is_hex && ((input.length() == 2) || |
| 12051 | ((input.length() > 2) && (input[2] == '.')))) { |
| 12052 | // special case |
| 12053 | segment_result = 0; |
| 12054 | input.remove_prefix(2); |
| 12055 | } else { |
| 12056 | std::from_chars_result r{}; |
| 12057 | if (is_hex) { |
| 12058 | r = std::from_chars(input.data() + 2, input.data() + input.size(), |
| 12059 | segment_result, 16); |
| 12060 | } else if ((input.length() >= 2) && input[0] == '0' && |
| 12061 | checkers::is_digit(input[1])) { |
| 12062 | r = std::from_chars(input.data() + 1, input.data() + input.size(), |
| 12063 | segment_result, 8); |
| 12064 | } else { |
| 12065 | pure_decimal_count++; |
| 12066 | r = std::from_chars(input.data(), input.data() + input.size(), |
| 12067 | segment_result, 10); |
| 12068 | } |
| 12069 | if (r.ec != std::errc()) { |
| 12070 | return is_valid = false; |
| 12071 | } |
| 12072 | input.remove_prefix(r.ptr - input.data()); |
| 12073 | } |
| 12074 | if (input.empty()) { |
| 12075 | // We have the last value. |
| 12076 | // At this stage, ipv4 contains digit_count*8 bits. |
| 12077 | // So we have 32-digit_count*8 bits left. |
| 12078 | if (segment_result >= (uint64_t(1) << (32 - digit_count * 8))) { |
| 12079 | return is_valid = false; |
| 12080 | } |
| 12081 | ipv4 <<= (32 - digit_count * 8); |
| 12082 | ipv4 |= segment_result; |
| 12083 | goto final; |
| 12084 | } else { |
| 12085 | // There is more, so that the value must no be larger than 255 |
| 12086 | // and we must have a '.'. |
| 12087 | if ((segment_result > 255) || (input[0] != '.')) { |
| 12088 | return is_valid = false; |
| 12089 | } |
| 12090 | ipv4 <<= 8; |
| 12091 | ipv4 |= segment_result; |
| 12092 | input.remove_prefix(1); // remove '.' |