From 404b233aa8ceb9934146c1f2bb201bae14bd5005 Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Sun, 20 Sep 2026 19:00:58 +0200 Subject: [PATCH] Let format autodetection fail as an answer, not as an exception MarCCD::CanRead and SMV::CanRead read the first plausible file of a directory outside their own try, and the CLI made all three CanRead calls outside the try that reports a bad input. "rugnux " whose alphabetically-first plausible file is unreadable therefore terminated with no message. CanRead now answers false for anything it cannot read, and the CLI asks the question where it can report the answer. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_013nW6FNRP1bBJJ8pfHiByAT --- reader/MarCCD.cpp | 13 +++++++++---- reader/SMV.cpp | 13 +++++++++---- rugnux/rugnux_cli.cpp | 10 +++++++--- 3 files changed, 25 insertions(+), 11 deletions(-) diff --git a/reader/MarCCD.cpp b/reader/MarCCD.cpp index 288d244c1..a5ee68d3a 100644 --- a/reader/MarCCD.cpp +++ b/reader/MarCCD.cpp @@ -251,13 +251,18 @@ std::vector CollectSweep(const std::string &path) { return out; } +// Asked of every input before anything is read, including inputs that are not marCCD at all, so it +// answers a question and never fails: a file it cannot open or make sense of is simply not one of +// ours. The directory arm has to be inside the try as much as the single-file one - it opens the +// first plausible file in the folder, which can be unreadable, and the throw came out of a call site +// that does not catch it, ending the run with no message at all. bool CanRead(const std::string &path) { std::error_code ec; - if (std::filesystem::is_directory(path, ec)) - return !CollectSweep(path).empty(); - if (!PlausibleExtension(std::filesystem::path(path))) - return false; try { + if (std::filesystem::is_directory(path, ec)) + return !CollectSweep(path).empty(); + if (!PlausibleExtension(std::filesystem::path(path))) + return false; return !InstrumentHeader(path).empty(); } catch (const JFJochException &) { return false; diff --git a/reader/SMV.cpp b/reader/SMV.cpp index 405582db1..d818cac6d 100644 --- a/reader/SMV.cpp +++ b/reader/SMV.cpp @@ -222,13 +222,18 @@ std::vector CollectSweep(const std::string &path) { return out; } +// Asked of every input before anything is read, including inputs that are not SMV at all, so it +// answers a question and never fails: a file it cannot open or make sense of is simply not one of +// ours. The directory arm has to be inside the try as much as the single-file one - it opens the +// first plausible file in the folder, which can be unreadable, and the throw came out of a call site +// that does not catch it, ending the run with no message at all. bool CanRead(const std::string &path) { std::error_code ec; - if (std::filesystem::is_directory(path, ec)) - return !CollectSweep(path).empty(); - if (!PlausibleExtension(std::filesystem::path(path))) - return false; try { + if (std::filesystem::is_directory(path, ec)) + return !CollectSweep(path).empty(); + if (!PlausibleExtension(std::filesystem::path(path))) + return false; const auto kv = HeaderBlock(path); return kv.has_value() && kv->count("SIZE1") && kv->count("SIZE2"); } catch (const JFJochException &) { diff --git a/rugnux/rugnux_cli.cpp b/rugnux/rugnux_cli.cpp index 9c10383ec..69cbb1b70 100644 --- a/rugnux/rugnux_cli.cpp +++ b/rugnux/rugnux_cli.cpp @@ -1420,10 +1420,14 @@ static int RunRugnux(int argc, char **argv) { JFJochMarCCDReader marccd_reader; JFJochSMVReader smv_reader; JFJochReader *reader_ptr = nullptr; - const bool input_is_cbf = JFJochCBFReader::CanRead(input_file); - const bool input_is_marccd = !input_is_cbf && JFJochMarCCDReader::CanRead(input_file); - const bool input_is_smv = !input_is_cbf && !input_is_marccd && JFJochSMVReader::CanRead(input_file); + // Which format this is. Asked INSIDE the try: these open and read the file - a directory whose + // first plausible member cannot be read throws here - and an input the program cannot read has to + // come out as the message below, not as an unhandled exception with nothing printed at all. + bool input_is_cbf = false, input_is_marccd = false, input_is_smv = false; try { + input_is_cbf = JFJochCBFReader::CanRead(input_file); + input_is_marccd = !input_is_cbf && JFJochMarCCDReader::CanRead(input_file); + input_is_smv = !input_is_cbf && !input_is_marccd && JFJochSMVReader::CanRead(input_file); if (input_is_cbf) { cbf_reader.ReadFiles(input_file); reader_ptr = &cbf_reader;