yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
dungeon_room_document_file.cc
Go to the documentation of this file.
2
3#include <algorithm>
4#include <cctype>
5#include <filesystem>
6#include <fstream>
7
9#include "core/project.h"
10#include "util/macro.h"
11
12namespace yaze::editor {
13
14absl::StatusOr<std::string> ReadDungeonRoomDocumentFile(
15 const std::string& path) {
16 std::error_code error;
17 if (!std::filesystem::is_regular_file(path, error) || error) {
18 return absl::InvalidArgumentError("Choose a regular room JSON file.");
19 }
20 std::ifstream file(path, std::ios::binary);
21 if (!file) {
22 return absl::PermissionDeniedError("Cannot open room JSON file.");
23 }
24 // Read at most limit + 1 even if the file grows after opening. Do not allocate
25 // based on an untrusted on-disk size or read a whole oversized file first.
26 std::string json(kMaxDungeonRoomDocumentBytes + 1, '\0');
27 file.read(json.data(), static_cast<std::streamsize>(json.size()));
28 json.resize(static_cast<size_t>(file.gcount()));
29 if (file.bad()) {
30 return absl::DataLossError("Failed to read room JSON file.");
31 }
32 if (json.size() > kMaxDungeonRoomDocumentBytes) {
33 return absl::ResourceExhaustedError(
34 "Room JSON exceeds the 1 MiB document limit.");
35 }
37 return json;
38}
39
40absl::Status WriteDungeonRoomDocumentFile(const std::string& path,
41 const std::string& json) {
42#ifdef __EMSCRIPTEN__
43 return absl::UnimplementedError("Use Copy Room JSON in the browser build.");
44#else
46 std::string extension = std::filesystem::path(path).extension().string();
47 std::transform(
48 extension.begin(), extension.end(), extension.begin(),
49 [](unsigned char c) { return static_cast<char>(std::tolower(c)); });
50 if (extension != ".json") {
51 return absl::InvalidArgumentError(
52 "Save room templates with a .json extension.");
53 }
54 std::error_code error;
55 const auto status = std::filesystem::symlink_status(path, error);
56 if (error && error != std::errc::no_such_file_or_directory) {
57 return absl::PermissionDeniedError("Cannot inspect room JSON destination.");
58 }
59 const bool exists = std::filesystem::exists(status);
60 if (exists) {
61 if (!std::filesystem::is_regular_file(status)) {
62 return absl::InvalidArgumentError(
63 "Cannot replace a directory or symlink.");
64 }
65 if (!ReadDungeonRoomDocumentFile(path).ok()) {
66 return absl::FailedPreconditionError(
67 "The destination is not a valid room template. Choose another file.");
68 }
69 }
70 return project::WriteProjectFileAtomically(path, json, exists);
71#endif
72}
73
74} // namespace yaze::editor
Editors are the view controllers for the application.
absl::Status WriteDungeonRoomDocumentFile(const std::string &path, const std::string &json)
absl::StatusOr< DungeonRoomDocument > ParseDungeonRoomDocument(const std::string &json)
absl::StatusOr< std::string > ReadDungeonRoomDocumentFile(const std::string &path)
constexpr size_t kMaxDungeonRoomDocumentBytes
absl::Status WriteProjectFileAtomically(absl::string_view target_path, absl::string_view contents, bool replace_existing)
Definition project.cc:387
#define RETURN_IF_ERROR(expr)
Definition snes.cc:22