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"
15 #if defined(_WIN32) || defined(_WIN64) || defined(TEST_WIN32_CODE)
21 void write_active_macros(zip::writer
& w
, const std::string
& member
, const std::map
<std::string
, uint64_t>& ma
)
25 std::ostream
& m
= w
.create_file(member
);
28 m
<< i
.second
<< " " << i
.first
<< std::endl
;
30 throw std::runtime_error("Can't write ZIP file member");
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(""))
44 std::string c
= (stringfmt() << "(unnamed branch #" << count
++ << ")").str();
50 void write_rrdata(zip::writer
& w
, rrdata_set
& rrd
)
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");
58 m2
<< count
<< std::endl
;
60 throw std::runtime_error("Can't write ZIP file member");
68 void write_authors_file(zip::writer
& w
, std::vector
<std::pair
<std::string
, std::string
>>& authors
)
70 std::ostream
& m
= w
.create_file("authors");
74 m
<< i
.first
<< std::endl
;
76 m
<< i
.first
<< "|" << i
.second
<< std::endl
;
78 throw std::runtime_error("Can't write ZIP file member");
86 void write_input(zip::writer
& w
, const std::string
& mname
, portctrl::frame_vector
& input
)
88 std::ostream
& m
= w
.create_file(mname
);
90 char buffer
[MAX_SERIALIZED_SIZE
];
91 for(size_t i
= 0; i
< input
.size(); i
++) {
92 input
[i
].serialize(buffer
);
93 m
<< buffer
<< std::endl
;
96 throw std::runtime_error("Can't write ZIP file member");
104 void write_subtitles(zip::writer
& w
, const std::string
& file
, std::map
<moviefile_subtiming
, std::string
>& x
)
106 std::ostream
& m
= w
.create_file(file
);
109 m
<< i
.first
.get_frame() << " " << i
.first
.get_length() << " "
110 << subtitle_commentary::s_escape(i
.second
) << std::endl
;
112 throw std::runtime_error("Can't write ZIP file member");
120 void write_pollcounters(zip::writer
& w
, const std::string
& file
, const std::vector
<uint32_t>& pctr
)
122 std::ostream
& m
= w
.create_file(file
);
125 int32_t x
= i
& 0x7FFFFFFFUL
;
126 if((i
& 0x80000000UL
) == 0)
131 throw std::runtime_error("Can't write ZIP file member");
140 void moviefile::save(zip::writer
& w
, rrdata_set
& rrd
, bool as_state
)
142 w
.write_linefile("gametype", gametype
->get_name());
143 moviefile_write_settings
<zip::writer
>(w
, settings
, gametype
->get_type().get_settings(), [](zip::writer
& w
,
144 const std::string
& name
, const std::string
& value
) -> void {
145 if(regex_match("port[0-9]+", name
))
146 w
.write_linefile(name
, value
);
148 w
.write_linefile("setting." + name
, value
);
150 w
.write_linefile("gamename", gamename
, true);
151 w
.write_linefile("systemid", "lsnes-rr1");
152 w
.write_linefile("controlsversion", "0");
153 coreversion
= gametype
->get_type().get_core_identifier();
154 w
.write_linefile("coreversion", coreversion
);
155 w
.write_linefile("projectid", projectid
);
156 write_rrdata(w
, rrd
);
157 w
.write_linefile("rom.sha256", romimg_sha256
[0], true);
158 w
.write_linefile("romxml.sha256", romxml_sha256
[0], true);
159 w
.write_linefile("rom.hint", namehint
[0], true);
160 for(size_t i
= 1; i
< ROM_SLOT_COUNT
; i
++) {
161 w
.write_linefile((stringfmt() << "slot" << (char)(96 + i
) << ".sha256").str(), romimg_sha256
[i
],
163 w
.write_linefile((stringfmt() << "slot" << (char)(96 + i
) << "xml.sha256").str(), romxml_sha256
[i
],
165 w
.write_linefile((stringfmt() << "slot" << (char)(96 + i
) << ".hint").str(), namehint
[i
],
168 write_subtitles(w
, "subtitles", subtitles
);
169 for(auto i
: movie_sram
)
170 w
.write_raw_file("moviesram." + i
.first
, i
.second
);
171 w
.write_numeric_file("starttime.second", movie_rtc_second
);
172 w
.write_numeric_file("starttime.subsecond", movie_rtc_subsecond
);
173 if(!anchor_savestate
.empty())
174 w
.write_raw_file("savestate.anchor", anchor_savestate
);
176 w
.write_numeric_file("saveframe", dyn
.save_frame
);
177 w
.write_numeric_file("lagcounter", dyn
.lagged_frames
);
178 write_pollcounters(w
, "pollcounters", dyn
.pollcounters
);
179 w
.write_raw_file("hostmemory", dyn
.host_memory
);
180 w
.write_raw_file("savestate", dyn
.savestate
);
181 w
.write_raw_file("screenshot", dyn
.screenshot
);
182 for(auto i
: dyn
.sram
)
183 w
.write_raw_file("sram." + i
.first
, i
.second
);
184 w
.write_numeric_file("savetime.second", dyn
.rtc_second
);
185 w
.write_numeric_file("savetime.subsecond", dyn
.rtc_subsecond
);
186 w
.write_numeric_file("pollflag", dyn
.poll_flag
);
187 write_active_macros(w
, "macros", dyn
.active_macros
);
189 for(auto i
: ramcontent
)
190 w
.write_raw_file("initram." + i
.first
, i
.second
);
191 write_authors_file(w
, authors
);
193 std::map
<std::string
, uint64_t> branch_table
;
194 uint64_t next_branch
= 1;
195 for(auto& i
: branches
) {
197 if(&i
.second
== input
)
201 branch_table
[i
.first
] = id
;
202 w
.write_linefile((stringfmt() << "branchname." << id
).str(), i
.first
);
204 write_input(w
, (stringfmt() << "input." << id
).str(), i
.second
);
206 write_input(w
, "input", i
.second
);