1 #include "core/misc.hpp"
2 #include "core/movie.hpp"
3 #include "core/moviedata.hpp"
4 #include "core/moviefile.hpp"
5 #include "core/moviefile-common.hpp"
6 #include "library/zip.hpp"
7 #include "library/string.hpp"
8 #include "library/minmax.hpp"
9 #include "library/serialization.hpp"
10 #include "library/binarystream.hpp"
11 #include "interface/romtype.hpp"
18 #include <boost/iostreams/copy.hpp>
19 #include <boost/iostreams/device/back_inserter.hpp>
20 #if defined(_WIN32) || defined(_WIN64) || defined(TEST_WIN32_CODE)
26 std::map
<std::string
, uint64_t> read_active_macros(zip::reader
& r
, const std::string
& member
)
28 std::map
<std::string
, uint64_t> x
;
29 if(!r
.has_member(member
))
31 std::istream
& m
= r
[member
];
39 regex_results rx
= regex("([0-9]+) +(.*)", out
);
41 messages
<< "Warning: Bad macro state: '" << out
<< "'" << std::endl
;
45 uint64_t f
= parse_value
<uint64_t>(rx
[1]);
58 void write_active_macros(zip::writer
& w
, const std::string
& member
, const std::map
<std::string
, uint64_t>& ma
)
62 std::ostream
& m
= w
.create_file(member
);
65 m
<< i
.second
<< " " << i
.first
<< std::endl
;
67 throw std::runtime_error("Can't write ZIP file member");
75 template<typename T
> std::string
pick_a_name(const std::map
<std::string
, T
>& map
, bool prefer_unnamed
)
77 if(prefer_unnamed
&& !map
.count(""))
81 std::string c
= (stringfmt() << "(unnamed branch #" << count
++ << ")").str();
87 void write_rrdata(zip::writer
& w
, rrdata_set
& rrd
) throw(std::bad_alloc
, std::runtime_error
)
90 std::vector
<char> out
;
91 count
= rrd
.write(out
);
92 w
.write_raw_file("rrdata", out
);
93 std::ostream
& m2
= w
.create_file("rerecords");
95 m2
<< count
<< std::endl
;
97 throw std::runtime_error("Can't write ZIP file member");
105 void write_authors_file(zip::writer
& w
, std::vector
<std::pair
<std::string
, std::string
>>& authors
)
106 throw(std::bad_alloc
, std::runtime_error
)
108 std::ostream
& m
= w
.create_file("authors");
110 for(auto i
: authors
)
112 m
<< i
.first
<< std::endl
;
114 m
<< i
.first
<< "|" << i
.second
<< std::endl
;
116 throw std::runtime_error("Can't write ZIP file member");
124 void write_input(zip::writer
& w
, const std::string
& mname
, controller_frame_vector
& input
)
125 throw(std::bad_alloc
, std::runtime_error
)
127 std::ostream
& m
= w
.create_file(mname
);
129 char buffer
[MAX_SERIALIZED_SIZE
];
130 for(size_t i
= 0; i
< input
.size(); i
++) {
131 input
[i
].serialize(buffer
);
132 m
<< buffer
<< std::endl
;
135 throw std::runtime_error("Can't write ZIP file member");
143 void write_subtitles(zip::writer
& w
, const std::string
& file
, std::map
<moviefile_subtiming
, std::string
>& x
)
145 std::ostream
& m
= w
.create_file(file
);
148 m
<< i
.first
.get_frame() << " " << i
.first
.get_length() << " " << s_escape(i
.second
)
151 throw std::runtime_error("Can't write ZIP file member");
159 void write_pollcounters(zip::writer
& w
, const std::string
& file
, const std::vector
<uint32_t>& pctr
)
161 std::ostream
& m
= w
.create_file(file
);
164 int32_t x
= i
& 0x7FFFFFFFUL
;
165 if((i
& 0x80000000UL
) == 0)
170 throw std::runtime_error("Can't write ZIP file member");
179 void moviefile::save(zip::writer
& w
, rrdata_set
& rrd
) throw(std::bad_alloc
, std::runtime_error
)
181 w
.write_linefile("gametype", gametype
->get_name());
182 moviefile_write_settings
<zip::writer
>(w
, settings
, gametype
->get_type().get_settings(), [](zip::writer
& w
,
183 const std::string
& name
, const std::string
& value
) -> void {
184 if(regex_match("port[0-9]+", name
))
185 w
.write_linefile(name
, value
);
187 w
.write_linefile("setting." + name
, value
);
189 w
.write_linefile("gamename", gamename
, true);
190 w
.write_linefile("systemid", "lsnes-rr1");
191 w
.write_linefile("controlsversion", "0");
192 coreversion
= gametype
->get_type().get_core_identifier();
193 w
.write_linefile("coreversion", coreversion
);
194 w
.write_linefile("projectid", projectid
);
195 write_rrdata(w
, rrd
);
196 w
.write_linefile("rom.sha256", romimg_sha256
[0], true);
197 w
.write_linefile("romxml.sha256", romxml_sha256
[0], true);
198 w
.write_linefile("rom.hint", namehint
[0], true);
199 for(size_t i
= 1; i
< ROM_SLOT_COUNT
; i
++) {
200 w
.write_linefile((stringfmt() << "slot" << (char)(96 + i
) << ".sha256").str(), romimg_sha256
[i
],
202 w
.write_linefile((stringfmt() << "slot" << (char)(96 + i
) << "xml.sha256").str(), romxml_sha256
[i
],
204 w
.write_linefile((stringfmt() << "slot" << (char)(96 + i
) << ".hint").str(), namehint
[i
],
207 write_subtitles(w
, "subtitles", subtitles
);
208 for(auto i
: movie_sram
)
209 w
.write_raw_file("moviesram." + i
.first
, i
.second
);
210 w
.write_numeric_file("starttime.second", movie_rtc_second
);
211 w
.write_numeric_file("starttime.subsecond", movie_rtc_subsecond
);
212 if(!anchor_savestate
.empty())
213 w
.write_raw_file("savestate.anchor", anchor_savestate
);
215 w
.write_numeric_file("saveframe", save_frame
);
216 w
.write_numeric_file("lagcounter", lagged_frames
);
217 write_pollcounters(w
, "pollcounters", pollcounters
);
218 w
.write_raw_file("hostmemory", host_memory
);
219 w
.write_raw_file("savestate", savestate
);
220 w
.write_raw_file("screenshot", screenshot
);
222 w
.write_raw_file("sram." + i
.first
, i
.second
);
223 w
.write_numeric_file("savetime.second", rtc_second
);
224 w
.write_numeric_file("savetime.subsecond", rtc_subsecond
);
225 w
.write_numeric_file("pollflag", poll_flag
);
226 write_active_macros(w
, "macros", active_macros
);
228 for(auto i
: ramcontent
)
229 w
.write_raw_file("initram." + i
.first
, i
.second
);
230 write_authors_file(w
, authors
);
232 std::map
<std::string
, uint64_t> branch_table
;
233 uint64_t next_branch
= 1;
234 for(auto& i
: branches
) {
236 if(&i
.second
== input
)
240 branch_table
[i
.first
] = id
;
241 w
.write_linefile((stringfmt() << "branchname." << id
).str(), i
.first
);
243 write_input(w
, (stringfmt() << "input." << id
).str(), i
.second
);
245 write_input(w
, "input", i
.second
);