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
) throw(std::bad_alloc
, std::runtime_error
)
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
)
69 throw(std::bad_alloc
, std::runtime_error
)
71 std::ostream
& m
= w
.create_file("authors");
75 m
<< i
.first
<< std::endl
;
77 m
<< i
.first
<< "|" << i
.second
<< std::endl
;
79 throw std::runtime_error("Can't write ZIP file member");
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
);
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
;
98 throw std::runtime_error("Can't write ZIP file member");
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
);
111 m
<< i
.first
.get_frame() << " " << i
.first
.get_length() << " "
112 << subtitle_commentary::s_escape(i
.second
) << std::endl
;
114 throw std::runtime_error("Can't write ZIP file member");
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
);
127 int32_t x
= i
& 0x7FFFFFFFUL
;
128 if((i
& 0x80000000UL
) == 0)
133 throw std::runtime_error("Can't write ZIP file member");
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
);
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
],
165 w
.write_linefile((stringfmt() << "slot" << (char)(96 + i
) << "xml.sha256").str(), romxml_sha256
[i
],
167 w
.write_linefile((stringfmt() << "slot" << (char)(96 + i
) << ".hint").str(), namehint
[i
],
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
);
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
) {
199 if(&i
.second
== input
)
203 branch_table
[i
.first
] = id
;
204 w
.write_linefile((stringfmt() << "branchname." << id
).str(), i
.first
);
206 write_input(w
, (stringfmt() << "input." << id
).str(), i
.second
);
208 write_input(w
, "input", i
.second
);