From 1e32f5d480ecefa3a1c8fd1c43ac6b4260459266 Mon Sep 17 00:00:00 2001 From: Rose Hogenson Date: Sat, 13 Jan 2024 12:31:42 -0800 Subject: Reject files with invalid utf-8. It's easier to only support files with valid utf-8. --- src/rope.rs | 99 ++++++++++++++++++++++++++++++++++++++----------------------- 1 file changed, 62 insertions(+), 37 deletions(-) (limited to 'src/rope.rs') diff --git a/src/rope.rs b/src/rope.rs index 4e14d84..ab9a7bc 100644 --- a/src/rope.rs +++ b/src/rope.rs @@ -1,8 +1,23 @@ +use std::error::Error; use std::io::{ErrorKind, Read, Write}; use std::rc::Rc; const MAX_NODE_SIZE: usize = 1024; +fn read(r: &mut dyn Read, buf: &mut [u8]) -> Result { + loop { + match r.read(buf) { + Ok(n) => return Ok(n), + Err(err) => { + if err.kind() == ErrorKind::Interrupted { + continue; + } + return Err(err); + } + } + } +} + enum Insert { Node(Rope), Split(Rope, Rope), @@ -10,16 +25,16 @@ enum Insert { #[derive(Debug, Clone)] struct Leaf { - unsafe_buf: Option>, + unsafe_buf: Option>, start: u16, end: u16, lines: u16, } impl Leaf { - fn bytes(&self) -> &[u8] { + fn buf(&self) -> &str { match &self.unsafe_buf { - None => &[], + None => "", Some(buf) => &buf[usize::from(self.start)..usize::from(self.end)], } } @@ -44,7 +59,7 @@ pub struct Rope(Node); impl Rope { pub fn len(&self) -> usize { match self { - Rope(Node::Leaf(l)) => l.bytes().len(), + Rope(Node::Leaf(l)) => l.buf().len(), Rope(Node::Branch(b)) => b.len, } } @@ -67,12 +82,12 @@ impl Rope { lines: 0, })); - fn leaf(buf: &[u8]) -> Rope { + fn leaf(buf: &str) -> Rope { if buf.len() > MAX_NODE_SIZE { panic!("buffer too long"); } let mut lines = 0; - for &b in buf.iter() { + for &b in buf.as_bytes().iter() { if b == b'\n' { lines += 1; } @@ -108,19 +123,20 @@ impl Rope { fn concat_height(&self, self_height: usize, other: &Rope, other_height: usize) -> Insert { if let (Rope(Node::Leaf(l)), Rope(Node::Leaf(r))) = (self, other) { if self.len() + other.len() <= MAX_NODE_SIZE { - let mut buf = Vec::with_capacity(self.len() + other.len()); - buf.extend_from_slice(l.bytes()); - buf.extend_from_slice(r.bytes()); + let mut buf = String::with_capacity(self.len() + other.len()); + buf.push_str(l.buf()); + buf.push_str(r.buf()); return Insert::Node(Rope::leaf(&buf)); } if self.len() < MAX_NODE_SIZE / 2 || other.len() < MAX_NODE_SIZE / 2 { - let mut buf = Vec::with_capacity(self.len() + other.len()); - buf.extend_from_slice(l.bytes()); - buf.extend_from_slice(r.bytes()); - return Insert::Split( - Rope::leaf(&buf[..buf.len() / 2]), - Rope::leaf(&buf[buf.len() / 2..]), - ); + let mut buf = String::with_capacity(self.len() + other.len()); + buf.push_str(l.buf()); + buf.push_str(r.buf()); + let mut half = buf.len() / 2; + while !buf.is_char_boundary(half) { + half -= 1; + } + return Insert::Split(Rope::leaf(&buf[..half]), Rope::leaf(&buf[half..])); } return Insert::Split(self.clone(), other.clone()); } @@ -203,43 +219,52 @@ impl Rope { } } - pub fn read(r: &mut dyn Read) -> Result { + pub fn read(r: &mut dyn Read) -> Result> { let mut buf = vec![0; MAX_NODE_SIZE]; let mut rope = Rope::EMPTY; + let mut offset = 0; loop { - let n = match r.read(&mut buf) { - Ok(n) => n, + let mut n = read(r, &mut buf[offset..])?; + n += offset; + if n == 0 { + break; + } + let s = match std::str::from_utf8(&buf[..n]) { + Ok(s) => s, Err(err) => { - if err.kind() == ErrorKind::Interrupted { - continue; + let v = err.valid_up_to(); + if v == 0 { + return Err(Box::new(err)); } - return Err(err); + rope = rope.concat(&Rope::leaf( + std::str::from_utf8(&buf[..v]).expect("buf should be valid up to v"), + )); + offset = n - v; + for i in 0..offset { + buf[i] = buf[v + i]; + } + continue; } }; - if n == 0 { - break; - } - rope = rope.concat(&Rope::leaf(&buf[..n])); + rope = rope.concat(&Rope::leaf(s)); + offset = 0; } Ok(rope) } - pub fn new(buf: &[u8]) -> Rope { + pub fn new(buf: &str) -> Rope { if buf.is_empty() { return Rope::EMPTY; } if buf.len() <= MAX_NODE_SIZE { return Rope::leaf(buf); } - let mut buf = buf; - Rope::read(&mut buf).expect("reading from a slice should never fail") + Rope::read(&mut buf.as_bytes()).expect("reading from a slice should never fail") } fn is_char_boundary(&self, i: usize) -> bool { match self { - Rope(Node::Leaf(l)) => { - return i < l.bytes().len() && l.bytes()[i] & 0xc0 != 0x80; - } + Rope(Node::Leaf(l)) => l.buf().is_char_boundary(i), Rope(Node::Branch(b)) => { let mut i = i; for c in b.children.iter() { @@ -248,7 +273,7 @@ impl Rope { } i -= c.len(); } - false + i == 0 } } } @@ -275,7 +300,7 @@ impl Rope { match self { Rope(Node::Leaf(l)) => { let mut count = 0; - for (i, &c) in l.bytes().iter().enumerate() { + for (i, &c) in l.buf().as_bytes().iter().enumerate() { if c != b'\n' { continue; } @@ -317,7 +342,7 @@ impl Rope { pub fn print(&self, w: &mut dyn Write) -> Result<(), std::io::Error> { match self { Rope(Node::Leaf(l)) => { - w.write_all(l.bytes())?; + w.write_all(l.buf().as_bytes())?; Ok(()) } Rope(Node::Branch(b)) => { @@ -349,7 +374,7 @@ impl Rope { match self { Rope(Node::Leaf(l)) => { let mut lines = 0; - for &b in l.bytes()[start..end].iter() { + for &b in l.buf()[start..end].as_bytes().iter() { if b == b'\n' { lines += 1; } @@ -388,7 +413,7 @@ impl Rope { panic!("Index {} out of range 0..{}", i, self.len()); } match self { - Rope(Node::Leaf(l)) => l.bytes()[i], + Rope(Node::Leaf(l)) => l.buf().as_bytes()[i], Rope(Node::Branch(b)) => { let mut i = i; for c in b.children.iter() { -- cgit v1.3.1