Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion apps/big-search/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ imagesize = { version = "0.14" }
libc = { version = "0.2.186" }
log = { version = "0.4.33" }
notify = { version = "8.2" }
quick-xml = { version = "0.41.0" }
quick-xml = { version = "0.42.0" }
rusqlite = { version = "0.40.1", default-features = false, features = ["cache"] }
serde = { version = "1.0.228", features = ["derive"] }
serde_json = { version = "1.0.150" }
Expand Down
44 changes: 20 additions & 24 deletions apps/big-search/src/extract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -607,10 +607,10 @@ pub fn pages_with(path: &Path, terms: &[String]) -> Vec<usize> {
"pdf" => crate::extract_pdf::for_each_pdf_page(path, &mut |text| pages.test(text)),
"pptx" => for_each_pptx_slide(path, &mut |text| pages.test(text)),
"docx" | "odt" | "ods" | "odp" => {
let (part, break_tag): (&str, &[u8]) = if ext == "docx" {
("word/document.xml", b"w:lastRenderedPageBreak")
let (part, break_tag): (&str, &str) = if ext == "docx" {
("word/document.xml", "w:lastRenderedPageBreak")
} else {
("content.xml", b"text:soft-page-break")
("content.xml", "text:soft-page-break")
};
// No break markers → page layout unknown (the app didn't cache it).
// Report no page rather than guessing "page 1". PDF and PPTX page
Expand Down Expand Up @@ -692,7 +692,7 @@ fn for_each_pptx_slide(path: &Path, on_page: &mut dyn FnMut(&str)) {
fn for_each_office_page(
path: &Path,
part: &str,
break_tag: &[u8],
break_tag: &str,
on_page: &mut dyn FnMut(&str),
) -> bool {
use quick_xml::events::Event;
Expand Down Expand Up @@ -765,16 +765,16 @@ pub(crate) fn zip_entry_bytes(path: &Path, name: &str) -> Option<Vec<u8>> {
}

/// True if `e` is a cached page-break marker or an explicit `w:br w:type="page"`.
fn is_page_break(e: &quick_xml::events::BytesStart, break_tag: &[u8]) -> bool {
fn is_page_break(e: &quick_xml::events::BytesStart, break_tag: &str) -> bool {
let name = e.name();
if name.as_ref() == break_tag {
return true;
}
if name.as_ref() == b"w:br" {
if name.as_ref() == "w:br" {
return e
.attributes()
.flatten()
.any(|a| a.key.as_ref() == b"w:type" && a.value.as_ref() == b"page");
.any(|a| a.key.as_ref() == "w:type" && a.value.as_ref() == "page");
}
false
}
Expand Down Expand Up @@ -806,7 +806,7 @@ pub fn xml_text(xml: &[u8], out: &mut String) {
/// text deleted under change tracking and comments are not the document's text.
pub fn xml_text_lines(xml: &[u8], out: &mut String) {
use quick_xml::events::Event;
let hidden = |name: &[u8]| matches!(name, b"w:instrText" | b"w:delText" | b"office:annotation");
let hidden = |name: &str| matches!(name, "w:instrText" | "w:delText" | "office:annotation");
let mut reader = quick_xml::Reader::from_reader(xml);
let mut buf = Vec::new();
let mut hidden_depth = 0usize;
Expand All @@ -820,15 +820,15 @@ pub fn xml_text_lines(xml: &[u8], out: &mut String) {
if hidden_depth > 0 => {}
Ok(e @ (Event::Text(_) | Event::GeneralRef(_))) => push_xml_text(&e, out),
Ok(Event::End(e)) => match e.name().as_ref() {
b"w:p" | b"text:p" | b"text:h" | b"a:p" => out.push('\n'),
b"w:tc" | b"table:table-cell" => out.push('\t'),
"w:p" | "text:p" | "text:h" | "a:p" => out.push('\n'),
"w:tc" | "table:table-cell" => out.push('\t'),
_ => {}
},
Ok(Event::Empty(e)) => match e.name().as_ref() {
b"w:br" | b"w:cr" | b"text:line-break" => out.push('\n'),
b"w:tab" | b"text:tab" => out.push('\t'),
b"text:s" => out.push(' '),
b"w:p" | b"text:p" | b"text:h" => out.push('\n'),
"w:br" | "w:cr" | "text:line-break" => out.push('\n'),
"w:tab" | "text:tab" => out.push('\t'),
"text:s" => out.push(' '),
"w:p" | "text:p" | "text:h" => out.push('\n'),
_ => {}
},
Ok(Event::Eof) | Err(_) => break,
Expand All @@ -841,22 +841,18 @@ pub fn xml_text_lines(xml: &[u8], out: &mut String) {
/// The text of a text event or an entity reference, appended as written.
///
/// quick-xml reports `&amp;` and `&#243;` as events of their own, between the
/// text around them. Bytes that are not valid UTF-8 are read lossily rather
/// than dropped: an office part is UTF-8 by specification, so this only
/// happens to a damaged file, and a damaged file should still give up whatever
/// text it has.
/// text around them. The reader stops at bytes that are not valid UTF-8; an
/// office part is UTF-8 by specification, so only a damaged file loses the text
/// after the damage.
fn push_xml_text(event: &quick_xml::events::Event<'_>, out: &mut String) {
use quick_xml::events::Event;
match event {
Event::Text(t) => match t.decode() {
Ok(text) => out.push_str(&text),
Err(_) => out.push_str(&String::from_utf8_lossy(t)),
},
Event::Text(t) => out.push_str(t),
Event::GeneralRef(r) => {
if let Ok(Some(c)) = r.resolve_char_ref() {
out.push(c);
} else if let Ok(name) = r.decode() {
out.push_str(match name.as_ref() {
} else {
out.push_str(match &**r {
"amp" => "&",
"lt" => "<",
"gt" => ">",
Expand Down
24 changes: 12 additions & 12 deletions apps/big-search/src/extract/epub.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,15 +67,15 @@ pub(super) fn read_epub(path: &Path) -> Option<(String, Option<String>)> {
}

/// The local name of an XML element, without its namespace prefix.
fn local_name(e: &quick_xml::events::BytesStart<'_>) -> Vec<u8> {
e.local_name().as_ref().to_vec()
fn local_name(e: &quick_xml::events::BytesStart<'_>) -> String {
e.local_name().as_ref().to_owned()
}

fn xml_attribute(e: &quick_xml::events::BytesStart<'_>, name: &[u8]) -> Option<String> {
fn xml_attribute(e: &quick_xml::events::BytesStart<'_>, name: &str) -> Option<String> {
e.attributes()
.flatten()
.find(|a| a.key.local_name().as_ref() == name)
.map(|a| decode_entities(&String::from_utf8_lossy(&a.value)))
.map(|a| decode_entities(&a.value))
}

/// The package document `META-INF/container.xml` points to.
Expand All @@ -85,8 +85,8 @@ fn epub_package(container: &[u8]) -> Option<String> {
let mut buf = Vec::new();
loop {
match reader.read_event_into(&mut buf) {
Ok(Event::Start(e) | Event::Empty(e)) if local_name(&e) == b"rootfile" => {
return xml_attribute(&e, b"full-path");
Ok(Event::Start(e) | Event::Empty(e)) if local_name(&e) == "rootfile" => {
return xml_attribute(&e, "full-path");
}
Ok(Event::Eof) | Err(_) => return None,
_ => {}
Expand All @@ -105,22 +105,22 @@ fn epub_spine(opf: &[u8]) -> (Option<String>, Vec<String>) {
let mut title_text = String::new();
loop {
match reader.read_event_into(&mut buf) {
Ok(Event::Start(e) | Event::Empty(e)) => match local_name(&e).as_slice() {
b"item" => {
Ok(Event::Start(e) | Event::Empty(e)) => match local_name(&e).as_str() {
"item" => {
if let (Some(id), Some(href)) =
(xml_attribute(&e, b"id"), xml_attribute(&e, b"href"))
(xml_attribute(&e, "id"), xml_attribute(&e, "href"))
{
hrefs.insert(id, href);
}
}
b"itemref" => order.extend(xml_attribute(&e, b"idref")),
b"title" if title.is_none() => in_title = true,
"itemref" => order.extend(xml_attribute(&e, "idref")),
"title" if title.is_none() => in_title = true,
_ => {}
},
Ok(e @ (Event::Text(_) | Event::GeneralRef(_))) if in_title => {
push_xml_text(&e, &mut title_text);
}
Ok(Event::End(e)) if in_title && e.local_name().as_ref() == b"title" => {
Ok(Event::End(e)) if in_title && e.local_name().as_ref() == "title" => {
in_title = false;
let text = title_text.trim();
if !text.is_empty() {
Expand Down
Loading