Lua: Fix type confusion between signed and unsigned
[lsnes.git] / src / core / mbranch.cpp
blob0cb234eaf266a94946de17fc9249832364d42587
1 #include "core/command.hpp"
2 #include "core/controllerframe.hpp"
3 #include "core/dispatch.hpp"
4 #include "core/emustatus.hpp"
5 #include "core/mbranch.hpp"
6 #include "core/messages.hpp"
7 #include "core/movie.hpp"
8 #include "library/string.hpp"
10 movie_branches::movie_branches(movie_logic& _mlogic, emulator_dispatch& _dispatch, status_updater& _supdater)
11 : mlogic(_mlogic), edispatch(_dispatch), supdater(_supdater)
15 std::string movie_branches::name(const std::string& internal)
17 if(internal != "")
18 return internal;
19 return "(Default branch)";
22 std::set<std::string> movie_branches::enumerate()
24 std::set<std::string> r;
25 if(!mlogic)
26 return r;
27 for(auto& i : mlogic.get_mfile().branches)
28 r.insert(i.first);
29 return r;
32 std::string movie_branches::get()
34 if(!mlogic)
35 return "";
36 return mlogic.get_mfile().current_branch();
39 void movie_branches::set(const std::string& branch)
41 moviefile& mf = mlogic.get_mfile();
42 if(!mlogic.get_movie().readonly_mode())
43 (stringfmt() << "Branches are only switchable in readonly mode.").throwex();
44 if(!mf.branches.count(branch))
45 (stringfmt() << "Branch '" << name(branch) << "' does not exist.").throwex();
46 if(!mlogic.get_movie().compatible(mf.branches[branch]))
47 (stringfmt() << "Branch '" << name(branch) << "' differs in past.").throwex();
48 //Ok, execute the switch.
49 mf.input = &mf.branches[branch];
50 mlogic.get_movie().set_movie_data(mf.input);
51 edispatch.mbranch_change();
52 supdater.update();
53 messages << "Switched to branch '" << name(branch) << "'" << std::endl;
56 void movie_branches::_new(const std::string& branch, const std::string& from)
58 moviefile& mf = mlogic.get_mfile();
59 if(mf.branches.count(branch))
60 (stringfmt() << "Branch '" << name(branch) << "' already exists.").throwex();
61 mf.fork_branch(from, branch);
62 messages << "Created branch '" << name(branch) << "'" << std::endl;
63 edispatch.mbranch_change();
66 void movie_branches::rename(const std::string& oldn, const std::string& newn)
68 moviefile& mf = mlogic.get_mfile();
69 if(oldn == newn)
70 return;
71 if(!mf.branches.count(oldn))
72 (stringfmt() << "Branch '" << name(oldn) << "' does not exist.").throwex();
73 if(mf.branches.count(newn))
74 (stringfmt() << "Branch '" << name(newn) << "' already exists.").throwex();
75 mf.fork_branch(oldn, newn);
76 if(mlogic.get_mfile().current_branch() == oldn) {
77 mf.input = &mf.branches[newn];
78 mlogic.get_movie().set_movie_data(mf.input);
80 mf.branches.erase(oldn);
81 messages << "Renamed branch '" << name(oldn) << "' to '" << name(newn) << "'" << std::endl;
82 edispatch.mbranch_change();
83 supdater.update();
86 void movie_branches::_delete(const std::string& branch)
88 moviefile& mf = mlogic.get_mfile();
89 if(!mf.branches.count(branch))
90 (stringfmt() << "Branch '" << name(branch) << "' does not exist.").throwex();
91 if(mlogic.get_mfile().current_branch() == branch)
92 (stringfmt() << "Can't delete current branch '" << name(branch) << "'.").throwex();
93 mlogic.get_mfile().branches.erase(branch);
94 messages << "Deleted branch '" << name(branch) << "'" << std::endl;
95 edispatch.mbranch_change();
98 std::set<std::string> movie_branches::_movie_branches(const std::string& filename)
100 moviefile::branch_extractor e(filename);
101 return e.enumerate();
104 void movie_branches::import_branch(const std::string& filename, const std::string& ibranch,
105 const std::string& branchname, int mode)
107 auto& mv = mlogic.get_mfile();
108 if(mv.branches.count(branchname) && &mv.branches[branchname] == mv.input)
109 (stringfmt() << "Can't overwrite current branch.").throwex();
111 portctrl::frame_vector v(mv.input->get_types());
112 if(mode == MBRANCH_IMPORT_TEXT || mode == MBRANCH_IMPORT_BINARY) {
113 std::ifstream file(filename, (mode == MBRANCH_IMPORT_BINARY) ? std::ios_base::binary :
114 std::ios_base::in);
115 if(!file)
116 (stringfmt() << "Can't open '" << filename << "' for reading.").throwex();
117 portctrl::frame_vector::notify_freeze freeze(v);
118 if(mode == MBRANCH_IMPORT_BINARY) {
119 uint64_t stride = v.get_stride();
120 uint64_t pageframes = v.get_frames_per_page();
121 uint64_t vsize = 0;
122 size_t pagenum = 0;
123 size_t pagesize = stride * pageframes;
124 while(file) {
125 v.resize(vsize + pageframes);
126 unsigned char* contents = v.get_page_buffer(pagenum++);
127 file.read(reinterpret_cast<char*>(contents), pagesize);
128 vsize += (file.gcount() / stride);
130 v.resize(vsize);
131 v.recount_frames();
132 } else {
133 std::string line;
134 portctrl::frame tmpl = v.blank_frame(false);
135 while(file) {
136 std::getline(file, line);
137 istrip_CR(line);
138 if(line.length() == 0)
139 continue;
140 tmpl.deserialize(line.c_str());
141 v.append(tmpl);
144 } else if(mode == MBRANCH_IMPORT_MOVIE) {
145 moviefile::branch_extractor e(filename);
146 e.read(ibranch, v);
148 bool created = !mv.branches.count(branchname);
149 try {
150 mv.branches[branchname] = v;
151 } catch(...) {
152 if(created)
153 mv.branches.erase(branchname);
157 void movie_branches::export_branch(const std::string& filename, const std::string& branchname, bool binary)
159 auto& mv = mlogic.get_mfile();
160 if(!mv.branches.count(branchname))
161 (stringfmt() << "Branch '" << branchname << "' does not exist.").throwex();
162 auto& v = mv.branches[branchname];
163 std::ofstream file(filename, binary ? std::ios_base::binary : std::ios_base::out);
164 if(!file)
165 (stringfmt() << "Can't open '" << filename << "' for writing.").throwex();
166 if(binary) {
167 uint64_t stride = v.get_stride();
168 uint64_t pageframes = v.get_frames_per_page();
169 uint64_t vsize = v.size();
170 size_t pagenum = 0;
171 while(vsize > 0) {
172 uint64_t count = (vsize > pageframes) ? pageframes : vsize;
173 size_t bytes = count * stride;
174 unsigned char* content = v.get_page_buffer(pagenum++);
175 file.write(reinterpret_cast<char*>(content), bytes);
176 vsize -= count;
178 } else {
179 char buf[MAX_SERIALIZED_SIZE];
180 for(uint64_t i = 0; i < v.size(); i++) {
181 v[i].serialize(buf);
182 file << buf << std::endl;
185 if(!file)
186 (stringfmt() << "Can't write to '" << filename << "'.").throwex();