22 std::ifstream input(filename);
24 return absl::NotFoundError(
"Cannot open graphics preview: " + filename);
26 const auto document = nlohmann::json::parse(input);
27 if (document.at(
"schema_version").get<
int>() != 1 ||
28 !document.at(
"areas").is_array()) {
29 return absl::InvalidArgumentError(
"Unsupported graphics preview schema");
31 for (
const auto& area : document.at(
"areas")) {
32 const int parent = area.at(
"parent_map").get<
int>();
33 if (parent < 0 || parent >= 160 || result.contains(parent)) {
34 return absl::InvalidArgumentError(
35 "Invalid or duplicate graphics preview parent_map");
37 const int base = area.at(
"bg_character_base_word").get<
int>();
38 auto& tiles = result[parent];
39 if (!area.at(
"transfers").is_array() || area.at(
"transfers").empty()) {
40 return absl::InvalidArgumentError(
"Graphics preview needs transfers");
42 for (
const auto& transfer : area.at(
"transfers")) {
43 if (transfer.at(
"format").get<std::string>() !=
"snes4bpp") {
44 return absl::InvalidArgumentError(
45 "Graphics preview format must be snes4bpp");
47 const int count = transfer.at(
"byte_count").get<
int>();
48 if (count <= 0 || count > 0x8000 || count % 32 != 0) {
49 return absl::InvalidArgumentError(
50 "Invalid graphics preview byte_count");
52 const auto path = std::filesystem::path(filename).parent_path() /
53 transfer.at(
"path").get<std::string>();
55 const auto size = std::filesystem::file_size(path, ec);
57 return absl::NotFoundError(
"Missing graphics preview asset: " +
59 if (size !=
static_cast<size_t>(count)) {
60 return absl::InvalidArgumentError(
61 "Graphics preview asset has wrong byte count: " + path.string());
63 std::vector<uint8_t> bytes(count);
64 std::ifstream asset(path, std::ios::binary);
65 if (!asset.read(
reinterpret_cast<char*
>(bytes.data()), count)) {
66 return absl::DataLossError(
"Cannot read graphics preview asset: " +
70 bytes, transfer.at(
"vram_word_address").get<
int>(), base);
72 return decoded.status();
73 for (
const auto& [
id, pixels] : *decoded) {
74 if (!tiles.emplace(
id, pixels).second) {
75 return absl::InvalidArgumentError(
76 "Overlapping graphics preview transfers");
81 }
catch (
const nlohmann::json::exception& e) {
82 return absl::InvalidArgumentError(
83 std::string(
"Invalid graphics preview: ") + e.what());