mirror of
https://github.com/storytold/lightcraft.git
synced 2026-10-24 18:18:12 -06:00
LRC-LIB-KEYWORDS: keyword lists LightCraft can't read say what to do
A list saved as UTF-16, as Windows' Notepad can, now says to save it as UTF-8 instead of only "not UTF-8 text". Text passed to keyword.import is capped at 16 MB, like a file. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
91e8a0ac37
commit
68c044990e
@@ -110,6 +110,10 @@ fn read_list(path: &str) -> Result<String> {
|
||||
if bytes.len() as u64 > MAX_LIST_BYTES {
|
||||
return Err(bad("keyword.import", format!("{path}: larger than {} MB, not a keyword list", MAX_LIST_BYTES >> 20)));
|
||||
}
|
||||
// Notepad and some exporters save UTF-16: say how to get the file in, not just that it isn't
|
||||
if bytes.starts_with(&[0xff, 0xfe]) || bytes.starts_with(&[0xfe, 0xff]) {
|
||||
return Err(bad("keyword.import", format!("{path}: UTF-16 text — save it as UTF-8 and import it again")));
|
||||
}
|
||||
String::from_utf8(bytes).map_err(|_| bad("keyword.import", format!("{path}: not UTF-8 text")))
|
||||
}
|
||||
|
||||
@@ -458,6 +462,9 @@ pub fn specs() -> Vec<CommandSpec> {
|
||||
|s, p| {
|
||||
let text = match (str_param(p, "path").map(str::trim).filter(|x| !x.is_empty()), str_param(p, "text")) {
|
||||
(Some(path), _) => read_list(path)?,
|
||||
(None, Some(text)) if text.len() as u64 > MAX_LIST_BYTES => {
|
||||
return Err(bad("keyword.import", format!("larger than {} MB, not a keyword list", MAX_LIST_BYTES >> 20)));
|
||||
}
|
||||
(None, Some(text)) => text.to_string(),
|
||||
(None, None) => return Err(bad("keyword.import", "give `path` or `text`")),
|
||||
};
|
||||
|
||||
@@ -296,6 +296,22 @@ fn exporting_keywords_names_what_the_list_cant_hold() {
|
||||
s.execute("keyword.import", &json!({"text": text})).unwrap();
|
||||
}
|
||||
|
||||
/// A list saved as UTF-16 (as Windows' Notepad can) says to save it as UTF-8, and text too big to
|
||||
/// be a keyword list is refused, as a file that big is.
|
||||
#[test]
|
||||
fn importing_keywords_refuses_what_it_cant_read() {
|
||||
let dir = temp_dir("import-keywords-refused");
|
||||
let mut s = Session::with_demo();
|
||||
let utf16: Vec<u8> = [0xff, 0xfe].into_iter().chain("Travel\r\n".encode_utf16().flat_map(u16::to_le_bytes)).collect();
|
||||
std::fs::write(dir.join("travel.txt"), utf16).unwrap();
|
||||
let err = s.execute("keyword.import", &json!({"path": dir.join("travel.txt").to_string_lossy()})).unwrap_err().to_string();
|
||||
assert!(err.contains("UTF-16") && err.contains("UTF-8"), "{err}");
|
||||
let big = "Travel\n".repeat((17 << 20) / 7);
|
||||
let err = s.execute("keyword.import", &json!({"text": big})).unwrap_err().to_string();
|
||||
assert!(err.contains("16 MB"), "{err}");
|
||||
let _ = std::fs::remove_dir_all(&dir);
|
||||
}
|
||||
|
||||
/// Import Keywords reads a keyword list file (or text) as one undo step and says what it added;
|
||||
/// a file it can't read says which line, and nothing is taken.
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user