Lua: Fix type confusion between signed and unsigned
[lsnes.git] / src / core / moviefile-text-save.cpp
blobfe98e69443789673bb13a7f53e5e6b2079dbe9ff
1 #include "core/messages.hpp"
2 #include "core/moviefile-common.hpp"
3 #include "core/moviefile.hpp"
4 #include "library/binarystream.hpp"
5 #include "library/minmax.hpp"
6 #include "library/serialization.hpp"
7 #include "library/string.hpp"
8 #include "library/zip.hpp"
10 #include <fcntl.h>
11 #include <unistd.h>
12 #include <iostream>
13 #include <algorithm>
14 #include <sstream>
15 #if defined(_WIN32) || defined(_WIN64) || defined(TEST_WIN32_CODE)
16 #include <windows.h>
17 #endif
19 namespace
21 void write_active_macros(zip::writer& w, const std::string& member, const std::map<std::string, uint64_t>& ma)
23 if(ma.empty())
24 return;
25 std::ostream& m = w.create_file(member);
26 try {
27 for(auto i : ma)
28 m << i.second << " " << i.first << std::endl;
29 if(!m)
30 throw std::runtime_error("Can't write ZIP file member");
31 w.close_file();
32 } catch(...) {
33 w.close_file();
34 throw;
38 template<typename T> std::string pick_a_name(const std::map<std::string, T>& map, bool prefer_unnamed)
40 if(prefer_unnamed && !map.count(""))
41 return "";
42 size_t count = 1;
43 while(true) {
44 std::string c = (stringfmt() << "(unnamed branch #" << count++ << ")").str();
45 if(!map.count(c))
46 return c;
50 void write_rrdata(zip::writer& w, rrdata_set& rrd) throw(std::bad_alloc, std::runtime_error)
52 uint64_t count;
53 std::vector<char> out;
54 count = rrd.write(out);
55 w.write_raw_file("rrdata", out);
56 std::ostream& m2 = w.create_file("rerecords");
57 try {
58 m2 << count << std::endl;
59 if(!m2)
60 throw std::runtime_error("Can't write ZIP file member");
61 w.close_file();
62 } catch(...) {
63 w.close_file();
64 throw;
68 void write_authors_file(zip::writer& w, std::vector<std::pair<std::string, std::string>>& authors)
69 throw(std::bad_alloc, std::runtime_error)
71 std::ostream& m = w.create_file("authors");
72 try {
73 for(auto i : authors)
74 if(i.second == "")
75 m << i.first << std::endl;
76 else
77 m << i.first << "|" << i.second << std::endl;
78 if(!m)
79 throw std::runtime_error("Can't write ZIP file member");
80 w.close_file();
81 } catch(...) {
82 w.close_file();
83 throw;
87 void write_input(zip::writer& w, const std::string& mname, portctrl::frame_vector& input)
88 throw(std::bad_alloc, std::runtime_error)
90 std::ostream& m = w.create_file(mname);
91 try {
92 char buffer[MAX_SERIALIZED_SIZE];
93 for(size_t i = 0; i < input.size(); i++) {
94 input[i].serialize(buffer);
95 m << buffer << std::endl;
97 if(!m)
98 throw std::runtime_error("Can't write ZIP file member");
99 w.close_file();
100 } catch(...) {
101 w.close_file();
102 throw;
106 void write_subtitles(zip::writer& w, const std::string& file, std::map<moviefile_subtiming, std::string>& x)
108 std::ostream& m = w.create_file(file);
109 try {
110 for(auto i : x)
111 m << i.first.get_frame() << " " << i.first.get_length() << " "
112 << subtitle_commentary::s_escape(i.second) << std::endl;
113 if(!m)
114 throw std::runtime_error("Can't write ZIP file member");
115 w.close_file();
116 } catch(...) {
117 w.close_file();
118 throw;
122 void write_pollcounters(zip::writer& w, const std::string& file, const std::vector<uint32_t>& pctr)
124 std::ostream& m = w.create_file(file);
125 try {
126 for(auto i : pctr) {
127 int32_t x = i & 0x7FFFFFFFUL;
128 if((i & 0x80000000UL) == 0)
129 x = -x - 1;
130 m << x << std::endl;
132 if(!m)
133 throw std::runtime_error("Can't write ZIP file member");
134 w.close_file();
135 } catch(...) {
136 w.close_file();
137 throw;
142 void moviefile::save(zip::writer& w, rrdata_set& rrd, bool as_state) throw(std::bad_alloc, std::runtime_error)
144 w.write_linefile("gametype", gametype->get_name());
145 moviefile_write_settings<zip::writer>(w, settings, gametype->get_type().get_settings(), [](zip::writer& w,
146 const std::string& name, const std::string& value) -> void {
147 if(regex_match("port[0-9]+", name))
148 w.write_linefile(name, value);
149 else
150 w.write_linefile("setting." + name, value);
152 w.write_linefile("gamename", gamename, true);
153 w.write_linefile("systemid", "lsnes-rr1");
154 w.write_linefile("controlsversion", "0");
155 coreversion = gametype->get_type().get_core_identifier();
156 w.write_linefile("coreversion", coreversion);
157 w.write_linefile("projectid", projectid);
158 write_rrdata(w, rrd);
159 w.write_linefile("rom.sha256", romimg_sha256[0], true);
160 w.write_linefile("romxml.sha256", romxml_sha256[0], true);
161 w.write_linefile("rom.hint", namehint[0], true);
162 for(size_t i = 1; i < ROM_SLOT_COUNT; i++) {
163 w.write_linefile((stringfmt() << "slot" << (char)(96 + i) << ".sha256").str(), romimg_sha256[i],
164 true);
165 w.write_linefile((stringfmt() << "slot" << (char)(96 + i) << "xml.sha256").str(), romxml_sha256[i],
166 true);
167 w.write_linefile((stringfmt() << "slot" << (char)(96 + i) << ".hint").str(), namehint[i],
168 true);
170 write_subtitles(w, "subtitles", subtitles);
171 for(auto i : movie_sram)
172 w.write_raw_file("moviesram." + i.first, i.second);
173 w.write_numeric_file("starttime.second", movie_rtc_second);
174 w.write_numeric_file("starttime.subsecond", movie_rtc_subsecond);
175 if(!anchor_savestate.empty())
176 w.write_raw_file("savestate.anchor", anchor_savestate);
177 if(as_state) {
178 w.write_numeric_file("saveframe", dyn.save_frame);
179 w.write_numeric_file("lagcounter", dyn.lagged_frames);
180 write_pollcounters(w, "pollcounters", dyn.pollcounters);
181 w.write_raw_file("hostmemory", dyn.host_memory);
182 w.write_raw_file("savestate", dyn.savestate);
183 w.write_raw_file("screenshot", dyn.screenshot);
184 for(auto i : dyn.sram)
185 w.write_raw_file("sram." + i.first, i.second);
186 w.write_numeric_file("savetime.second", dyn.rtc_second);
187 w.write_numeric_file("savetime.subsecond", dyn.rtc_subsecond);
188 w.write_numeric_file("pollflag", dyn.poll_flag);
189 write_active_macros(w, "macros", dyn.active_macros);
191 for(auto i : ramcontent)
192 w.write_raw_file("initram." + i.first, i.second);
193 write_authors_file(w, authors);
195 std::map<std::string, uint64_t> branch_table;
196 uint64_t next_branch = 1;
197 for(auto& i : branches) {
198 uint64_t id;
199 if(&i.second == input)
200 id = 0;
201 else
202 id = next_branch++;
203 branch_table[i.first] = id;
204 w.write_linefile((stringfmt() << "branchname." << id).str(), i.first);
205 if(id)
206 write_input(w, (stringfmt() << "input." << id).str(), i.second);
207 else
208 write_input(w, "input", i.second);
211 w.commit();