// Copyright Mozilla Foundation. See the COPYRIGHT // file at the top-level directory of this distribution. // // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or // https://www.apache.org/licenses/LICENSE-2.0> or the MIT license // <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your // option. This file may not be copied, modified, or distributed // except according to those terms.
macro_rules! public_decode_function{
($(#[$meta:meta])*,
$decode_to_utf:ident,
$decode_to_utf_raw:ident,
$decode_to_utf_checking_end:ident,
$decode_to_utf_after_one_potential_bom_byte:ident,
$decode_to_utf_after_two_potential_bom_bytes:ident,
$decode_to_utf_checking_end_with_offset:ident,
$code_unit:ty) => (
$(#[$meta])* pubfn $decode_to_utf(&mutself,
src: &[u8],
dst: &mut [$code_unit],
last: bool)
-> (DecoderResult, usize, usize) { letmut offset = 0usize; loop { matchself.life_cycle { // The common case. (Post-sniffing.)
DecoderLifeCycle::Converting => { returnself.$decode_to_utf_checking_end(src, dst, last);
} // The rest is all BOM sniffing!
DecoderLifeCycle::AtStart => {
debug_assert_eq!(offset, 0usize); if src.is_empty() { return (DecoderResult::InputEmpty, 0, 0);
} match src[0] { 0xEFu8 => { self.life_cycle = DecoderLifeCycle::SeenUtf8First;
offset += 1; continue;
} 0xFEu8 => { self.life_cycle = DecoderLifeCycle::SeenUtf16BeFirst;
offset += 1; continue;
} 0xFFu8 => { self.life_cycle = DecoderLifeCycle::SeenUtf16LeFirst;
offset += 1; continue;
}
_ => { self.life_cycle = DecoderLifeCycle::Converting; continue;
}
}
}
DecoderLifeCycle::AtUtf8Start => {
debug_assert_eq!(offset, 0usize); if src.is_empty() { return (DecoderResult::InputEmpty, 0, 0);
} match src[0] { 0xEFu8 => { self.life_cycle = DecoderLifeCycle::SeenUtf8First;
offset += 1; continue;
}
_ => { self.life_cycle = DecoderLifeCycle::Converting; continue;
}
}
}
DecoderLifeCycle::AtUtf16BeStart => {
debug_assert_eq!(offset, 0usize); if src.is_empty() { return (DecoderResult::InputEmpty, 0, 0);
} match src[0] { 0xFEu8 => { self.life_cycle = DecoderLifeCycle::SeenUtf16BeFirst;
offset += 1; continue;
}
_ => { self.life_cycle = DecoderLifeCycle::Converting; continue;
}
}
}
DecoderLifeCycle::AtUtf16LeStart => {
debug_assert_eq!(offset, 0usize); if src.is_empty() { return (DecoderResult::InputEmpty, 0, 0);
} match src[0] { 0xFFu8 => { self.life_cycle = DecoderLifeCycle::SeenUtf16LeFirst;
offset += 1; continue;
}
_ => { self.life_cycle = DecoderLifeCycle::Converting; continue;
}
}
}
DecoderLifeCycle::SeenUtf8First => { if offset >= src.len() { if last { returnself.$decode_to_utf_after_one_potential_bom_byte(src,
dst,
last,
offset, 0xEFu8);
} return (DecoderResult::InputEmpty, offset, 0);
} if src[offset] == 0xBBu8 { self.life_cycle = DecoderLifeCycle::SeenUtf8Second;
offset += 1; continue;
} returnself.$decode_to_utf_after_one_potential_bom_byte(src,
dst,
last,
offset, 0xEFu8);
}
DecoderLifeCycle::SeenUtf8Second => { if offset >= src.len() { if last { returnself.$decode_to_utf_after_two_potential_bom_bytes(src,
dst,
last,
offset);
} return (DecoderResult::InputEmpty, offset, 0);
} if src[offset] == 0xBFu8 { self.life_cycle = DecoderLifeCycle::Converting;
offset += 1; ifself.encoding != UTF_8 { self.encoding = UTF_8; self.variant = UTF_8.new_variant_decoder();
} returnself.$decode_to_utf_checking_end_with_offset(src,
dst,
last,
offset);
} returnself.$decode_to_utf_after_two_potential_bom_bytes(src,
dst,
last,
offset);
}
DecoderLifeCycle::SeenUtf16BeFirst => { if offset >= src.len() { if last { returnself.$decode_to_utf_after_one_potential_bom_byte(src,
dst,
last,
offset, 0xFEu8);
} return (DecoderResult::InputEmpty, offset, 0);
} if src[offset] == 0xFFu8 { self.life_cycle = DecoderLifeCycle::Converting;
offset += 1; ifself.encoding != UTF_16BE { self.encoding = UTF_16BE; self.variant = UTF_16BE.new_variant_decoder();
} returnself.$decode_to_utf_checking_end_with_offset(src,
dst,
last,
offset);
} returnself.$decode_to_utf_after_one_potential_bom_byte(src,
dst,
last,
offset, 0xFEu8);
}
DecoderLifeCycle::SeenUtf16LeFirst => { if offset >= src.len() { if last { returnself.$decode_to_utf_after_one_potential_bom_byte(src,
dst,
last,
offset, 0xFFu8);
} return (DecoderResult::InputEmpty, offset, 0);
} if src[offset] == 0xFEu8 { self.life_cycle = DecoderLifeCycle::Converting;
offset += 1; ifself.encoding != UTF_16LE { self.encoding = UTF_16LE; self.variant = UTF_16LE.new_variant_decoder();
} returnself.$decode_to_utf_checking_end_with_offset(src,
dst,
last,
offset);
} returnself.$decode_to_utf_after_one_potential_bom_byte(src,
dst,
last,
offset, 0xFFu8);
}
DecoderLifeCycle::ConvertingWithPendingBB => {
debug_assert_eq!(offset, 0usize); returnself.$decode_to_utf_after_one_potential_bom_byte(src,
dst,
last, 0usize, 0xBBu8);
}
DecoderLifeCycle::Finished => panic!("Must not use a decoder that has finished."),
}
}
}
fn $decode_to_utf_after_one_potential_bom_byte(&mutself,
src: &[u8],
dst: &mut [$code_unit],
last: bool,
offset: usize,
first_byte: u8)
-> (DecoderResult, usize, usize) { self.life_cycle = DecoderLifeCycle::Converting; if offset == 0usize { // First byte was seen previously. let first = [first_byte]; letmut out_read = 0usize; let (mut first_result, _, mut first_written) = self.variant
.$decode_to_utf_raw(&first[..], dst, false); match first_result {
DecoderResult::InputEmpty => { let (result, read, written) = self.$decode_to_utf_checking_end(src, &mut dst[first_written..], last);
first_result = result;
out_read = read; // Overwrite, don't add!
first_written += written;
}
DecoderResult::Malformed(_, _) => { // Wasn't read from `src`!, leave out_read to 0
}
DecoderResult::OutputFull => {
panic!("Output buffer must have been too small.");
}
} return (first_result, out_read, first_written);
}
debug_assert_eq!(offset, 1usize); // The first byte is in `src`, so no need to push it separately. self.$decode_to_utf_checking_end(src, dst, last)
}
fn $decode_to_utf_after_two_potential_bom_bytes(&mutself,
src: &[u8],
dst: &mut [$code_unit],
last: bool,
offset: usize)
-> (DecoderResult, usize, usize) { self.life_cycle = DecoderLifeCycle::Converting; if offset == 0usize { // The first two bytes are not in the current buffer.. let ef_bb = [0xEFu8, 0xBBu8]; let (mut first_result, mut first_read, mut first_written) = self.variant
.$decode_to_utf_raw(&ef_bb[..], dst, false); match first_result {
DecoderResult::InputEmpty => { let (result, read, written) = self.$decode_to_utf_checking_end(src, &mut dst[first_written..], last);
first_result = result;
first_read = read; // Overwrite, don't add!
first_written += written;
}
DecoderResult::Malformed(_, _) => { if first_read == 1usize { // The first byte was malformed. We need to handle // the second one, which isn't in `src`, later. self.life_cycle = DecoderLifeCycle::ConvertingWithPendingBB;
}
first_read = 0usize; // Wasn't read from `src`!
}
DecoderResult::OutputFull => {
panic!("Output buffer must have been too small.");
}
} return (first_result, first_read, first_written);
} if offset == 1usize { // The first byte isn't in the current buffer but the second one // is. returnself.$decode_to_utf_after_one_potential_bom_byte(src,
dst,
last, 0usize, 0xEFu8);
}
debug_assert_eq!(offset, 2usize); // The first two bytes are in `src`, so no need to push them separately. self.$decode_to_utf_checking_end(src, dst, last)
}
/// Calls `$decode_to_utf_checking_end` with `offset` bytes omitted from /// the start of `src` but adjusting the return values to show those bytes /// as having been consumed. fn $decode_to_utf_checking_end_with_offset(&mutself,
src: &[u8],
dst: &mut [$code_unit],
last: bool,
offset: usize)
-> (DecoderResult, usize, usize) {
debug_assert_eq!(self.life_cycle, DecoderLifeCycle::Converting); let (result, read, written) = self.$decode_to_utf_checking_end(&src[offset..], dst, last);
(result, read + offset, written)
}
/// Calls through to the delegate and adjusts life cycle iff `last` is /// `true` and result is `DecoderResult::InputEmpty`. fn $decode_to_utf_checking_end(&mutself,
src: &[u8],
dst: &mut [$code_unit],
last: bool)
-> (DecoderResult, usize, usize) {
debug_assert_eq!(self.life_cycle, DecoderLifeCycle::Converting); let (result, read, written) = self.variant
.$decode_to_utf_raw(src, dst, last); if last { iflet DecoderResult::InputEmpty = result { self.life_cycle = DecoderLifeCycle::Finished;
}
}
(result, read, written)
});
}
Messung V0.5 in Prozent
¤ Diese beiden folgenden Angebotsgruppen bietet das Unternehmen0.32Angebot
(Wie Sie bei der Firma Beratungs- und Dienstleistungen beauftragen können 2026-06-19)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.