| 1 | static inline int |
| 2 | dec_loop_generic_32_inner (const uint8_t **s, uint8_t **o, size_t *rounds) |
| 3 | { |
| 4 | const uint32_t str |
| 5 | = base64_table_dec_d0[(*s)[0]] |
| 6 | | base64_table_dec_d1[(*s)[1]] |
| 7 | | base64_table_dec_d2[(*s)[2]] |
| 8 | | base64_table_dec_d3[(*s)[3]]; |
| 9 | |
| 10 | #if BASE64_LITTLE_ENDIAN |
| 11 | |
| 12 | // LUTs for little-endian set MSB in case of invalid character: |
| 13 | if (str & UINT32_C(0x80000000)) { |
| 14 | return 0; |
| 15 | } |
| 16 | #else |
| 17 | // LUTs for big-endian set LSB in case of invalid character: |
| 18 | if (str & UINT32_C(1)) { |
| 19 | return 0; |
| 20 | } |
| 21 | #endif |
| 22 | // Store the output: |
| 23 | memcpy(*o, &str, sizeof (str)); |
| 24 | |
| 25 | *s += 4; |
| 26 | *o += 3; |
| 27 | *rounds -= 1; |
| 28 | |
| 29 | return 1; |
| 30 | } |
| 31 | |
| 32 | static inline void |
| 33 | dec_loop_generic_32 (const uint8_t **s, size_t *slen, uint8_t **o, size_t *olen) |
| 34 | { |
| 35 | if (*slen < 8) { |
| 36 | return; |
| 37 | } |
| 38 | |
| 39 | // Process blocks of 4 bytes per round. Because one extra zero byte is |
| 40 | // written after the output, ensure that there will be at least 4 bytes |
| 41 | // of input data left to cover the gap. (Two data bytes and up to two |
| 42 | // end-of-string markers.) |
| 43 | size_t rounds = (*slen - 4) / 4; |
| 44 | |
| 45 | *slen -= rounds * 4; // 4 bytes consumed per round |
| 46 | *olen += rounds * 3; // 3 bytes produced per round |
| 47 | |
| 48 | do { |
| 49 | if (rounds >= 8) { |
| 50 | if (dec_loop_generic_32_inner(s, o, &rounds) && |
| 51 | dec_loop_generic_32_inner(s, o, &rounds) && |
| 52 | dec_loop_generic_32_inner(s, o, &rounds) && |
| 53 | dec_loop_generic_32_inner(s, o, &rounds) && |
| 54 | dec_loop_generic_32_inner(s, o, &rounds) && |
| 55 | dec_loop_generic_32_inner(s, o, &rounds) && |
| 56 | dec_loop_generic_32_inner(s, o, &rounds) && |
| 57 | dec_loop_generic_32_inner(s, o, &rounds)) { |
| 58 | continue; |
| 59 | } |
| 60 | break; |
| 61 | } |
| 62 | if (rounds >= 4) { |
| 63 | if (dec_loop_generic_32_inner(s, o, &rounds) && |
| 64 | dec_loop_generic_32_inner(s, o, &rounds) && |
| 65 | dec_loop_generic_32_inner(s, o, &rounds) && |
| 66 | dec_loop_generic_32_inner(s, o, &rounds)) { |
| 67 | continue; |
| 68 | } |
| 69 | break; |
| 70 | } |
| 71 | if (rounds >= 2) { |
| 72 | if (dec_loop_generic_32_inner(s, o, &rounds) && |
| 73 | dec_loop_generic_32_inner(s, o, &rounds)) { |
| 74 | continue; |
| 75 | } |
| 76 | break; |
| 77 | } |
| 78 | dec_loop_generic_32_inner(s, o, &rounds); |
| 79 | break; |
| 80 | |
| 81 | } while (rounds > 0); |
| 82 | |
| 83 | // Adjust for any rounds that were skipped: |
| 84 | *slen += rounds * 4; |
| 85 | *olen -= rounds * 3; |
| 86 | } |
| 87 | |