11use crate :: {
22 engine:: { general_purpose:: INVALID_VALUE , DecodeMetadata , DecodePaddingMode } ,
3- DecodeError , PAD_BYTE ,
3+ DecodeError , DecodeSliceError , PAD_BYTE ,
44} ;
55
66/// Decode the last 0-4 bytes, checking for trailing set bits and padding per the provided
@@ -16,11 +16,11 @@ pub(crate) fn decode_suffix(
1616 decode_table : & [ u8 ; 256 ] ,
1717 decode_allow_trailing_bits : bool ,
1818 padding_mode : DecodePaddingMode ,
19- ) -> Result < DecodeMetadata , DecodeError > {
19+ ) -> Result < DecodeMetadata , DecodeSliceError > {
2020 debug_assert ! ( ( input. len( ) - input_index) <= 4 ) ;
2121
22- // Decode any leftovers that might not be a complete input chunk of 8 bytes.
23- // Use a u64 as a stack-resident 8 byte buffer.
22+ // Decode any leftovers that might not be a complete input chunk of 4 bytes.
23+ // Use a u32 as a stack-resident 4 byte buffer.
2424 let mut morsels_in_leftover = 0 ;
2525 let mut padding_bytes_count = 0 ;
2626 // offset from input_index
@@ -44,22 +44,14 @@ pub(crate) fn decode_suffix(
4444 // may be treated as an error condition.
4545
4646 if leftover_index < 2 {
47- // Check for case #2.
48- let bad_padding_index = input_index
49- + if padding_bytes_count > 0 {
50- // If we've already seen padding, report the first padding index.
51- // This is to be consistent with the normal decode logic: it will report an
52- // error on the first padding character (since it doesn't expect to see
53- // anything but actual encoded data).
54- // This could only happen if the padding started in the previous quad since
55- // otherwise this case would have been hit at i == 4 if it was the same
56- // quad.
57- first_padding_offset
58- } else {
59- // haven't seen padding before, just use where we are now
60- leftover_index
61- } ;
62- return Err ( DecodeError :: InvalidByte ( bad_padding_index, b) ) ;
47+ // Check for error #2.
48+ // Either the previous byte was padding, in which case we would have already hit
49+ // this case, or it wasn't, in which case this is the first such error.
50+ debug_assert ! (
51+ leftover_index == 0 || ( leftover_index == 1 && padding_bytes_count == 0 )
52+ ) ;
53+ let bad_padding_index = input_index + leftover_index;
54+ return Err ( DecodeError :: InvalidByte ( bad_padding_index, b) . into ( ) ) ;
6355 }
6456
6557 if padding_bytes_count == 0 {
@@ -75,10 +67,9 @@ pub(crate) fn decode_suffix(
7567 // non-suffix '=' in trailing chunk either. Report error as first
7668 // erroneous padding.
7769 if padding_bytes_count > 0 {
78- return Err ( DecodeError :: InvalidByte (
79- input_index + first_padding_offset,
80- PAD_BYTE ,
81- ) ) ;
70+ return Err (
71+ DecodeError :: InvalidByte ( input_index + first_padding_offset, PAD_BYTE ) . into ( ) ,
72+ ) ;
8273 }
8374
8475 last_symbol = b;
@@ -87,7 +78,7 @@ pub(crate) fn decode_suffix(
8778 // Pack the leftovers from left to right.
8879 let morsel = decode_table[ b as usize ] ;
8980 if morsel == INVALID_VALUE {
90- return Err ( DecodeError :: InvalidByte ( input_index + leftover_index, b) ) ;
81+ return Err ( DecodeError :: InvalidByte ( input_index + leftover_index, b) . into ( ) ) ;
9182 }
9283
9384 morsels[ morsels_in_leftover] = morsel;
@@ -97,24 +88,22 @@ pub(crate) fn decode_suffix(
9788 // If there was 1 trailing byte, and it was valid, and we got to this point without hitting
9889 // an invalid byte, now we can report invalid length
9990 if !input. is_empty ( ) && morsels_in_leftover < 2 {
100- return Err ( DecodeError :: InvalidLength (
101- input_index + morsels_in_leftover,
102- ) ) ;
91+ return Err ( DecodeError :: InvalidLength ( input_index + morsels_in_leftover) . into ( ) ) ;
10392 }
10493
10594 match padding_mode {
10695 DecodePaddingMode :: Indifferent => { /* everything we care about was already checked */ }
10796 DecodePaddingMode :: RequireCanonical => {
10897 // allow empty input
10998 if ( padding_bytes_count + morsels_in_leftover) % 4 != 0 {
110- return Err ( DecodeError :: InvalidPadding ) ;
99+ return Err ( DecodeError :: InvalidPadding . into ( ) ) ;
111100 }
112101 }
113102 DecodePaddingMode :: RequireNone => {
114103 if padding_bytes_count > 0 {
115104 // check at the end to make sure we let the cases of padding that should be InvalidByte
116105 // get hit
117- return Err ( DecodeError :: InvalidPadding ) ;
106+ return Err ( DecodeError :: InvalidPadding . into ( ) ) ;
118107 }
119108 }
120109 }
@@ -127,7 +116,7 @@ pub(crate) fn decode_suffix(
127116 // bits in the bottom 6, but would be a non-canonical encoding. So, we calculate a
128117 // mask based on how many bits are used for just the canonical encoding, and optionally
129118 // error if any other bits are set. In the example of one encoded byte -> 2 symbols,
130- // 2 symbols can technically encode 12 bits, but the last 4 are non canonical, and
119+ // 2 symbols can technically encode 12 bits, but the last 4 are non- canonical, and
131120 // useless since there are no more symbols to provide the necessary 4 additional bits
132121 // to finish the second original byte.
133122
@@ -147,16 +136,18 @@ pub(crate) fn decode_suffix(
147136 return Err ( DecodeError :: InvalidLastSymbol (
148137 input_index + morsels_in_leftover - 1 ,
149138 last_symbol,
150- ) ) ;
139+ )
140+ . into ( ) ) ;
151141 }
152142
153143 // Strangely, this approach benchmarks better than writing bytes one at a time,
154144 // or copy_from_slice into output.
155145 for _ in 0 ..leftover_bytes_to_append {
156146 let hi_byte = ( leftover_num >> 24 ) as u8 ;
157147 leftover_num <<= 8 ;
158- // TODO use checked writes
159- output[ output_index] = hi_byte;
148+ * output
149+ . get_mut ( output_index)
150+ . ok_or ( DecodeSliceError :: OutputSliceTooSmall ) ? = hi_byte;
160151 output_index += 1 ;
161152 }
162153
0 commit comments