#include "fgc/CameraProfile.h" #include "fgc/Hash.h" #include #include #include #include namespace fs = std::filesystem; namespace fgc { CameraProfile loadCameraProfile(const std::string& profile_dir, const std::string& name, ProfileLoadResult& result) { result = {}; CameraProfile p; p.name = name; p.xml_path = (fs::path(profile_dir) / (name + ".xml")).string(); p.txt_path = (fs::path(profile_dir) / (name + ".txt")).string(); if (!fs::is_regular_file(p.xml_path)) throw std::runtime_error("camera profile '" + name + "': " + p.xml_path + " not found (export it from the VimbaX Viewer)"); const std::string label = hashLabel(fnv1a64File(p.xml_path)); p.settings = parseCameraSettingsXml(p.xml_path); // An absent or stale record is regenerated. Reading the old one first is what // lets the caller report WHICH settings moved, rather than just that the file // changed - that difference is the whole value of the check. const SettingsRecord old = readSettingsRecord(p.txt_path); if (old.hash_label == label) return p; result.regenerated = true; // No previous record means no baseline, not 800 changed settings. result.first_run = old.hash_label.empty() && old.entries.empty(); if (!result.first_run) result.changes = diffSettings(old.entries, p.settings.entries); const std::string xml_name = fs::path(p.xml_path).filename().string(); std::ofstream out(p.txt_path, std::ios::binary | std::ios::trunc); if (!out) throw std::runtime_error("camera profile '" + name + "': cannot write the settings " "record " + p.txt_path); out << renderSettingsRecord(p.settings, xml_name, label); if (!out) throw std::runtime_error("camera profile '" + name + "': failed writing " + p.txt_path); return p; } std::map loadCameraProfiles( const std::string& dir, std::map& results) { results.clear(); std::error_code ec; if (!fs::is_directory(dir, ec)) throw std::runtime_error("camera profile directory not found: " + dir); // Sorted so startup logs and the UI list profiles in a stable order. std::vector names; for (const auto& entry : fs::directory_iterator(dir, ec)) if (entry.is_regular_file() && entry.path().extension() == ".xml") names.push_back(entry.path().stem().string()); std::sort(names.begin(), names.end()); std::map out; for (const auto& n : names) { ProfileLoadResult r; out.emplace(n, loadCameraProfile(dir, n, r)); if (r.regenerated) results.emplace(n, std::move(r)); } if (out.empty()) throw std::runtime_error("no camera profiles (*.xml) in " + dir + " (export them from the VimbaX Viewer)"); return out; } } // namespace fgc