229 | 2.28k | } Unexecuted instantiation: simdutf.cpp:simdutf::full_result simdutf::haswell::(anonymous namespace)::base64::compress_decode_base64<false, true, true, char>(char*, char const*, unsigned long, simdutf::base64_options, simdutf::last_chunk_handling_options) Unexecuted instantiation: simdutf.cpp:simdutf::full_result simdutf::haswell::(anonymous namespace)::base64::compress_decode_base64<false, false, true, char>(char*, char const*, unsigned long, simdutf::base64_options, simdutf::last_chunk_handling_options) Unexecuted instantiation: simdutf.cpp:simdutf::full_result simdutf::haswell::(anonymous namespace)::base64::compress_decode_base64<true, true, false, char>(char*, char const*, unsigned long, simdutf::base64_options, simdutf::last_chunk_handling_options) simdutf.cpp:simdutf::full_result simdutf::haswell::(anonymous namespace)::base64::compress_decode_base64<true, false, false, char>(char*, char const*, unsigned long, simdutf::base64_options, simdutf::last_chunk_handling_options) Line | Count | Source | 45 | 2.43k | last_chunk_handling_options last_chunk_options) { | 46 | 2.43k | const uint8_t *to_base64 = | 47 | 2.43k | default_or_url ? tables::base64::to_base64_default_or_url_value | 48 | 2.43k | : (base64_url ? tables::base64::to_base64_url_value | 49 | 2.43k | : tables::base64::to_base64_value); | 50 | 2.43k | auto ri = simdutf::scalar::base64::find_end(src, srclen, options); | 51 | 2.43k | size_t equallocation = ri.equallocation; | 52 | 2.43k | size_t equalsigns = ri.equalsigns; | 53 | 2.43k | srclen = ri.srclen; | 54 | 2.43k | size_t full_input_length = ri.full_input_length; | 55 | 2.43k | if (srclen == 0) { | 56 | 119 | if (!ignore_garbage && equalsigns > 0) { | 57 | 18 | return {INVALID_BASE64_CHARACTER, equallocation, 0, true}; | 58 | 18 | } | 59 | 101 | return {SUCCESS, full_input_length, 0}; | 60 | 119 | } | 61 | 2.31k | char *end_of_safe_64byte_zone = | 62 | 2.31k | dst == nullptr | 63 | 2.31k | ? nullptr | 64 | 2.31k | : ((srclen + 3) / 4 * 3 >= 63 ? dst + (srclen + 3) / 4 * 3 - 63 | 65 | 2.26k | : dst); | 66 | | | 67 | 2.31k | const chartype *const srcinit = src; | 68 | 2.31k | const char *const dstinit = dst; | 69 | 2.31k | const chartype *const srcend = src + srclen; | 70 | | | 71 | 2.31k | constexpr size_t block_size = 6; | 72 | 2.31k | static_assert(block_size >= 2, "block_size must be at least two"); | 73 | 2.31k | char buffer[block_size * 64]; | 74 | 2.31k | char *bufferptr = buffer; | 75 | 2.31k | if (srclen >= 64) { | 76 | 1.79k | const chartype *const srcend64 = src + srclen - 64; | 77 | 724k | while (src <= srcend64) { | 78 | 722k | block64 b(src); | 79 | 722k | src += 64; | 80 | 722k | uint64_t error = 0; | 81 | 722k | const uint64_t badcharmask = | 82 | 722k | b.to_base64_mask<base64_url, ignore_garbage, default_or_url>(&error); | 83 | 722k | if (!ignore_garbage && error) { | 84 | 456 | src -= 64; | 85 | 456 | const size_t error_offset = trailing_zeroes(error); | 86 | 456 | return {error_code::INVALID_BASE64_CHARACTER, | 87 | 456 | size_t(src - srcinit + error_offset), size_t(dst - dstinit)}; | 88 | 456 | } | 89 | 722k | if (badcharmask != 0) { | 90 | 58.1k | bufferptr += b.compress_block(badcharmask, bufferptr); | 91 | 664k | } else if (bufferptr != buffer) { | 92 | 35.6k | b.copy_block(bufferptr); | 93 | 35.6k | bufferptr += 64; | 94 | 628k | } else { | 95 | 628k | if (dst >= end_of_safe_64byte_zone) { | 96 | 283 | b.base64_decode_block_safe(dst); | 97 | 628k | } else { | 98 | 628k | b.base64_decode_block(dst); | 99 | 628k | } | 100 | 628k | dst += 48; | 101 | 628k | } | 102 | 722k | if (bufferptr >= (block_size - 1) * 64 + buffer) { | 103 | 82.2k | for (size_t i = 0; i < (block_size - 2); i++) { | 104 | 65.8k | base64_decode_block(dst, buffer + i * 64); | 105 | 65.8k | dst += 48; | 106 | 65.8k | } | 107 | 16.4k | if (dst >= end_of_safe_64byte_zone) { | 108 | 0 | base64_decode_block_safe(dst, buffer + (block_size - 2) * 64); | 109 | 16.4k | } else { | 110 | 16.4k | base64_decode_block(dst, buffer + (block_size - 2) * 64); | 111 | 16.4k | } | 112 | 16.4k | dst += 48; | 113 | 16.4k | std::memcpy(buffer, buffer + (block_size - 1) * 64, | 114 | 16.4k | 64); // 64 might be too much | 115 | 16.4k | bufferptr -= (block_size - 1) * 64; | 116 | 16.4k | } | 117 | 722k | } | 118 | 1.79k | } | 119 | | | 120 | 1.86k | char *buffer_start = buffer; | 121 | | // Optimization note: if this is almost full, then it is worth our | 122 | | // time, otherwise, we should just decode directly. | 123 | 1.86k | int last_block = (int)((bufferptr - buffer_start) % 64); | 124 | 1.86k | if (last_block != 0 && srcend - src + last_block >= 64) { | 125 | | | 126 | 1.69k | while ((bufferptr - buffer_start) % 64 != 0 && src < srcend) { | 127 | 1.56k | uint8_t val = to_base64[uint8_t(*src)]; | 128 | 1.56k | *bufferptr = char(val); | 129 | 1.56k | if (!ignore_garbage && | 130 | 1.56k | (!scalar::base64::is_eight_byte(*src) || val > 64)) { | 131 | 7 | return {error_code::INVALID_BASE64_CHARACTER, size_t(src - srcinit), | 132 | 7 | size_t(dst - dstinit)}; | 133 | 7 | } | 134 | 1.56k | bufferptr += (val <= 63); | 135 | 1.56k | src++; | 136 | 1.56k | } | 137 | 131 | } | 138 | | | 139 | 2.54k | for (; buffer_start + 64 <= bufferptr; buffer_start += 64) { | 140 | 691 | if (dst >= end_of_safe_64byte_zone) { | 141 | 57 | base64_decode_block_safe(dst, buffer_start); | 142 | 634 | } else { | 143 | 634 | base64_decode_block(dst, buffer_start); | 144 | 634 | } | 145 | 691 | dst += 48; | 146 | 691 | } | 147 | 1.85k | if ((bufferptr - buffer_start) % 64 != 0) { | 148 | 6.59k | while (buffer_start + 4 < bufferptr) { | 149 | 5.79k | uint32_t triple = ((uint32_t(uint8_t(buffer_start[0])) << 3 * 6) + | 150 | 5.79k | (uint32_t(uint8_t(buffer_start[1])) << 2 * 6) + | 151 | 5.79k | (uint32_t(uint8_t(buffer_start[2])) << 1 * 6) + | 152 | 5.79k | (uint32_t(uint8_t(buffer_start[3])) << 0 * 6)) | 153 | 5.79k | << 8; | 154 | 5.79k | #if !SIMDUTF_IS_BIG_ENDIAN | 155 | 5.79k | triple = scalar::u32_swap_bytes(triple); | 156 | 5.79k | #endif | 157 | 5.79k | std::memcpy(dst, &triple, 3); | 158 | | | 159 | 5.79k | dst += 3; | 160 | 5.79k | buffer_start += 4; | 161 | 5.79k | } | 162 | 797 | if (buffer_start + 4 <= bufferptr) { | 163 | 207 | uint32_t triple = ((uint32_t(uint8_t(buffer_start[0])) << 3 * 6) + | 164 | 207 | (uint32_t(uint8_t(buffer_start[1])) << 2 * 6) + | 165 | 207 | (uint32_t(uint8_t(buffer_start[2])) << 1 * 6) + | 166 | 207 | (uint32_t(uint8_t(buffer_start[3])) << 0 * 6)) | 167 | 207 | << 8; | 168 | 207 | #if !SIMDUTF_IS_BIG_ENDIAN | 169 | 207 | triple = scalar::u32_swap_bytes(triple); | 170 | 207 | #endif | 171 | 207 | std::memcpy(dst, &triple, 3); | 172 | | | 173 | 207 | dst += 3; | 174 | 207 | buffer_start += 4; | 175 | 207 | } | 176 | | // we may have 1, 2 or 3 bytes left and we need to decode them so let us | 177 | | // backtrack | 178 | 797 | int leftover = int(bufferptr - buffer_start); | 179 | 1.98k | while (leftover > 0) { | 180 | 1.18k | if (!ignore_garbage) { | 181 | 55.5k | while (to_base64[uint8_t(*(src - 1))] == 64) { | 182 | 54.3k | src--; | 183 | 54.3k | } | 184 | 1.18k | } else { | 185 | 0 | while (to_base64[uint8_t(*(src - 1))] >= 64) { | 186 | 0 | src--; | 187 | 0 | } | 188 | 0 | } | 189 | 1.18k | src--; | 190 | 1.18k | leftover--; | 191 | 1.18k | } | 192 | 797 | } | 193 | 1.85k | if (src < srcend + equalsigns) { | 194 | 1.60k | full_result r = scalar::base64::base64_tail_decode( | 195 | 1.60k | dst, src, srcend - src, equalsigns, options, last_chunk_options); | 196 | 1.60k | r = scalar::base64::patch_tail_result( | 197 | 1.60k | r, size_t(src - srcinit), size_t(dst - dstinit), equallocation, | 198 | 1.60k | full_input_length, last_chunk_options); | 199 | | // When is_partial(last_chunk_options) is true, we must either end with | 200 | | // the end of the stream (beyond whitespace) or right after a non-ignorable | 201 | | // character or at the very beginning of the stream. | 202 | | // See https://tc39.es/proposal-arraybuffer-base64/spec/#sec-frombase64 | 203 | 1.60k | if (is_partial(last_chunk_options) && r.error == error_code::SUCCESS && | 204 | 486 | r.input_count < full_input_length) { | 205 | | // First check if we can extend the input to the end of the stream | 206 | 1.35k | while (r.input_count < full_input_length && | 207 | 1.34k | base64_ignorable(*(srcinit + r.input_count), options)) { | 208 | 937 | r.input_count++; | 209 | 937 | } | 210 | | // If we are still not at the end of the stream, then we must backtrack | 211 | | // to the last non-ignorable character. | 212 | 422 | if (r.input_count < full_input_length) { | 213 | 68.9k | while (r.input_count > 0 && | 214 | 68.7k | base64_ignorable(*(srcinit + r.input_count - 1), options)) { | 215 | 68.4k | r.input_count--; | 216 | 68.4k | } | 217 | 407 | } | 218 | 422 | } | 219 | 1.60k | return r; | 220 | 1.60k | } | 221 | 248 | if (!ignore_garbage && equalsigns > 0) { | 222 | 0 | if ((size_t(dst - dstinit) % 3 == 0) || | 223 | 0 | ((size_t(dst - dstinit) % 3) + 1 + equalsigns != 4)) { | 224 | 0 | return {INVALID_BASE64_CHARACTER, equallocation, size_t(dst - dstinit), | 225 | 0 | true}; | 226 | 0 | } | 227 | 0 | } | 228 | 248 | return {SUCCESS, srclen, size_t(dst - dstinit)}; | 229 | 248 | } |
Unexecuted instantiation: simdutf.cpp:simdutf::full_result simdutf::haswell::(anonymous namespace)::base64::compress_decode_base64<false, true, false, char>(char*, char const*, unsigned long, simdutf::base64_options, simdutf::last_chunk_handling_options) simdutf.cpp:simdutf::full_result simdutf::haswell::(anonymous namespace)::base64::compress_decode_base64<false, false, false, char>(char*, char const*, unsigned long, simdutf::base64_options, simdutf::last_chunk_handling_options) Line | Count | Source | 45 | 64.4k | last_chunk_handling_options last_chunk_options) { | 46 | 64.4k | const uint8_t *to_base64 = | 47 | 64.4k | default_or_url ? tables::base64::to_base64_default_or_url_value | 48 | 64.4k | : (base64_url ? tables::base64::to_base64_url_value | 49 | 64.4k | : tables::base64::to_base64_value); | 50 | 64.4k | auto ri = simdutf::scalar::base64::find_end(src, srclen, options); | 51 | 64.4k | size_t equallocation = ri.equallocation; | 52 | 64.4k | size_t equalsigns = ri.equalsigns; | 53 | 64.4k | srclen = ri.srclen; | 54 | 64.4k | size_t full_input_length = ri.full_input_length; | 55 | 64.4k | if (srclen == 0) { | 56 | 55.6k | if (!ignore_garbage && equalsigns > 0) { | 57 | 36 | return {INVALID_BASE64_CHARACTER, equallocation, 0, true}; | 58 | 36 | } | 59 | 55.6k | return {SUCCESS, full_input_length, 0}; | 60 | 55.6k | } | 61 | 8.84k | char *end_of_safe_64byte_zone = | 62 | 8.84k | dst == nullptr | 63 | 8.84k | ? nullptr | 64 | 8.84k | : ((srclen + 3) / 4 * 3 >= 63 ? dst + (srclen + 3) / 4 * 3 - 63 | 65 | 8.69k | : dst); | 66 | | | 67 | 8.84k | const chartype *const srcinit = src; | 68 | 8.84k | const char *const dstinit = dst; | 69 | 8.84k | const chartype *const srcend = src + srclen; | 70 | | | 71 | 8.84k | constexpr size_t block_size = 6; | 72 | 8.84k | static_assert(block_size >= 2, "block_size must be at least two"); | 73 | 8.84k | char buffer[block_size * 64]; | 74 | 8.84k | char *bufferptr = buffer; | 75 | 8.84k | if (srclen >= 64) { | 76 | 4.96k | const chartype *const srcend64 = src + srclen - 64; | 77 | 901k | while (src <= srcend64) { | 78 | 898k | block64 b(src); | 79 | 898k | src += 64; | 80 | 898k | uint64_t error = 0; | 81 | 898k | const uint64_t badcharmask = | 82 | 898k | b.to_base64_mask<base64_url, ignore_garbage, default_or_url>(&error); | 83 | 898k | if (!ignore_garbage && error) { | 84 | 1.27k | src -= 64; | 85 | 1.27k | const size_t error_offset = trailing_zeroes(error); | 86 | 1.27k | return {error_code::INVALID_BASE64_CHARACTER, | 87 | 1.27k | size_t(src - srcinit + error_offset), size_t(dst - dstinit)}; | 88 | 1.27k | } | 89 | 896k | if (badcharmask != 0) { | 90 | 63.6k | bufferptr += b.compress_block(badcharmask, bufferptr); | 91 | 833k | } else if (bufferptr != buffer) { | 92 | 126k | b.copy_block(bufferptr); | 93 | 126k | bufferptr += 64; | 94 | 706k | } else { | 95 | 706k | if (dst >= end_of_safe_64byte_zone) { | 96 | 1.04k | b.base64_decode_block_safe(dst); | 97 | 705k | } else { | 98 | 705k | b.base64_decode_block(dst); | 99 | 705k | } | 100 | 706k | dst += 48; | 101 | 706k | } | 102 | 896k | if (bufferptr >= (block_size - 1) * 64 + buffer) { | 103 | 177k | for (size_t i = 0; i < (block_size - 2); i++) { | 104 | 141k | base64_decode_block(dst, buffer + i * 64); | 105 | 141k | dst += 48; | 106 | 141k | } | 107 | 35.4k | if (dst >= end_of_safe_64byte_zone) { | 108 | 0 | base64_decode_block_safe(dst, buffer + (block_size - 2) * 64); | 109 | 35.4k | } else { | 110 | 35.4k | base64_decode_block(dst, buffer + (block_size - 2) * 64); | 111 | 35.4k | } | 112 | 35.4k | dst += 48; | 113 | 35.4k | std::memcpy(buffer, buffer + (block_size - 1) * 64, | 114 | 35.4k | 64); // 64 might be too much | 115 | 35.4k | bufferptr -= (block_size - 1) * 64; | 116 | 35.4k | } | 117 | 896k | } | 118 | 4.96k | } | 119 | | | 120 | 7.56k | char *buffer_start = buffer; | 121 | | // Optimization note: if this is almost full, then it is worth our | 122 | | // time, otherwise, we should just decode directly. | 123 | 7.56k | int last_block = (int)((bufferptr - buffer_start) % 64); | 124 | 7.56k | if (last_block != 0 && srcend - src + last_block >= 64) { | 125 | | | 126 | 3.31k | while ((bufferptr - buffer_start) % 64 != 0 && src < srcend) { | 127 | 3.07k | uint8_t val = to_base64[uint8_t(*src)]; | 128 | 3.07k | *bufferptr = char(val); | 129 | 3.07k | if (!ignore_garbage && | 130 | 3.07k | (!scalar::base64::is_eight_byte(*src) || val > 64)) { | 131 | 20 | return {error_code::INVALID_BASE64_CHARACTER, size_t(src - srcinit), | 132 | 20 | size_t(dst - dstinit)}; | 133 | 20 | } | 134 | 3.05k | bufferptr += (val <= 63); | 135 | 3.05k | src++; | 136 | 3.05k | } | 137 | 260 | } | 138 | | | 139 | 8.79k | for (; buffer_start + 64 <= bufferptr; buffer_start += 64) { | 140 | 1.25k | if (dst >= end_of_safe_64byte_zone) { | 141 | 106 | base64_decode_block_safe(dst, buffer_start); | 142 | 1.14k | } else { | 143 | 1.14k | base64_decode_block(dst, buffer_start); | 144 | 1.14k | } | 145 | 1.25k | dst += 48; | 146 | 1.25k | } | 147 | 7.54k | if ((bufferptr - buffer_start) % 64 != 0) { | 148 | 12.2k | while (buffer_start + 4 < bufferptr) { | 149 | 10.8k | uint32_t triple = ((uint32_t(uint8_t(buffer_start[0])) << 3 * 6) + | 150 | 10.8k | (uint32_t(uint8_t(buffer_start[1])) << 2 * 6) + | 151 | 10.8k | (uint32_t(uint8_t(buffer_start[2])) << 1 * 6) + | 152 | 10.8k | (uint32_t(uint8_t(buffer_start[3])) << 0 * 6)) | 153 | 10.8k | << 8; | 154 | 10.8k | #if !SIMDUTF_IS_BIG_ENDIAN | 155 | 10.8k | triple = scalar::u32_swap_bytes(triple); | 156 | 10.8k | #endif | 157 | 10.8k | std::memcpy(dst, &triple, 3); | 158 | | | 159 | 10.8k | dst += 3; | 160 | 10.8k | buffer_start += 4; | 161 | 10.8k | } | 162 | 1.39k | if (buffer_start + 4 <= bufferptr) { | 163 | 358 | uint32_t triple = ((uint32_t(uint8_t(buffer_start[0])) << 3 * 6) + | 164 | 358 | (uint32_t(uint8_t(buffer_start[1])) << 2 * 6) + | 165 | 358 | (uint32_t(uint8_t(buffer_start[2])) << 1 * 6) + | 166 | 358 | (uint32_t(uint8_t(buffer_start[3])) << 0 * 6)) | 167 | 358 | << 8; | 168 | 358 | #if !SIMDUTF_IS_BIG_ENDIAN | 169 | 358 | triple = scalar::u32_swap_bytes(triple); | 170 | 358 | #endif | 171 | 358 | std::memcpy(dst, &triple, 3); | 172 | | | 173 | 358 | dst += 3; | 174 | 358 | buffer_start += 4; | 175 | 358 | } | 176 | | // we may have 1, 2 or 3 bytes left and we need to decode them so let us | 177 | | // backtrack | 178 | 1.39k | int leftover = int(bufferptr - buffer_start); | 179 | 3.49k | while (leftover > 0) { | 180 | 2.10k | if (!ignore_garbage) { | 181 | 123k | while (to_base64[uint8_t(*(src - 1))] == 64) { | 182 | 121k | src--; | 183 | 121k | } | 184 | 2.10k | } else { | 185 | 0 | while (to_base64[uint8_t(*(src - 1))] >= 64) { | 186 | 0 | src--; | 187 | 0 | } | 188 | 0 | } | 189 | 2.10k | src--; | 190 | 2.10k | leftover--; | 191 | 2.10k | } | 192 | 1.39k | } | 193 | 7.54k | if (src < srcend + equalsigns) { | 194 | 6.90k | full_result r = scalar::base64::base64_tail_decode( | 195 | 6.90k | dst, src, srcend - src, equalsigns, options, last_chunk_options); | 196 | 6.90k | r = scalar::base64::patch_tail_result( | 197 | 6.90k | r, size_t(src - srcinit), size_t(dst - dstinit), equallocation, | 198 | 6.90k | full_input_length, last_chunk_options); | 199 | | // When is_partial(last_chunk_options) is true, we must either end with | 200 | | // the end of the stream (beyond whitespace) or right after a non-ignorable | 201 | | // character or at the very beginning of the stream. | 202 | | // See https://tc39.es/proposal-arraybuffer-base64/spec/#sec-frombase64 | 203 | 6.90k | if (is_partial(last_chunk_options) && r.error == error_code::SUCCESS && | 204 | 2.13k | r.input_count < full_input_length) { | 205 | | // First check if we can extend the input to the end of the stream | 206 | 4.61k | while (r.input_count < full_input_length && | 207 | 4.55k | base64_ignorable(*(srcinit + r.input_count), options)) { | 208 | 3.78k | r.input_count++; | 209 | 3.78k | } | 210 | | // If we are still not at the end of the stream, then we must backtrack | 211 | | // to the last non-ignorable character. | 212 | 830 | if (r.input_count < full_input_length) { | 213 | 52.7k | while (r.input_count > 0 && | 214 | 52.5k | base64_ignorable(*(srcinit + r.input_count - 1), options)) { | 215 | 51.9k | r.input_count--; | 216 | 51.9k | } | 217 | 773 | } | 218 | 830 | } | 219 | 6.90k | return r; | 220 | 6.90k | } | 221 | 638 | if (!ignore_garbage && equalsigns > 0) { | 222 | 0 | if ((size_t(dst - dstinit) % 3 == 0) || | 223 | 0 | ((size_t(dst - dstinit) % 3) + 1 + equalsigns != 4)) { | 224 | 0 | return {INVALID_BASE64_CHARACTER, equallocation, size_t(dst - dstinit), | 225 | 0 | true}; | 226 | 0 | } | 227 | 0 | } | 228 | 638 | return {SUCCESS, srclen, size_t(dst - dstinit)}; | 229 | 638 | } |
Unexecuted instantiation: simdutf.cpp:simdutf::full_result simdutf::haswell::(anonymous namespace)::base64::compress_decode_base64<false, true, true, char16_t>(char*, char16_t const*, unsigned long, simdutf::base64_options, simdutf::last_chunk_handling_options) Unexecuted instantiation: simdutf.cpp:simdutf::full_result simdutf::haswell::(anonymous namespace)::base64::compress_decode_base64<false, false, true, char16_t>(char*, char16_t const*, unsigned long, simdutf::base64_options, simdutf::last_chunk_handling_options) Unexecuted instantiation: simdutf.cpp:simdutf::full_result simdutf::haswell::(anonymous namespace)::base64::compress_decode_base64<true, true, false, char16_t>(char*, char16_t const*, unsigned long, simdutf::base64_options, simdutf::last_chunk_handling_options) simdutf.cpp:simdutf::full_result simdutf::haswell::(anonymous namespace)::base64::compress_decode_base64<true, false, false, char16_t>(char*, char16_t const*, unsigned long, simdutf::base64_options, simdutf::last_chunk_handling_options) Line | Count | Source | 45 | 2.04k | last_chunk_handling_options last_chunk_options) { | 46 | 2.04k | const uint8_t *to_base64 = | 47 | 2.04k | default_or_url ? tables::base64::to_base64_default_or_url_value | 48 | 2.04k | : (base64_url ? tables::base64::to_base64_url_value | 49 | 2.04k | : tables::base64::to_base64_value); | 50 | 2.04k | auto ri = simdutf::scalar::base64::find_end(src, srclen, options); | 51 | 2.04k | size_t equallocation = ri.equallocation; | 52 | 2.04k | size_t equalsigns = ri.equalsigns; | 53 | 2.04k | srclen = ri.srclen; | 54 | 2.04k | size_t full_input_length = ri.full_input_length; | 55 | 2.04k | if (srclen == 0) { | 56 | 114 | if (!ignore_garbage && equalsigns > 0) { | 57 | 11 | return {INVALID_BASE64_CHARACTER, equallocation, 0, true}; | 58 | 11 | } | 59 | 103 | return {SUCCESS, full_input_length, 0}; | 60 | 114 | } | 61 | 1.93k | char *end_of_safe_64byte_zone = | 62 | 1.93k | dst == nullptr | 63 | 1.93k | ? nullptr | 64 | 1.93k | : ((srclen + 3) / 4 * 3 >= 63 ? dst + (srclen + 3) / 4 * 3 - 63 | 65 | 1.79k | : dst); | 66 | | | 67 | 1.93k | const chartype *const srcinit = src; | 68 | 1.93k | const char *const dstinit = dst; | 69 | 1.93k | const chartype *const srcend = src + srclen; | 70 | | | 71 | 1.93k | constexpr size_t block_size = 6; | 72 | 1.93k | static_assert(block_size >= 2, "block_size must be at least two"); | 73 | 1.93k | char buffer[block_size * 64]; | 74 | 1.93k | char *bufferptr = buffer; | 75 | 1.93k | if (srclen >= 64) { | 76 | 1.43k | const chartype *const srcend64 = src + srclen - 64; | 77 | 51.1k | while (src <= srcend64) { | 78 | 50.1k | block64 b(src); | 79 | 50.1k | src += 64; | 80 | 50.1k | uint64_t error = 0; | 81 | 50.1k | const uint64_t badcharmask = | 82 | 50.1k | b.to_base64_mask<base64_url, ignore_garbage, default_or_url>(&error); | 83 | 50.1k | if (!ignore_garbage && error) { | 84 | 476 | src -= 64; | 85 | 476 | const size_t error_offset = trailing_zeroes(error); | 86 | 476 | return {error_code::INVALID_BASE64_CHARACTER, | 87 | 476 | size_t(src - srcinit + error_offset), size_t(dst - dstinit)}; | 88 | 476 | } | 89 | 49.6k | if (badcharmask != 0) { | 90 | 41.9k | bufferptr += b.compress_block(badcharmask, bufferptr); | 91 | 41.9k | } else if (bufferptr != buffer) { | 92 | 6.70k | b.copy_block(bufferptr); | 93 | 6.70k | bufferptr += 64; | 94 | 6.70k | } else { | 95 | 1.05k | if (dst >= end_of_safe_64byte_zone) { | 96 | 13 | b.base64_decode_block_safe(dst); | 97 | 1.04k | } else { | 98 | 1.04k | b.base64_decode_block(dst); | 99 | 1.04k | } | 100 | 1.05k | dst += 48; | 101 | 1.05k | } | 102 | 49.6k | if (bufferptr >= (block_size - 1) * 64 + buffer) { | 103 | 27.2k | for (size_t i = 0; i < (block_size - 2); i++) { | 104 | 21.7k | base64_decode_block(dst, buffer + i * 64); | 105 | 21.7k | dst += 48; | 106 | 21.7k | } | 107 | 5.44k | if (dst >= end_of_safe_64byte_zone) { | 108 | 0 | base64_decode_block_safe(dst, buffer + (block_size - 2) * 64); | 109 | 5.44k | } else { | 110 | 5.44k | base64_decode_block(dst, buffer + (block_size - 2) * 64); | 111 | 5.44k | } | 112 | 5.44k | dst += 48; | 113 | 5.44k | std::memcpy(buffer, buffer + (block_size - 1) * 64, | 114 | 5.44k | 64); // 64 might be too much | 115 | 5.44k | bufferptr -= (block_size - 1) * 64; | 116 | 5.44k | } | 117 | 49.6k | } | 118 | 1.43k | } | 119 | | | 120 | 1.45k | char *buffer_start = buffer; | 121 | | // Optimization note: if this is almost full, then it is worth our | 122 | | // time, otherwise, we should just decode directly. | 123 | 1.45k | int last_block = (int)((bufferptr - buffer_start) % 64); | 124 | 1.45k | if (last_block != 0 && srcend - src + last_block >= 64) { | 125 | | | 126 | 1.62k | while ((bufferptr - buffer_start) % 64 != 0 && src < srcend) { | 127 | 1.53k | uint8_t val = to_base64[uint8_t(*src)]; | 128 | 1.53k | *bufferptr = char(val); | 129 | 1.53k | if (!ignore_garbage && | 130 | 1.53k | (!scalar::base64::is_eight_byte(*src) || val > 64)) { | 131 | 67 | return {error_code::INVALID_BASE64_CHARACTER, size_t(src - srcinit), | 132 | 67 | size_t(dst - dstinit)}; | 133 | 67 | } | 134 | 1.46k | bufferptr += (val <= 63); | 135 | 1.46k | src++; | 136 | 1.46k | } | 137 | 162 | } | 138 | | | 139 | 1.91k | for (; buffer_start + 64 <= bufferptr; buffer_start += 64) { | 140 | 525 | if (dst >= end_of_safe_64byte_zone) { | 141 | 38 | base64_decode_block_safe(dst, buffer_start); | 142 | 487 | } else { | 143 | 487 | base64_decode_block(dst, buffer_start); | 144 | 487 | } | 145 | 525 | dst += 48; | 146 | 525 | } | 147 | 1.39k | if ((bufferptr - buffer_start) % 64 != 0) { | 148 | 6.17k | while (buffer_start + 4 < bufferptr) { | 149 | 5.41k | uint32_t triple = ((uint32_t(uint8_t(buffer_start[0])) << 3 * 6) + | 150 | 5.41k | (uint32_t(uint8_t(buffer_start[1])) << 2 * 6) + | 151 | 5.41k | (uint32_t(uint8_t(buffer_start[2])) << 1 * 6) + | 152 | 5.41k | (uint32_t(uint8_t(buffer_start[3])) << 0 * 6)) | 153 | 5.41k | << 8; | 154 | 5.41k | #if !SIMDUTF_IS_BIG_ENDIAN | 155 | 5.41k | triple = scalar::u32_swap_bytes(triple); | 156 | 5.41k | #endif | 157 | 5.41k | std::memcpy(dst, &triple, 3); | 158 | | | 159 | 5.41k | dst += 3; | 160 | 5.41k | buffer_start += 4; | 161 | 5.41k | } | 162 | 762 | if (buffer_start + 4 <= bufferptr) { | 163 | 188 | uint32_t triple = ((uint32_t(uint8_t(buffer_start[0])) << 3 * 6) + | 164 | 188 | (uint32_t(uint8_t(buffer_start[1])) << 2 * 6) + | 165 | 188 | (uint32_t(uint8_t(buffer_start[2])) << 1 * 6) + | 166 | 188 | (uint32_t(uint8_t(buffer_start[3])) << 0 * 6)) | 167 | 188 | << 8; | 168 | 188 | #if !SIMDUTF_IS_BIG_ENDIAN | 169 | 188 | triple = scalar::u32_swap_bytes(triple); | 170 | 188 | #endif | 171 | 188 | std::memcpy(dst, &triple, 3); | 172 | | | 173 | 188 | dst += 3; | 174 | 188 | buffer_start += 4; | 175 | 188 | } | 176 | | // we may have 1, 2 or 3 bytes left and we need to decode them so let us | 177 | | // backtrack | 178 | 762 | int leftover = int(bufferptr - buffer_start); | 179 | 1.90k | while (leftover > 0) { | 180 | 1.14k | if (!ignore_garbage) { | 181 | 55.6k | while (to_base64[uint8_t(*(src - 1))] == 64) { | 182 | 54.4k | src--; | 183 | 54.4k | } | 184 | 1.14k | } else { | 185 | 0 | while (to_base64[uint8_t(*(src - 1))] >= 64) { | 186 | 0 | src--; | 187 | 0 | } | 188 | 0 | } | 189 | 1.14k | src--; | 190 | 1.14k | leftover--; | 191 | 1.14k | } | 192 | 762 | } | 193 | 1.39k | if (src < srcend + equalsigns) { | 194 | 1.19k | full_result r = scalar::base64::base64_tail_decode( | 195 | 1.19k | dst, src, srcend - src, equalsigns, options, last_chunk_options); | 196 | 1.19k | r = scalar::base64::patch_tail_result( | 197 | 1.19k | r, size_t(src - srcinit), size_t(dst - dstinit), equallocation, | 198 | 1.19k | full_input_length, last_chunk_options); | 199 | | // When is_partial(last_chunk_options) is true, we must either end with | 200 | | // the end of the stream (beyond whitespace) or right after a non-ignorable | 201 | | // character or at the very beginning of the stream. | 202 | | // See https://tc39.es/proposal-arraybuffer-base64/spec/#sec-frombase64 | 203 | 1.19k | if (is_partial(last_chunk_options) && r.error == error_code::SUCCESS && | 204 | 572 | r.input_count < full_input_length) { | 205 | | // First check if we can extend the input to the end of the stream | 206 | 31.1k | while (r.input_count < full_input_length && | 207 | 31.1k | base64_ignorable(*(srcinit + r.input_count), options)) { | 208 | 30.6k | r.input_count++; | 209 | 30.6k | } | 210 | | // If we are still not at the end of the stream, then we must backtrack | 211 | | // to the last non-ignorable character. | 212 | 523 | if (r.input_count < full_input_length) { | 213 | 41.9k | while (r.input_count > 0 && | 214 | 41.7k | base64_ignorable(*(srcinit + r.input_count - 1), options)) { | 215 | 41.4k | r.input_count--; | 216 | 41.4k | } | 217 | 508 | } | 218 | 523 | } | 219 | 1.19k | return r; | 220 | 1.19k | } | 221 | 198 | if (!ignore_garbage && equalsigns > 0) { | 222 | 0 | if ((size_t(dst - dstinit) % 3 == 0) || | 223 | 0 | ((size_t(dst - dstinit) % 3) + 1 + equalsigns != 4)) { | 224 | 0 | return {INVALID_BASE64_CHARACTER, equallocation, size_t(dst - dstinit), | 225 | 0 | true}; | 226 | 0 | } | 227 | 0 | } | 228 | 198 | return {SUCCESS, srclen, size_t(dst - dstinit)}; | 229 | 198 | } |
Unexecuted instantiation: simdutf.cpp:simdutf::full_result simdutf::haswell::(anonymous namespace)::base64::compress_decode_base64<false, true, false, char16_t>(char*, char16_t const*, unsigned long, simdutf::base64_options, simdutf::last_chunk_handling_options) simdutf.cpp:simdutf::full_result simdutf::haswell::(anonymous namespace)::base64::compress_decode_base64<false, false, false, char16_t>(char*, char16_t const*, unsigned long, simdutf::base64_options, simdutf::last_chunk_handling_options) Line | Count | Source | 45 | 2.18k | last_chunk_handling_options last_chunk_options) { | 46 | 2.18k | const uint8_t *to_base64 = | 47 | 2.18k | default_or_url ? tables::base64::to_base64_default_or_url_value | 48 | 2.18k | : (base64_url ? tables::base64::to_base64_url_value | 49 | 2.18k | : tables::base64::to_base64_value); | 50 | 2.18k | auto ri = simdutf::scalar::base64::find_end(src, srclen, options); | 51 | 2.18k | size_t equallocation = ri.equallocation; | 52 | 2.18k | size_t equalsigns = ri.equalsigns; | 53 | 2.18k | srclen = ri.srclen; | 54 | 2.18k | size_t full_input_length = ri.full_input_length; | 55 | 2.18k | if (srclen == 0) { | 56 | 181 | if (!ignore_garbage && equalsigns > 0) { | 57 | 19 | return {INVALID_BASE64_CHARACTER, equallocation, 0, true}; | 58 | 19 | } | 59 | 162 | return {SUCCESS, full_input_length, 0}; | 60 | 181 | } | 61 | 1.99k | char *end_of_safe_64byte_zone = | 62 | 1.99k | dst == nullptr | 63 | 1.99k | ? nullptr | 64 | 1.99k | : ((srclen + 3) / 4 * 3 >= 63 ? dst + (srclen + 3) / 4 * 3 - 63 | 65 | 1.85k | : dst); | 66 | | | 67 | 1.99k | const chartype *const srcinit = src; | 68 | 1.99k | const char *const dstinit = dst; | 69 | 1.99k | const chartype *const srcend = src + srclen; | 70 | | | 71 | 1.99k | constexpr size_t block_size = 6; | 72 | 1.99k | static_assert(block_size >= 2, "block_size must be at least two"); | 73 | 1.99k | char buffer[block_size * 64]; | 74 | 1.99k | char *bufferptr = buffer; | 75 | 1.99k | if (srclen >= 64) { | 76 | 1.46k | const chartype *const srcend64 = src + srclen - 64; | 77 | 97.1k | while (src <= srcend64) { | 78 | 96.2k | block64 b(src); | 79 | 96.2k | src += 64; | 80 | 96.2k | uint64_t error = 0; | 81 | 96.2k | const uint64_t badcharmask = | 82 | 96.2k | b.to_base64_mask<base64_url, ignore_garbage, default_or_url>(&error); | 83 | 96.2k | if (!ignore_garbage && error) { | 84 | 511 | src -= 64; | 85 | 511 | const size_t error_offset = trailing_zeroes(error); | 86 | 511 | return {error_code::INVALID_BASE64_CHARACTER, | 87 | 511 | size_t(src - srcinit + error_offset), size_t(dst - dstinit)}; | 88 | 511 | } | 89 | 95.7k | if (badcharmask != 0) { | 90 | 78.1k | bufferptr += b.compress_block(badcharmask, bufferptr); | 91 | 78.1k | } else if (bufferptr != buffer) { | 92 | 16.7k | b.copy_block(bufferptr); | 93 | 16.7k | bufferptr += 64; | 94 | 16.7k | } else { | 95 | 808 | if (dst >= end_of_safe_64byte_zone) { | 96 | 7 | b.base64_decode_block_safe(dst); | 97 | 801 | } else { | 98 | 801 | b.base64_decode_block(dst); | 99 | 801 | } | 100 | 808 | dst += 48; | 101 | 808 | } | 102 | 95.7k | if (bufferptr >= (block_size - 1) * 64 + buffer) { | 103 | 73.4k | for (size_t i = 0; i < (block_size - 2); i++) { | 104 | 58.7k | base64_decode_block(dst, buffer + i * 64); | 105 | 58.7k | dst += 48; | 106 | 58.7k | } | 107 | 14.6k | if (dst >= end_of_safe_64byte_zone) { | 108 | 0 | base64_decode_block_safe(dst, buffer + (block_size - 2) * 64); | 109 | 14.6k | } else { | 110 | 14.6k | base64_decode_block(dst, buffer + (block_size - 2) * 64); | 111 | 14.6k | } | 112 | 14.6k | dst += 48; | 113 | 14.6k | std::memcpy(buffer, buffer + (block_size - 1) * 64, | 114 | 14.6k | 64); // 64 might be too much | 115 | 14.6k | bufferptr -= (block_size - 1) * 64; | 116 | 14.6k | } | 117 | 95.7k | } | 118 | 1.46k | } | 119 | | | 120 | 1.48k | char *buffer_start = buffer; | 121 | | // Optimization note: if this is almost full, then it is worth our | 122 | | // time, otherwise, we should just decode directly. | 123 | 1.48k | int last_block = (int)((bufferptr - buffer_start) % 64); | 124 | 1.48k | if (last_block != 0 && srcend - src + last_block >= 64) { | 125 | | | 126 | 1.40k | while ((bufferptr - buffer_start) % 64 != 0 && src < srcend) { | 127 | 1.29k | uint8_t val = to_base64[uint8_t(*src)]; | 128 | 1.29k | *bufferptr = char(val); | 129 | 1.29k | if (!ignore_garbage && | 130 | 1.29k | (!scalar::base64::is_eight_byte(*src) || val > 64)) { | 131 | 59 | return {error_code::INVALID_BASE64_CHARACTER, size_t(src - srcinit), | 132 | 59 | size_t(dst - dstinit)}; | 133 | 59 | } | 134 | 1.23k | bufferptr += (val <= 63); | 135 | 1.23k | src++; | 136 | 1.23k | } | 137 | 171 | } | 138 | | | 139 | 2.05k | for (; buffer_start + 64 <= bufferptr; buffer_start += 64) { | 140 | 626 | if (dst >= end_of_safe_64byte_zone) { | 141 | 48 | base64_decode_block_safe(dst, buffer_start); | 142 | 578 | } else { | 143 | 578 | base64_decode_block(dst, buffer_start); | 144 | 578 | } | 145 | 626 | dst += 48; | 146 | 626 | } | 147 | 1.42k | if ((bufferptr - buffer_start) % 64 != 0) { | 148 | 6.45k | while (buffer_start + 4 < bufferptr) { | 149 | 5.68k | uint32_t triple = ((uint32_t(uint8_t(buffer_start[0])) << 3 * 6) + | 150 | 5.68k | (uint32_t(uint8_t(buffer_start[1])) << 2 * 6) + | 151 | 5.68k | (uint32_t(uint8_t(buffer_start[2])) << 1 * 6) + | 152 | 5.68k | (uint32_t(uint8_t(buffer_start[3])) << 0 * 6)) | 153 | 5.68k | << 8; | 154 | 5.68k | #if !SIMDUTF_IS_BIG_ENDIAN | 155 | 5.68k | triple = scalar::u32_swap_bytes(triple); | 156 | 5.68k | #endif | 157 | 5.68k | std::memcpy(dst, &triple, 3); | 158 | | | 159 | 5.68k | dst += 3; | 160 | 5.68k | buffer_start += 4; | 161 | 5.68k | } | 162 | 762 | if (buffer_start + 4 <= bufferptr) { | 163 | 182 | uint32_t triple = ((uint32_t(uint8_t(buffer_start[0])) << 3 * 6) + | 164 | 182 | (uint32_t(uint8_t(buffer_start[1])) << 2 * 6) + | 165 | 182 | (uint32_t(uint8_t(buffer_start[2])) << 1 * 6) + | 166 | 182 | (uint32_t(uint8_t(buffer_start[3])) << 0 * 6)) | 167 | 182 | << 8; | 168 | 182 | #if !SIMDUTF_IS_BIG_ENDIAN | 169 | 182 | triple = scalar::u32_swap_bytes(triple); | 170 | 182 | #endif | 171 | 182 | std::memcpy(dst, &triple, 3); | 172 | | | 173 | 182 | dst += 3; | 174 | 182 | buffer_start += 4; | 175 | 182 | } | 176 | | // we may have 1, 2 or 3 bytes left and we need to decode them so let us | 177 | | // backtrack | 178 | 762 | int leftover = int(bufferptr - buffer_start); | 179 | 1.91k | while (leftover > 0) { | 180 | 1.14k | if (!ignore_garbage) { | 181 | 101k | while (to_base64[uint8_t(*(src - 1))] == 64) { | 182 | 100k | src--; | 183 | 100k | } | 184 | 1.14k | } else { | 185 | 0 | while (to_base64[uint8_t(*(src - 1))] >= 64) { | 186 | 0 | src--; | 187 | 0 | } | 188 | 0 | } | 189 | 1.14k | src--; | 190 | 1.14k | leftover--; | 191 | 1.14k | } | 192 | 762 | } | 193 | 1.42k | if (src < srcend + equalsigns) { | 194 | 1.23k | full_result r = scalar::base64::base64_tail_decode( | 195 | 1.23k | dst, src, srcend - src, equalsigns, options, last_chunk_options); | 196 | 1.23k | r = scalar::base64::patch_tail_result( | 197 | 1.23k | r, size_t(src - srcinit), size_t(dst - dstinit), equallocation, | 198 | 1.23k | full_input_length, last_chunk_options); | 199 | | // When is_partial(last_chunk_options) is true, we must either end with | 200 | | // the end of the stream (beyond whitespace) or right after a non-ignorable | 201 | | // character or at the very beginning of the stream. | 202 | | // See https://tc39.es/proposal-arraybuffer-base64/spec/#sec-frombase64 | 203 | 1.23k | if (is_partial(last_chunk_options) && r.error == error_code::SUCCESS && | 204 | 564 | r.input_count < full_input_length) { | 205 | | // First check if we can extend the input to the end of the stream | 206 | 57.0k | while (r.input_count < full_input_length && | 207 | 57.0k | base64_ignorable(*(srcinit + r.input_count), options)) { | 208 | 56.5k | r.input_count++; | 209 | 56.5k | } | 210 | | // If we are still not at the end of the stream, then we must backtrack | 211 | | // to the last non-ignorable character. | 212 | 501 | if (r.input_count < full_input_length) { | 213 | 20.7k | while (r.input_count > 0 && | 214 | 20.5k | base64_ignorable(*(srcinit + r.input_count - 1), options)) { | 215 | 20.2k | r.input_count--; | 216 | 20.2k | } | 217 | 485 | } | 218 | 501 | } | 219 | 1.23k | return r; | 220 | 1.23k | } | 221 | 198 | if (!ignore_garbage && equalsigns > 0) { | 222 | 0 | if ((size_t(dst - dstinit) % 3 == 0) || | 223 | 0 | ((size_t(dst - dstinit) % 3) + 1 + equalsigns != 4)) { | 224 | 0 | return {INVALID_BASE64_CHARACTER, equallocation, size_t(dst - dstinit), | 225 | 0 | true}; | 226 | 0 | } | 227 | 0 | } | 228 | 198 | return {SUCCESS, srclen, size_t(dst - dstinit)}; | 229 | 198 | } |
Unexecuted instantiation: simdutf.cpp:simdutf::full_result simdutf::westmere::(anonymous namespace)::base64::compress_decode_base64<false, true, true, char>(char*, char const*, unsigned long, simdutf::base64_options, simdutf::last_chunk_handling_options) Unexecuted instantiation: simdutf.cpp:simdutf::full_result simdutf::westmere::(anonymous namespace)::base64::compress_decode_base64<false, false, true, char>(char*, char const*, unsigned long, simdutf::base64_options, simdutf::last_chunk_handling_options) Unexecuted instantiation: simdutf.cpp:simdutf::full_result simdutf::westmere::(anonymous namespace)::base64::compress_decode_base64<true, true, false, char>(char*, char const*, unsigned long, simdutf::base64_options, simdutf::last_chunk_handling_options) simdutf.cpp:simdutf::full_result simdutf::westmere::(anonymous namespace)::base64::compress_decode_base64<true, false, false, char>(char*, char const*, unsigned long, simdutf::base64_options, simdutf::last_chunk_handling_options) Line | Count | Source | 45 | 2.23k | last_chunk_handling_options last_chunk_options) { | 46 | 2.23k | const uint8_t *to_base64 = | 47 | 2.23k | default_or_url ? tables::base64::to_base64_default_or_url_value | 48 | 2.23k | : (base64_url ? tables::base64::to_base64_url_value | 49 | 2.23k | : tables::base64::to_base64_value); | 50 | 2.23k | auto ri = simdutf::scalar::base64::find_end(src, srclen, options); | 51 | 2.23k | size_t equallocation = ri.equallocation; | 52 | 2.23k | size_t equalsigns = ri.equalsigns; | 53 | 2.23k | srclen = ri.srclen; | 54 | 2.23k | size_t full_input_length = ri.full_input_length; | 55 | 2.23k | if (srclen == 0) { | 56 | 42 | if (!ignore_garbage && equalsigns > 0) { | 57 | 15 | return {INVALID_BASE64_CHARACTER, equallocation, 0, true}; | 58 | 15 | } | 59 | 27 | return {SUCCESS, full_input_length, 0}; | 60 | 42 | } | 61 | 2.19k | char *end_of_safe_64byte_zone = | 62 | 2.19k | dst == nullptr | 63 | 2.19k | ? nullptr | 64 | 2.19k | : ((srclen + 3) / 4 * 3 >= 63 ? dst + (srclen + 3) / 4 * 3 - 63 | 65 | 2.13k | : dst); | 66 | | | 67 | 2.19k | const chartype *const srcinit = src; | 68 | 2.19k | const char *const dstinit = dst; | 69 | 2.19k | const chartype *const srcend = src + srclen; | 70 | | | 71 | 2.19k | constexpr size_t block_size = 6; | 72 | 2.19k | static_assert(block_size >= 2, "block_size must be at least two"); | 73 | 2.19k | char buffer[block_size * 64]; | 74 | 2.19k | char *bufferptr = buffer; | 75 | 2.19k | if (srclen >= 64) { | 76 | 1.72k | const chartype *const srcend64 = src + srclen - 64; | 77 | 719k | while (src <= srcend64) { | 78 | 718k | block64 b(src); | 79 | 718k | src += 64; | 80 | 718k | uint64_t error = 0; | 81 | 718k | const uint64_t badcharmask = | 82 | 718k | b.to_base64_mask<base64_url, ignore_garbage, default_or_url>(&error); | 83 | 718k | if (!ignore_garbage && error) { | 84 | 435 | src -= 64; | 85 | 435 | const size_t error_offset = trailing_zeroes(error); | 86 | 435 | return {error_code::INVALID_BASE64_CHARACTER, | 87 | 435 | size_t(src - srcinit + error_offset), size_t(dst - dstinit)}; | 88 | 435 | } | 89 | 718k | if (badcharmask != 0) { | 90 | 54.0k | bufferptr += b.compress_block(badcharmask, bufferptr); | 91 | 663k | } else if (bufferptr != buffer) { | 92 | 35.5k | b.copy_block(bufferptr); | 93 | 35.5k | bufferptr += 64; | 94 | 628k | } else { | 95 | 628k | if (dst >= end_of_safe_64byte_zone) { | 96 | 283 | b.base64_decode_block_safe(dst); | 97 | 628k | } else { | 98 | 628k | b.base64_decode_block(dst); | 99 | 628k | } | 100 | 628k | dst += 48; | 101 | 628k | } | 102 | 718k | if (bufferptr >= (block_size - 1) * 64 + buffer) { | 103 | 81.4k | for (size_t i = 0; i < (block_size - 2); i++) { | 104 | 65.1k | base64_decode_block(dst, buffer + i * 64); | 105 | 65.1k | dst += 48; | 106 | 65.1k | } | 107 | 16.2k | if (dst >= end_of_safe_64byte_zone) { | 108 | 0 | base64_decode_block_safe(dst, buffer + (block_size - 2) * 64); | 109 | 16.2k | } else { | 110 | 16.2k | base64_decode_block(dst, buffer + (block_size - 2) * 64); | 111 | 16.2k | } | 112 | 16.2k | dst += 48; | 113 | 16.2k | std::memcpy(buffer, buffer + (block_size - 1) * 64, | 114 | 16.2k | 64); // 64 might be too much | 115 | 16.2k | bufferptr -= (block_size - 1) * 64; | 116 | 16.2k | } | 117 | 718k | } | 118 | 1.72k | } | 119 | | | 120 | 1.75k | char *buffer_start = buffer; | 121 | | // Optimization note: if this is almost full, then it is worth our | 122 | | // time, otherwise, we should just decode directly. | 123 | 1.75k | int last_block = (int)((bufferptr - buffer_start) % 64); | 124 | 1.75k | if (last_block != 0 && srcend - src + last_block >= 64) { | 125 | | | 126 | 1.31k | while ((bufferptr - buffer_start) % 64 != 0 && src < srcend) { | 127 | 1.20k | uint8_t val = to_base64[uint8_t(*src)]; | 128 | 1.20k | *bufferptr = char(val); | 129 | 1.20k | if (!ignore_garbage && | 130 | 1.20k | (!scalar::base64::is_eight_byte(*src) || val > 64)) { | 131 | 7 | return {error_code::INVALID_BASE64_CHARACTER, size_t(src - srcinit), | 132 | 7 | size_t(dst - dstinit)}; | 133 | 7 | } | 134 | 1.20k | bufferptr += (val <= 63); | 135 | 1.20k | src++; | 136 | 1.20k | } | 137 | 118 | } | 138 | | | 139 | 2.41k | for (; buffer_start + 64 <= bufferptr; buffer_start += 64) { | 140 | 662 | if (dst >= end_of_safe_64byte_zone) { | 141 | 57 | base64_decode_block_safe(dst, buffer_start); | 142 | 605 | } else { | 143 | 605 | base64_decode_block(dst, buffer_start); | 144 | 605 | } | 145 | 662 | dst += 48; | 146 | 662 | } | 147 | 1.74k | if ((bufferptr - buffer_start) % 64 != 0) { | 148 | 6.28k | while (buffer_start + 4 < bufferptr) { | 149 | 5.53k | uint32_t triple = ((uint32_t(uint8_t(buffer_start[0])) << 3 * 6) + | 150 | 5.53k | (uint32_t(uint8_t(buffer_start[1])) << 2 * 6) + | 151 | 5.53k | (uint32_t(uint8_t(buffer_start[2])) << 1 * 6) + | 152 | 5.53k | (uint32_t(uint8_t(buffer_start[3])) << 0 * 6)) | 153 | 5.53k | << 8; | 154 | 5.53k | #if !SIMDUTF_IS_BIG_ENDIAN | 155 | 5.53k | triple = scalar::u32_swap_bytes(triple); | 156 | 5.53k | #endif | 157 | 5.53k | std::memcpy(dst, &triple, 3); | 158 | | | 159 | 5.53k | dst += 3; | 160 | 5.53k | buffer_start += 4; | 161 | 5.53k | } | 162 | 748 | if (buffer_start + 4 <= bufferptr) { | 163 | 197 | uint32_t triple = ((uint32_t(uint8_t(buffer_start[0])) << 3 * 6) + | 164 | 197 | (uint32_t(uint8_t(buffer_start[1])) << 2 * 6) + | 165 | 197 | (uint32_t(uint8_t(buffer_start[2])) << 1 * 6) + | 166 | 197 | (uint32_t(uint8_t(buffer_start[3])) << 0 * 6)) | 167 | 197 | << 8; | 168 | 197 | #if !SIMDUTF_IS_BIG_ENDIAN | 169 | 197 | triple = scalar::u32_swap_bytes(triple); | 170 | 197 | #endif | 171 | 197 | std::memcpy(dst, &triple, 3); | 172 | | | 173 | 197 | dst += 3; | 174 | 197 | buffer_start += 4; | 175 | 197 | } | 176 | | // we may have 1, 2 or 3 bytes left and we need to decode them so let us | 177 | | // backtrack | 178 | 748 | int leftover = int(bufferptr - buffer_start); | 179 | 1.85k | while (leftover > 0) { | 180 | 1.10k | if (!ignore_garbage) { | 181 | 15.2k | while (to_base64[uint8_t(*(src - 1))] == 64) { | 182 | 14.1k | src--; | 183 | 14.1k | } | 184 | 1.10k | } else { | 185 | 0 | while (to_base64[uint8_t(*(src - 1))] >= 64) { | 186 | 0 | src--; | 187 | 0 | } | 188 | 0 | } | 189 | 1.10k | src--; | 190 | 1.10k | leftover--; | 191 | 1.10k | } | 192 | 748 | } | 193 | 1.74k | if (src < srcend + equalsigns) { | 194 | 1.50k | full_result r = scalar::base64::base64_tail_decode( | 195 | 1.50k | dst, src, srcend - src, equalsigns, options, last_chunk_options); | 196 | 1.50k | r = scalar::base64::patch_tail_result( | 197 | 1.50k | r, size_t(src - srcinit), size_t(dst - dstinit), equallocation, | 198 | 1.50k | full_input_length, last_chunk_options); | 199 | | // When is_partial(last_chunk_options) is true, we must either end with | 200 | | // the end of the stream (beyond whitespace) or right after a non-ignorable | 201 | | // character or at the very beginning of the stream. | 202 | | // See https://tc39.es/proposal-arraybuffer-base64/spec/#sec-frombase64 | 203 | 1.50k | if (is_partial(last_chunk_options) && r.error == error_code::SUCCESS && | 204 | 410 | r.input_count < full_input_length) { | 205 | | // First check if we can extend the input to the end of the stream | 206 | 1.06k | while (r.input_count < full_input_length && | 207 | 1.05k | base64_ignorable(*(srcinit + r.input_count), options)) { | 208 | 718 | r.input_count++; | 209 | 718 | } | 210 | | // If we are still not at the end of the stream, then we must backtrack | 211 | | // to the last non-ignorable character. | 212 | 351 | if (r.input_count < full_input_length) { | 213 | 22.2k | while (r.input_count > 0 && | 214 | 22.1k | base64_ignorable(*(srcinit + r.input_count - 1), options)) { | 215 | 21.9k | r.input_count--; | 216 | 21.9k | } | 217 | 340 | } | 218 | 351 | } | 219 | 1.50k | return r; | 220 | 1.50k | } | 221 | 242 | if (!ignore_garbage && equalsigns > 0) { | 222 | 0 | if ((size_t(dst - dstinit) % 3 == 0) || | 223 | 0 | ((size_t(dst - dstinit) % 3) + 1 + equalsigns != 4)) { | 224 | 0 | return {INVALID_BASE64_CHARACTER, equallocation, size_t(dst - dstinit), | 225 | 0 | true}; | 226 | 0 | } | 227 | 0 | } | 228 | 242 | return {SUCCESS, srclen, size_t(dst - dstinit)}; | 229 | 242 | } |
Unexecuted instantiation: simdutf.cpp:simdutf::full_result simdutf::westmere::(anonymous namespace)::base64::compress_decode_base64<false, true, false, char>(char*, char const*, unsigned long, simdutf::base64_options, simdutf::last_chunk_handling_options) simdutf.cpp:simdutf::full_result simdutf::westmere::(anonymous namespace)::base64::compress_decode_base64<false, false, false, char>(char*, char const*, unsigned long, simdutf::base64_options, simdutf::last_chunk_handling_options) Line | Count | Source | 45 | 17.8k | last_chunk_handling_options last_chunk_options) { | 46 | 17.8k | const uint8_t *to_base64 = | 47 | 17.8k | default_or_url ? tables::base64::to_base64_default_or_url_value | 48 | 17.8k | : (base64_url ? tables::base64::to_base64_url_value | 49 | 17.8k | : tables::base64::to_base64_value); | 50 | 17.8k | auto ri = simdutf::scalar::base64::find_end(src, srclen, options); | 51 | 17.8k | size_t equallocation = ri.equallocation; | 52 | 17.8k | size_t equalsigns = ri.equalsigns; | 53 | 17.8k | srclen = ri.srclen; | 54 | 17.8k | size_t full_input_length = ri.full_input_length; | 55 | 17.8k | if (srclen == 0) { | 56 | 14.0k | if (!ignore_garbage && equalsigns > 0) { | 57 | 21 | return {INVALID_BASE64_CHARACTER, equallocation, 0, true}; | 58 | 21 | } | 59 | 14.0k | return {SUCCESS, full_input_length, 0}; | 60 | 14.0k | } | 61 | 3.81k | char *end_of_safe_64byte_zone = | 62 | 3.81k | dst == nullptr | 63 | 3.81k | ? nullptr | 64 | 3.81k | : ((srclen + 3) / 4 * 3 >= 63 ? dst + (srclen + 3) / 4 * 3 - 63 | 65 | 3.69k | : dst); | 66 | | | 67 | 3.81k | const chartype *const srcinit = src; | 68 | 3.81k | const char *const dstinit = dst; | 69 | 3.81k | const chartype *const srcend = src + srclen; | 70 | | | 71 | 3.81k | constexpr size_t block_size = 6; | 72 | 3.81k | static_assert(block_size >= 2, "block_size must be at least two"); | 73 | 3.81k | char buffer[block_size * 64]; | 74 | 3.81k | char *bufferptr = buffer; | 75 | 3.81k | if (srclen >= 64) { | 76 | 2.57k | const chartype *const srcend64 = src + srclen - 64; | 77 | 881k | while (src <= srcend64) { | 78 | 879k | block64 b(src); | 79 | 879k | src += 64; | 80 | 879k | uint64_t error = 0; | 81 | 879k | const uint64_t badcharmask = | 82 | 879k | b.to_base64_mask<base64_url, ignore_garbage, default_or_url>(&error); | 83 | 879k | if (!ignore_garbage && error) { | 84 | 694 | src -= 64; | 85 | 694 | const size_t error_offset = trailing_zeroes(error); | 86 | 694 | return {error_code::INVALID_BASE64_CHARACTER, | 87 | 694 | size_t(src - srcinit + error_offset), size_t(dst - dstinit)}; | 88 | 694 | } | 89 | 878k | if (badcharmask != 0) { | 90 | 55.0k | bufferptr += b.compress_block(badcharmask, bufferptr); | 91 | 823k | } else if (bufferptr != buffer) { | 92 | 126k | b.copy_block(bufferptr); | 93 | 126k | bufferptr += 64; | 94 | 697k | } else { | 95 | 697k | if (dst >= end_of_safe_64byte_zone) { | 96 | 413 | b.base64_decode_block_safe(dst); | 97 | 696k | } else { | 98 | 696k | b.base64_decode_block(dst); | 99 | 696k | } | 100 | 697k | dst += 48; | 101 | 697k | } | 102 | 878k | if (bufferptr >= (block_size - 1) * 64 + buffer) { | 103 | 176k | for (size_t i = 0; i < (block_size - 2); i++) { | 104 | 141k | base64_decode_block(dst, buffer + i * 64); | 105 | 141k | dst += 48; | 106 | 141k | } | 107 | 35.2k | if (dst >= end_of_safe_64byte_zone) { | 108 | 0 | base64_decode_block_safe(dst, buffer + (block_size - 2) * 64); | 109 | 35.2k | } else { | 110 | 35.2k | base64_decode_block(dst, buffer + (block_size - 2) * 64); | 111 | 35.2k | } | 112 | 35.2k | dst += 48; | 113 | 35.2k | std::memcpy(buffer, buffer + (block_size - 1) * 64, | 114 | 35.2k | 64); // 64 might be too much | 115 | 35.2k | bufferptr -= (block_size - 1) * 64; | 116 | 35.2k | } | 117 | 878k | } | 118 | 2.57k | } | 119 | | | 120 | 3.12k | char *buffer_start = buffer; | 121 | | // Optimization note: if this is almost full, then it is worth our | 122 | | // time, otherwise, we should just decode directly. | 123 | 3.12k | int last_block = (int)((bufferptr - buffer_start) % 64); | 124 | 3.12k | if (last_block != 0 && srcend - src + last_block >= 64) { | 125 | | | 126 | 1.74k | while ((bufferptr - buffer_start) % 64 != 0 && src < srcend) { | 127 | 1.58k | uint8_t val = to_base64[uint8_t(*src)]; | 128 | 1.58k | *bufferptr = char(val); | 129 | 1.58k | if (!ignore_garbage && | 130 | 1.58k | (!scalar::base64::is_eight_byte(*src) || val > 64)) { | 131 | 9 | return {error_code::INVALID_BASE64_CHARACTER, size_t(src - srcinit), | 132 | 9 | size_t(dst - dstinit)}; | 133 | 9 | } | 134 | 1.57k | bufferptr += (val <= 63); | 135 | 1.57k | src++; | 136 | 1.57k | } | 137 | 169 | } | 138 | | | 139 | 3.96k | for (; buffer_start + 64 <= bufferptr; buffer_start += 64) { | 140 | 853 | if (dst >= end_of_safe_64byte_zone) { | 141 | 73 | base64_decode_block_safe(dst, buffer_start); | 142 | 780 | } else { | 143 | 780 | base64_decode_block(dst, buffer_start); | 144 | 780 | } | 145 | 853 | dst += 48; | 146 | 853 | } | 147 | 3.11k | if ((bufferptr - buffer_start) % 64 != 0) { | 148 | 8.63k | while (buffer_start + 4 < bufferptr) { | 149 | 7.64k | uint32_t triple = ((uint32_t(uint8_t(buffer_start[0])) << 3 * 6) + | 150 | 7.64k | (uint32_t(uint8_t(buffer_start[1])) << 2 * 6) + | 151 | 7.64k | (uint32_t(uint8_t(buffer_start[2])) << 1 * 6) + | 152 | 7.64k | (uint32_t(uint8_t(buffer_start[3])) << 0 * 6)) | 153 | 7.64k | << 8; | 154 | 7.64k | #if !SIMDUTF_IS_BIG_ENDIAN | 155 | 7.64k | triple = scalar::u32_swap_bytes(triple); | 156 | 7.64k | #endif | 157 | 7.64k | std::memcpy(dst, &triple, 3); | 158 | | | 159 | 7.64k | dst += 3; | 160 | 7.64k | buffer_start += 4; | 161 | 7.64k | } | 162 | 991 | if (buffer_start + 4 <= bufferptr) { | 163 | 264 | uint32_t triple = ((uint32_t(uint8_t(buffer_start[0])) << 3 * 6) + | 164 | 264 | (uint32_t(uint8_t(buffer_start[1])) << 2 * 6) + | 165 | 264 | (uint32_t(uint8_t(buffer_start[2])) << 1 * 6) + | 166 | 264 | (uint32_t(uint8_t(buffer_start[3])) << 0 * 6)) | 167 | 264 | << 8; | 168 | 264 | #if !SIMDUTF_IS_BIG_ENDIAN | 169 | 264 | triple = scalar::u32_swap_bytes(triple); | 170 | 264 | #endif | 171 | 264 | std::memcpy(dst, &triple, 3); | 172 | | | 173 | 264 | dst += 3; | 174 | 264 | buffer_start += 4; | 175 | 264 | } | 176 | | // we may have 1, 2 or 3 bytes left and we need to decode them so let us | 177 | | // backtrack | 178 | 991 | int leftover = int(bufferptr - buffer_start); | 179 | 2.44k | while (leftover > 0) { | 180 | 1.45k | if (!ignore_garbage) { | 181 | 11.4k | while (to_base64[uint8_t(*(src - 1))] == 64) { | 182 | 10.0k | src--; | 183 | 10.0k | } | 184 | 1.45k | } else { | 185 | 0 | while (to_base64[uint8_t(*(src - 1))] >= 64) { | 186 | 0 | src--; | 187 | 0 | } | 188 | 0 | } | 189 | 1.45k | src--; | 190 | 1.45k | leftover--; | 191 | 1.45k | } | 192 | 991 | } | 193 | 3.11k | if (src < srcend + equalsigns) { | 194 | 2.74k | full_result r = scalar::base64::base64_tail_decode( | 195 | 2.74k | dst, src, srcend - src, equalsigns, options, last_chunk_options); | 196 | 2.74k | r = scalar::base64::patch_tail_result( | 197 | 2.74k | r, size_t(src - srcinit), size_t(dst - dstinit), equallocation, | 198 | 2.74k | full_input_length, last_chunk_options); | 199 | | // When is_partial(last_chunk_options) is true, we must either end with | 200 | | // the end of the stream (beyond whitespace) or right after a non-ignorable | 201 | | // character or at the very beginning of the stream. | 202 | | // See https://tc39.es/proposal-arraybuffer-base64/spec/#sec-frombase64 | 203 | 2.74k | if (is_partial(last_chunk_options) && r.error == error_code::SUCCESS && | 204 | 506 | r.input_count < full_input_length) { | 205 | | // First check if we can extend the input to the end of the stream | 206 | 1.35k | while (r.input_count < full_input_length && | 207 | 1.34k | base64_ignorable(*(srcinit + r.input_count), options)) { | 208 | 912 | r.input_count++; | 209 | 912 | } | 210 | | // If we are still not at the end of the stream, then we must backtrack | 211 | | // to the last non-ignorable character. | 212 | 443 | if (r.input_count < full_input_length) { | 213 | 6.58k | while (r.input_count > 0 && | 214 | 6.47k | base64_ignorable(*(srcinit + r.input_count - 1), options)) { | 215 | 6.14k | r.input_count--; | 216 | 6.14k | } | 217 | 433 | } | 218 | 443 | } | 219 | 2.74k | return r; | 220 | 2.74k | } | 221 | 371 | if (!ignore_garbage && equalsigns > 0) { | 222 | 0 | if ((size_t(dst - dstinit) % 3 == 0) || | 223 | 0 | ((size_t(dst - dstinit) % 3) + 1 + equalsigns != 4)) { | 224 | 0 | return {INVALID_BASE64_CHARACTER, equallocation, size_t(dst - dstinit), | 225 | 0 | true}; | 226 | 0 | } | 227 | 0 | } | 228 | 371 | return {SUCCESS, srclen, size_t(dst - dstinit)}; | 229 | 371 | } |
Unexecuted instantiation: simdutf.cpp:simdutf::full_result simdutf::westmere::(anonymous namespace)::base64::compress_decode_base64<false, true, true, char16_t>(char*, char16_t const*, unsigned long, simdutf::base64_options, simdutf::last_chunk_handling_options) Unexecuted instantiation: simdutf.cpp:simdutf::full_result simdutf::westmere::(anonymous namespace)::base64::compress_decode_base64<false, false, true, char16_t>(char*, char16_t const*, unsigned long, simdutf::base64_options, simdutf::last_chunk_handling_options) Unexecuted instantiation: simdutf.cpp:simdutf::full_result simdutf::westmere::(anonymous namespace)::base64::compress_decode_base64<true, true, false, char16_t>(char*, char16_t const*, unsigned long, simdutf::base64_options, simdutf::last_chunk_handling_options) simdutf.cpp:simdutf::full_result simdutf::westmere::(anonymous namespace)::base64::compress_decode_base64<true, false, false, char16_t>(char*, char16_t const*, unsigned long, simdutf::base64_options, simdutf::last_chunk_handling_options) Line | Count | Source | 45 | 1.84k | last_chunk_handling_options last_chunk_options) { | 46 | 1.84k | const uint8_t *to_base64 = | 47 | 1.84k | default_or_url ? tables::base64::to_base64_default_or_url_value | 48 | 1.84k | : (base64_url ? tables::base64::to_base64_url_value | 49 | 1.84k | : tables::base64::to_base64_value); | 50 | 1.84k | auto ri = simdutf::scalar::base64::find_end(src, srclen, options); | 51 | 1.84k | size_t equallocation = ri.equallocation; | 52 | 1.84k | size_t equalsigns = ri.equalsigns; | 53 | 1.84k | srclen = ri.srclen; | 54 | 1.84k | size_t full_input_length = ri.full_input_length; | 55 | 1.84k | if (srclen == 0) { | 56 | 24 | if (!ignore_garbage && equalsigns > 0) { | 57 | 10 | return {INVALID_BASE64_CHARACTER, equallocation, 0, true}; | 58 | 10 | } | 59 | 14 | return {SUCCESS, full_input_length, 0}; | 60 | 24 | } | 61 | 1.82k | char *end_of_safe_64byte_zone = | 62 | 1.82k | dst == nullptr | 63 | 1.82k | ? nullptr | 64 | 1.82k | : ((srclen + 3) / 4 * 3 >= 63 ? dst + (srclen + 3) / 4 * 3 - 63 | 65 | 1.68k | : dst); | 66 | | | 67 | 1.82k | const chartype *const srcinit = src; | 68 | 1.82k | const char *const dstinit = dst; | 69 | 1.82k | const chartype *const srcend = src + srclen; | 70 | | | 71 | 1.82k | constexpr size_t block_size = 6; | 72 | 1.82k | static_assert(block_size >= 2, "block_size must be at least two"); | 73 | 1.82k | char buffer[block_size * 64]; | 74 | 1.82k | char *bufferptr = buffer; | 75 | 1.82k | if (srclen >= 64) { | 76 | 1.39k | const chartype *const srcend64 = src + srclen - 64; | 77 | 41.0k | while (src <= srcend64) { | 78 | 40.0k | block64 b(src); | 79 | 40.0k | src += 64; | 80 | 40.0k | uint64_t error = 0; | 81 | 40.0k | const uint64_t badcharmask = | 82 | 40.0k | b.to_base64_mask<base64_url, ignore_garbage, default_or_url>(&error); | 83 | 40.0k | if (!ignore_garbage && error) { | 84 | 464 | src -= 64; | 85 | 464 | const size_t error_offset = trailing_zeroes(error); | 86 | 464 | return {error_code::INVALID_BASE64_CHARACTER, | 87 | 464 | size_t(src - srcinit + error_offset), size_t(dst - dstinit)}; | 88 | 464 | } | 89 | 39.6k | if (badcharmask != 0) { | 90 | 31.8k | bufferptr += b.compress_block(badcharmask, bufferptr); | 91 | 31.8k | } else if (bufferptr != buffer) { | 92 | 6.68k | b.copy_block(bufferptr); | 93 | 6.68k | bufferptr += 64; | 94 | 6.68k | } else { | 95 | 1.05k | if (dst >= end_of_safe_64byte_zone) { | 96 | 13 | b.base64_decode_block_safe(dst); | 97 | 1.04k | } else { | 98 | 1.04k | b.base64_decode_block(dst); | 99 | 1.04k | } | 100 | 1.05k | dst += 48; | 101 | 1.05k | } | 102 | 39.6k | if (bufferptr >= (block_size - 1) * 64 + buffer) { | 103 | 26.9k | for (size_t i = 0; i < (block_size - 2); i++) { | 104 | 21.5k | base64_decode_block(dst, buffer + i * 64); | 105 | 21.5k | dst += 48; | 106 | 21.5k | } | 107 | 5.38k | if (dst >= end_of_safe_64byte_zone) { | 108 | 0 | base64_decode_block_safe(dst, buffer + (block_size - 2) * 64); | 109 | 5.38k | } else { | 110 | 5.38k | base64_decode_block(dst, buffer + (block_size - 2) * 64); | 111 | 5.38k | } | 112 | 5.38k | dst += 48; | 113 | 5.38k | std::memcpy(buffer, buffer + (block_size - 1) * 64, | 114 | 5.38k | 64); // 64 might be too much | 115 | 5.38k | bufferptr -= (block_size - 1) * 64; | 116 | 5.38k | } | 117 | 39.6k | } | 118 | 1.39k | } | 119 | | | 120 | 1.35k | char *buffer_start = buffer; | 121 | | // Optimization note: if this is almost full, then it is worth our | 122 | | // time, otherwise, we should just decode directly. | 123 | 1.35k | int last_block = (int)((bufferptr - buffer_start) % 64); | 124 | 1.35k | if (last_block != 0 && srcend - src + last_block >= 64) { | 125 | | | 126 | 1.41k | while ((bufferptr - buffer_start) % 64 != 0 && src < srcend) { | 127 | 1.32k | uint8_t val = to_base64[uint8_t(*src)]; | 128 | 1.32k | *bufferptr = char(val); | 129 | 1.32k | if (!ignore_garbage && | 130 | 1.32k | (!scalar::base64::is_eight_byte(*src) || val > 64)) { | 131 | 66 | return {error_code::INVALID_BASE64_CHARACTER, size_t(src - srcinit), | 132 | 66 | size_t(dst - dstinit)}; | 133 | 66 | } | 134 | 1.25k | bufferptr += (val <= 63); | 135 | 1.25k | src++; | 136 | 1.25k | } | 137 | 156 | } | 138 | | | 139 | 1.79k | for (; buffer_start + 64 <= bufferptr; buffer_start += 64) { | 140 | 504 | if (dst >= end_of_safe_64byte_zone) { | 141 | 38 | base64_decode_block_safe(dst, buffer_start); | 142 | 466 | } else { | 143 | 466 | base64_decode_block(dst, buffer_start); | 144 | 466 | } | 145 | 504 | dst += 48; | 146 | 504 | } | 147 | 1.29k | if ((bufferptr - buffer_start) % 64 != 0) { | 148 | 6.06k | while (buffer_start + 4 < bufferptr) { | 149 | 5.32k | uint32_t triple = ((uint32_t(uint8_t(buffer_start[0])) << 3 * 6) + | 150 | 5.32k | (uint32_t(uint8_t(buffer_start[1])) << 2 * 6) + | 151 | 5.32k | (uint32_t(uint8_t(buffer_start[2])) << 1 * 6) + | 152 | 5.32k | (uint32_t(uint8_t(buffer_start[3])) << 0 * 6)) | 153 | 5.32k | << 8; | 154 | 5.32k | #if !SIMDUTF_IS_BIG_ENDIAN | 155 | 5.32k | triple = scalar::u32_swap_bytes(triple); | 156 | 5.32k | #endif | 157 | 5.32k | std::memcpy(dst, &triple, 3); | 158 | | | 159 | 5.32k | dst += 3; | 160 | 5.32k | buffer_start += 4; | 161 | 5.32k | } | 162 | 739 | if (buffer_start + 4 <= bufferptr) { | 163 | 183 | uint32_t triple = ((uint32_t(uint8_t(buffer_start[0])) << 3 * 6) + | 164 | 183 | (uint32_t(uint8_t(buffer_start[1])) << 2 * 6) + | 165 | 183 | (uint32_t(uint8_t(buffer_start[2])) << 1 * 6) + | 166 | 183 | (uint32_t(uint8_t(buffer_start[3])) << 0 * 6)) | 167 | 183 | << 8; | 168 | 183 | #if !SIMDUTF_IS_BIG_ENDIAN | 169 | 183 | triple = scalar::u32_swap_bytes(triple); | 170 | 183 | #endif | 171 | 183 | std::memcpy(dst, &triple, 3); | 172 | | | 173 | 183 | dst += 3; | 174 | 183 | buffer_start += 4; | 175 | 183 | } | 176 | | // we may have 1, 2 or 3 bytes left and we need to decode them so let us | 177 | | // backtrack | 178 | 739 | int leftover = int(bufferptr - buffer_start); | 179 | 1.85k | while (leftover > 0) { | 180 | 1.11k | if (!ignore_garbage) { | 181 | 11.5k | while (to_base64[uint8_t(*(src - 1))] == 64) { | 182 | 10.4k | src--; | 183 | 10.4k | } | 184 | 1.11k | } else { | 185 | 0 | while (to_base64[uint8_t(*(src - 1))] >= 64) { | 186 | 0 | src--; | 187 | 0 | } | 188 | 0 | } | 189 | 1.11k | src--; | 190 | 1.11k | leftover--; | 191 | 1.11k | } | 192 | 739 | } | 193 | 1.29k | if (src < srcend + equalsigns) { | 194 | 1.09k | full_result r = scalar::base64::base64_tail_decode( | 195 | 1.09k | dst, src, srcend - src, equalsigns, options, last_chunk_options); | 196 | 1.09k | r = scalar::base64::patch_tail_result( | 197 | 1.09k | r, size_t(src - srcinit), size_t(dst - dstinit), equallocation, | 198 | 1.09k | full_input_length, last_chunk_options); | 199 | | // When is_partial(last_chunk_options) is true, we must either end with | 200 | | // the end of the stream (beyond whitespace) or right after a non-ignorable | 201 | | // character or at the very beginning of the stream. | 202 | | // See https://tc39.es/proposal-arraybuffer-base64/spec/#sec-frombase64 | 203 | 1.09k | if (is_partial(last_chunk_options) && r.error == error_code::SUCCESS && | 204 | 512 | r.input_count < full_input_length) { | 205 | | // First check if we can extend the input to the end of the stream | 206 | 30.0k | while (r.input_count < full_input_length && | 207 | 30.0k | base64_ignorable(*(srcinit + r.input_count), options)) { | 208 | 29.5k | r.input_count++; | 209 | 29.5k | } | 210 | | // If we are still not at the end of the stream, then we must backtrack | 211 | | // to the last non-ignorable character. | 212 | 472 | if (r.input_count < full_input_length) { | 213 | 39.5k | while (r.input_count > 0 && | 214 | 39.4k | base64_ignorable(*(srcinit + r.input_count - 1), options)) { | 215 | 39.1k | r.input_count--; | 216 | 39.1k | } | 217 | 462 | } | 218 | 472 | } | 219 | 1.09k | return r; | 220 | 1.09k | } | 221 | 195 | if (!ignore_garbage && equalsigns > 0) { | 222 | 0 | if ((size_t(dst - dstinit) % 3 == 0) || | 223 | 0 | ((size_t(dst - dstinit) % 3) + 1 + equalsigns != 4)) { | 224 | 0 | return {INVALID_BASE64_CHARACTER, equallocation, size_t(dst - dstinit), | 225 | 0 | true}; | 226 | 0 | } | 227 | 0 | } | 228 | 195 | return {SUCCESS, srclen, size_t(dst - dstinit)}; | 229 | 195 | } |
Unexecuted instantiation: simdutf.cpp:simdutf::full_result simdutf::westmere::(anonymous namespace)::base64::compress_decode_base64<false, true, false, char16_t>(char*, char16_t const*, unsigned long, simdutf::base64_options, simdutf::last_chunk_handling_options) simdutf.cpp:simdutf::full_result simdutf::westmere::(anonymous namespace)::base64::compress_decode_base64<false, false, false, char16_t>(char*, char16_t const*, unsigned long, simdutf::base64_options, simdutf::last_chunk_handling_options) Line | Count | Source | 45 | 1.93k | last_chunk_handling_options last_chunk_options) { | 46 | 1.93k | const uint8_t *to_base64 = | 47 | 1.93k | default_or_url ? tables::base64::to_base64_default_or_url_value | 48 | 1.93k | : (base64_url ? tables::base64::to_base64_url_value | 49 | 1.93k | : tables::base64::to_base64_value); | 50 | 1.93k | auto ri = simdutf::scalar::base64::find_end(src, srclen, options); | 51 | 1.93k | size_t equallocation = ri.equallocation; | 52 | 1.93k | size_t equalsigns = ri.equalsigns; | 53 | 1.93k | srclen = ri.srclen; | 54 | 1.93k | size_t full_input_length = ri.full_input_length; | 55 | 1.93k | if (srclen == 0) { | 56 | 37 | if (!ignore_garbage && equalsigns > 0) { | 57 | 17 | return {INVALID_BASE64_CHARACTER, equallocation, 0, true}; | 58 | 17 | } | 59 | 20 | return {SUCCESS, full_input_length, 0}; | 60 | 37 | } | 61 | 1.90k | char *end_of_safe_64byte_zone = | 62 | 1.90k | dst == nullptr | 63 | 1.90k | ? nullptr | 64 | 1.90k | : ((srclen + 3) / 4 * 3 >= 63 ? dst + (srclen + 3) / 4 * 3 - 63 | 65 | 1.76k | : dst); | 66 | | | 67 | 1.90k | const chartype *const srcinit = src; | 68 | 1.90k | const char *const dstinit = dst; | 69 | 1.90k | const chartype *const srcend = src + srclen; | 70 | | | 71 | 1.90k | constexpr size_t block_size = 6; | 72 | 1.90k | static_assert(block_size >= 2, "block_size must be at least two"); | 73 | 1.90k | char buffer[block_size * 64]; | 74 | 1.90k | char *bufferptr = buffer; | 75 | 1.90k | if (srclen >= 64) { | 76 | 1.43k | const chartype *const srcend64 = src + srclen - 64; | 77 | 94.0k | while (src <= srcend64) { | 78 | 93.1k | block64 b(src); | 79 | 93.1k | src += 64; | 80 | 93.1k | uint64_t error = 0; | 81 | 93.1k | const uint64_t badcharmask = | 82 | 93.1k | b.to_base64_mask<base64_url, ignore_garbage, default_or_url>(&error); | 83 | 93.1k | if (!ignore_garbage && error) { | 84 | 504 | src -= 64; | 85 | 504 | const size_t error_offset = trailing_zeroes(error); | 86 | 504 | return {error_code::INVALID_BASE64_CHARACTER, | 87 | 504 | size_t(src - srcinit + error_offset), size_t(dst - dstinit)}; | 88 | 504 | } | 89 | 92.6k | if (badcharmask != 0) { | 90 | 75.1k | bufferptr += b.compress_block(badcharmask, bufferptr); | 91 | 75.1k | } else if (bufferptr != buffer) { | 92 | 16.6k | b.copy_block(bufferptr); | 93 | 16.6k | bufferptr += 64; | 94 | 16.6k | } else { | 95 | 808 | if (dst >= end_of_safe_64byte_zone) { | 96 | 7 | b.base64_decode_block_safe(dst); | 97 | 801 | } else { | 98 | 801 | b.base64_decode_block(dst); | 99 | 801 | } | 100 | 808 | dst += 48; | 101 | 808 | } | 102 | 92.6k | if (bufferptr >= (block_size - 1) * 64 + buffer) { | 103 | 73.3k | for (size_t i = 0; i < (block_size - 2); i++) { | 104 | 58.6k | base64_decode_block(dst, buffer + i * 64); | 105 | 58.6k | dst += 48; | 106 | 58.6k | } | 107 | 14.6k | if (dst >= end_of_safe_64byte_zone) { | 108 | 0 | base64_decode_block_safe(dst, buffer + (block_size - 2) * 64); | 109 | 14.6k | } else { | 110 | 14.6k | base64_decode_block(dst, buffer + (block_size - 2) * 64); | 111 | 14.6k | } | 112 | 14.6k | dst += 48; | 113 | 14.6k | std::memcpy(buffer, buffer + (block_size - 1) * 64, | 114 | 14.6k | 64); // 64 might be too much | 115 | 14.6k | bufferptr -= (block_size - 1) * 64; | 116 | 14.6k | } | 117 | 92.6k | } | 118 | 1.43k | } | 119 | | | 120 | 1.39k | char *buffer_start = buffer; | 121 | | // Optimization note: if this is almost full, then it is worth our | 122 | | // time, otherwise, we should just decode directly. | 123 | 1.39k | int last_block = (int)((bufferptr - buffer_start) % 64); | 124 | 1.39k | if (last_block != 0 && srcend - src + last_block >= 64) { | 125 | | | 126 | 1.27k | while ((bufferptr - buffer_start) % 64 != 0 && src < srcend) { | 127 | 1.16k | uint8_t val = to_base64[uint8_t(*src)]; | 128 | 1.16k | *bufferptr = char(val); | 129 | 1.16k | if (!ignore_garbage && | 130 | 1.16k | (!scalar::base64::is_eight_byte(*src) || val > 64)) { | 131 | 58 | return {error_code::INVALID_BASE64_CHARACTER, size_t(src - srcinit), | 132 | 58 | size_t(dst - dstinit)}; | 133 | 58 | } | 134 | 1.10k | bufferptr += (val <= 63); | 135 | 1.10k | src++; | 136 | 1.10k | } | 137 | 167 | } | 138 | | | 139 | 1.96k | for (; buffer_start + 64 <= bufferptr; buffer_start += 64) { | 140 | 623 | if (dst >= end_of_safe_64byte_zone) { | 141 | 48 | base64_decode_block_safe(dst, buffer_start); | 142 | 575 | } else { | 143 | 575 | base64_decode_block(dst, buffer_start); | 144 | 575 | } | 145 | 623 | dst += 48; | 146 | 623 | } | 147 | 1.34k | if ((bufferptr - buffer_start) % 64 != 0) { | 148 | 6.42k | while (buffer_start + 4 < bufferptr) { | 149 | 5.67k | uint32_t triple = ((uint32_t(uint8_t(buffer_start[0])) << 3 * 6) + | 150 | 5.67k | (uint32_t(uint8_t(buffer_start[1])) << 2 * 6) + | 151 | 5.67k | (uint32_t(uint8_t(buffer_start[2])) << 1 * 6) + | 152 | 5.67k | (uint32_t(uint8_t(buffer_start[3])) << 0 * 6)) | 153 | 5.67k | << 8; | 154 | 5.67k | #if !SIMDUTF_IS_BIG_ENDIAN | 155 | 5.67k | triple = scalar::u32_swap_bytes(triple); | 156 | 5.67k | #endif | 157 | 5.67k | std::memcpy(dst, &triple, 3); | 158 | | | 159 | 5.67k | dst += 3; | 160 | 5.67k | buffer_start += 4; | 161 | 5.67k | } | 162 | 745 | if (buffer_start + 4 <= bufferptr) { | 163 | 182 | uint32_t triple = ((uint32_t(uint8_t(buffer_start[0])) << 3 * 6) + | 164 | 182 | (uint32_t(uint8_t(buffer_start[1])) << 2 * 6) + | 165 | 182 | (uint32_t(uint8_t(buffer_start[2])) << 1 * 6) + | 166 | 182 | (uint32_t(uint8_t(buffer_start[3])) << 0 * 6)) | 167 | 182 | << 8; | 168 | 182 | #if !SIMDUTF_IS_BIG_ENDIAN | 169 | 182 | triple = scalar::u32_swap_bytes(triple); | 170 | 182 | #endif | 171 | 182 | std::memcpy(dst, &triple, 3); | 172 | | | 173 | 182 | dst += 3; | 174 | 182 | buffer_start += 4; | 175 | 182 | } | 176 | | // we may have 1, 2 or 3 bytes left and we need to decode them so let us | 177 | | // backtrack | 178 | 745 | int leftover = int(bufferptr - buffer_start); | 179 | 1.86k | while (leftover > 0) { | 180 | 1.12k | if (!ignore_garbage) { | 181 | 19.9k | while (to_base64[uint8_t(*(src - 1))] == 64) { | 182 | 18.8k | src--; | 183 | 18.8k | } | 184 | 1.12k | } else { | 185 | 0 | while (to_base64[uint8_t(*(src - 1))] >= 64) { | 186 | 0 | src--; | 187 | 0 | } | 188 | 0 | } | 189 | 1.12k | src--; | 190 | 1.12k | leftover--; | 191 | 1.12k | } | 192 | 745 | } | 193 | 1.34k | if (src < srcend + equalsigns) { | 194 | 1.14k | full_result r = scalar::base64::base64_tail_decode( | 195 | 1.14k | dst, src, srcend - src, equalsigns, options, last_chunk_options); | 196 | 1.14k | r = scalar::base64::patch_tail_result( | 197 | 1.14k | r, size_t(src - srcinit), size_t(dst - dstinit), equallocation, | 198 | 1.14k | full_input_length, last_chunk_options); | 199 | | // When is_partial(last_chunk_options) is true, we must either end with | 200 | | // the end of the stream (beyond whitespace) or right after a non-ignorable | 201 | | // character or at the very beginning of the stream. | 202 | | // See https://tc39.es/proposal-arraybuffer-base64/spec/#sec-frombase64 | 203 | 1.14k | if (is_partial(last_chunk_options) && r.error == error_code::SUCCESS && | 204 | 509 | r.input_count < full_input_length) { | 205 | | // First check if we can extend the input to the end of the stream | 206 | 10.3k | while (r.input_count < full_input_length && | 207 | 10.2k | base64_ignorable(*(srcinit + r.input_count), options)) { | 208 | 9.85k | r.input_count++; | 209 | 9.85k | } | 210 | | // If we are still not at the end of the stream, then we must backtrack | 211 | | // to the last non-ignorable character. | 212 | 454 | if (r.input_count < full_input_length) { | 213 | 16.2k | while (r.input_count > 0 && | 214 | 16.1k | base64_ignorable(*(srcinit + r.input_count - 1), options)) { | 215 | 15.8k | r.input_count--; | 216 | 15.8k | } | 217 | 442 | } | 218 | 454 | } | 219 | 1.14k | return r; | 220 | 1.14k | } | 221 | 198 | if (!ignore_garbage && equalsigns > 0) { | 222 | 0 | if ((size_t(dst - dstinit) % 3 == 0) || | 223 | 0 | ((size_t(dst - dstinit) % 3) + 1 + equalsigns != 4)) { | 224 | 0 | return {INVALID_BASE64_CHARACTER, equallocation, size_t(dst - dstinit), | 225 | 0 | true}; | 226 | 0 | } | 227 | 0 | } | 228 | 198 | return {SUCCESS, srclen, size_t(dst - dstinit)}; | 229 | 198 | } |
|