Give InputEmpty correct precedent when encoding with replacement.

This commit is contained in:
Henri Sivonen
2017-05-08 10:33:20 +03:00
parent e2b8d33f82
commit bf78f047ae
5 changed files with 180 additions and 0 deletions
+6
View File
@@ -96,6 +96,12 @@ encoding_rs is
## Release Notes
### 0.6.7
* Give `InputEmpty` correct precedence over `OutputFull` when encoding
with replacement and the output buffer passed in is too short or the
remaining space in the output buffer is too small after a replacement.
### 0.6.6
* Correct max length calculation when a partial BOM prefix is part of
+8
View File
@@ -1468,6 +1468,14 @@ for variant in encoder_variants:
variant_file.write('''}
impl VariantEncoder {
pub fn has_pending_state(&self) -> bool {
match *self {
VariantEncoder::Iso2022Jp(ref v) => {
v.has_pending_state()
}
_ => false,
}
}
''')
write_variant_method("max_buffer_length_from_utf16_without_replacement", False, [("u16_length", "usize")], "Option<usize>", encoder_variants, [], "Encoder")
+8
View File
@@ -402,6 +402,14 @@ impl Iso2022JpEncoder {
}))
}
pub fn has_pending_state(&self) -> bool {
match self.state {
Iso2022JpEncoderState::Ascii => false,
_ => true,
}
}
pub fn max_buffer_length_from_utf16_without_replacement(&self,
u16_length: usize)
-> Option<usize> {
+152
View File
@@ -3523,6 +3523,15 @@ impl Encoder {
self.encoding
}
/// Returns `true` if this is an ISO-2022-JP encoder that's not in the
/// ASCII state and `false` otherwise.
///
/// XXX make this public to allow other libs to implement custom replacement
/// strategies and still get the `InputEmpty` semantics right.
fn has_pending_state(&self) -> bool {
self.variant.has_pending_state()
}
/// Query the worst-case output size when encoding from UTF-8 with
/// replacement.
///
@@ -3574,6 +3583,9 @@ impl Encoder {
dst_len
} else {
if dst_len < NCR_EXTRA {
if src.is_empty() && !(last && self.has_pending_state()) {
return (CoderResult::InputEmpty, 0, 0, false);
}
return (CoderResult::OutputFull, 0, 0, false);
}
dst_len - NCR_EXTRA
@@ -3603,6 +3615,12 @@ impl Encoder {
// transitioning to ASCII when returning with Unmappable.
total_written += write_ncr(unmappable, &mut dst[total_written..]);
if total_written >= effective_dst_len {
if total_read == src.len() && !(last && self.has_pending_state()) {
return (CoderResult::InputEmpty,
total_read,
total_written,
had_unmappables);
}
return (CoderResult::OutputFull,
total_read,
total_written,
@@ -3724,6 +3742,9 @@ impl Encoder {
dst_len
} else {
if dst_len < NCR_EXTRA {
if src.is_empty() && !(last && self.has_pending_state()) {
return (CoderResult::InputEmpty, 0, 0, false);
}
return (CoderResult::OutputFull, 0, 0, false);
}
dst_len - NCR_EXTRA
@@ -3759,6 +3780,12 @@ impl Encoder {
// printable ASCII excluding \ and ~.
total_written += write_ncr(unmappable, &mut dst[total_written..]);
if total_written >= effective_dst_len {
if total_read == src.len() && !(last && self.has_pending_state()) {
return (CoderResult::InputEmpty,
total_read,
total_written,
had_unmappables);
}
return (CoderResult::OutputFull,
total_read,
total_written,
@@ -4504,4 +4531,129 @@ mod tests {
}
}
#[test]
fn test_too_short_buffer_with_iso_2022_jp_ascii_from_utf8() {
let mut dst = [0u8; 8];
let mut encoder = ISO_2022_JP.new_encoder();
{
let (result, _, _, _) = encoder.encode_from_utf8("", &mut dst[..], false);
assert_eq!(result, CoderResult::InputEmpty);
}
{
let (result, _, _, _) = encoder.encode_from_utf8("", &mut dst[..], true);
assert_eq!(result, CoderResult::InputEmpty);
}
}
#[test]
fn test_too_short_buffer_with_iso_2022_jp_roman_from_utf8() {
let mut dst = [0u8; 15];
let mut encoder = ISO_2022_JP.new_encoder();
{
let (result, _, _, _) = encoder.encode_from_utf8("\u{A5}", &mut dst[..], false);
assert_eq!(result, CoderResult::InputEmpty);
}
{
let (result, _, _, _) = encoder.encode_from_utf8("", &mut dst[..8], false);
assert_eq!(result, CoderResult::InputEmpty);
}
{
let (result, _, _, _) = encoder.encode_from_utf8("", &mut dst[..8], true);
assert_eq!(result, CoderResult::OutputFull);
}
}
#[test]
fn test_buffer_end_iso_2022_jp_from_utf8() {
let mut dst = [0u8; 17];
{
let mut encoder = ISO_2022_JP.new_encoder();
let (result, _, _, _) = encoder.encode_from_utf8("\u{A5}\u{1F4A9}",
&mut dst[..],
false);
assert_eq!(result, CoderResult::InputEmpty);
}
{
let mut encoder = ISO_2022_JP.new_encoder();
let (result, _, _, _) = encoder.encode_from_utf8("\u{A5}\u{1F4A9}", &mut dst[..], true);
assert_eq!(result, CoderResult::OutputFull);
}
{
let mut encoder = ISO_2022_JP.new_encoder();
let (result, _, _, _) = encoder.encode_from_utf8("\u{1F4A9}", &mut dst[..12], false);
assert_eq!(result, CoderResult::InputEmpty);
}
{
let mut encoder = ISO_2022_JP.new_encoder();
let (result, _, _, _) = encoder.encode_from_utf8("\u{1F4A9}", &mut dst[..12], true);
assert_eq!(result, CoderResult::InputEmpty);
}
}
#[test]
fn test_too_short_buffer_with_iso_2022_jp_ascii_from_utf16() {
let mut dst = [0u8; 8];
let mut encoder = ISO_2022_JP.new_encoder();
{
let (result, _, _, _) = encoder.encode_from_utf16(&[0u16; 0], &mut dst[..], false);
assert_eq!(result, CoderResult::InputEmpty);
}
{
let (result, _, _, _) = encoder.encode_from_utf16(&[0u16; 0], &mut dst[..], true);
assert_eq!(result, CoderResult::InputEmpty);
}
}
#[test]
fn test_too_short_buffer_with_iso_2022_jp_roman_from_utf16() {
let mut dst = [0u8; 15];
let mut encoder = ISO_2022_JP.new_encoder();
{
let (result, _, _, _) = encoder.encode_from_utf16(&[0xA5u16], &mut dst[..], false);
assert_eq!(result, CoderResult::InputEmpty);
}
{
let (result, _, _, _) = encoder.encode_from_utf16(&[0u16; 0], &mut dst[..8], false);
assert_eq!(result, CoderResult::InputEmpty);
}
{
let (result, _, _, _) = encoder.encode_from_utf16(&[0u16; 0], &mut dst[..8], true);
assert_eq!(result, CoderResult::OutputFull);
}
}
#[test]
fn test_buffer_end_iso_2022_jp_from_utf16() {
let mut dst = [0u8; 17];
{
let mut encoder = ISO_2022_JP.new_encoder();
let (result, _, _, _) = encoder.encode_from_utf16(&[0xA5u16, 0xD83Du16, 0xDCA9u16],
&mut dst[..],
false);
assert_eq!(result, CoderResult::InputEmpty);
}
{
let mut encoder = ISO_2022_JP.new_encoder();
let (result, _, _, _) = encoder.encode_from_utf16(&[0xA5u16, 0xD83Du16, 0xDCA9u16],
&mut dst[..],
true);
assert_eq!(result, CoderResult::OutputFull);
}
{
let mut encoder = ISO_2022_JP.new_encoder();
let (result, _, _, _) = encoder.encode_from_utf16(&[0xD83Du16, 0xDCA9u16],
&mut dst[..12],
false);
assert_eq!(result, CoderResult::InputEmpty);
}
{
let mut encoder = ISO_2022_JP.new_encoder();
let (result, _, _, _) = encoder.encode_from_utf16(&[0xD83Du16, 0xDCA9u16],
&mut dst[..12],
true);
assert_eq!(result, CoderResult::InputEmpty);
}
}
}
+6
View File
@@ -171,6 +171,12 @@ pub enum VariantEncoder {
}
impl VariantEncoder {
pub fn has_pending_state(&self) -> bool {
match *self {
VariantEncoder::Iso2022Jp(ref v) => v.has_pending_state(),
_ => false,
}
}
pub fn max_buffer_length_from_utf16_without_replacement(&self,
u16_length: usize)
-> Option<usize> {