81 lines
3.0 KiB
C++
81 lines
3.0 KiB
C++
#include "fgc/CameraProfile.h"
|
|
|
|
#include "fgc/Hash.h"
|
|
|
|
#include <algorithm>
|
|
#include <filesystem>
|
|
#include <fstream>
|
|
#include <stdexcept>
|
|
|
|
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<std::string, CameraProfile> loadCameraProfiles(
|
|
const std::string& dir, std::map<std::string, ProfileLoadResult>& 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<std::string> 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<std::string, CameraProfile> 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
|