// SPDX-FileCopyrightText: 2026 Filip Leonarski, Paul Scherrer Institute // SPDX-License-Identifier: GPL-3.0-only #include "JFJochCBFReader.h" #include #include #include #include #include #include #include #include #include #include #include "../common/JFJochException.h" #include "../common/Logger.h" #include "../common/JFJochMath.h" namespace { // ".cbf", or ".cbf.gz" - EMBL Hamburg's beamlines write the gzipped form by default, and the // reader decompresses it in place, so a sweep of those is named here rather than converted first. // Returns the suffix that matched, because the sweep template needs its length. std::optional CBFSuffix(const std::filesystem::path &p) { std::string name = p.filename().string(); std::transform(name.begin(), name.end(), name.begin(), [](unsigned char c) { return std::tolower(c); }); for (const char *suffix : {".cbf.gz", ".cbf"}) { const std::string s(suffix); if (name.size() > s.size() && name.compare(name.size() - s.size(), s.size(), s) == 0) return s; } return {}; } bool HasCBFExtension(const std::filesystem::path &p) { return CBFSuffix(p).has_value(); } // The sweep a file belongs to, as a template: everything before the trailing run of digits, the // number of digits, and the extension. "o8_1_0042.cbf" -> {"o8_1_", 4}. A directory can hold several // sweeps ("o8_1_*" beside "o8_2_*"), so collecting every .cbf in it would silently splice two // crystals together; matching the template is what makes "point at any frame" safe. struct Template { std::string prefix; size_t digits = 0; std::string suffix = ".cbf"; // ".cbf" or ".cbf.gz"; the two are not one sweep bool Matches(const std::string &name) const { if (name.size() != prefix.size() + digits + suffix.size()) return false; if (name.compare(0, prefix.size(), prefix) != 0) return false; if (name.compare(prefix.size() + digits, suffix.size(), suffix) != 0) return false; for (size_t i = 0; i < digits; i++) if (!std::isdigit(static_cast(name[prefix.size() + i]))) return false; return true; } }; std::optional