1 #include "core/misc.hpp"
2 #include "core/movie.hpp"
3 #include "core/moviedata.hpp"
4 #include "core/moviefile.hpp"
5 #include "core/moviefile-binary.hpp"
6 #include "core/moviefile-common.hpp"
7 #include "library/zip.hpp"
8 #include "library/string.hpp"
9 #include "library/minmax.hpp"
10 #include "library/serialization.hpp"
11 #include "library/binarystream.hpp"
12 #include "interface/romtype.hpp"
17 #if defined(_WIN32) || defined(_WIN64) || defined(TEST_WIN32_CODE)
18 //FUCK YOU. SERIOUSLY.
19 #define EXTRA_OPENFLAGS O_BINARY
21 #define EXTRA_OPENFLAGS 0
24 void moviefile::brief_info::binary_io(int _stream
)
26 binarystream::input
in(_stream
);
27 sysregion
= in
.string();
28 //Discard the settings.
34 {TAG_CORE_VERSION
, [this](binarystream::input
& s
) {
35 this->corename
= s
.string_implicit();
36 }},{TAG_PROJECT_ID
, [this](binarystream::input
& s
) {
37 this->projectid
= s
.string_implicit();
38 }},{TAG_SAVESTATE
, [this](binarystream::input
& s
) {
39 this->current_frame
= s
.number();
40 }},{TAG_RRDATA
, [this](binarystream::input
& s
) {
41 std::vector
<char> c_rrdata
;
42 s
.blob_implicit(c_rrdata
);
43 this->rerecords
= rrdata_set::count(c_rrdata
);
44 }},{TAG_ROMHASH
, [this](binarystream::input
& s
) {
46 std::string h
= s
.string_implicit();
47 if(n
> 2 * ROM_SLOT_COUNT
)
50 this->hashxml
[n
>> 1] = h
;
52 this->hash
[n
>> 1] = h
;
53 }},{TAG_ROMHINT
, [this](binarystream::input
& s
) {
55 std::string h
= s
.string_implicit();
56 if(n
> ROM_SLOT_COUNT
)
60 }, binarystream::null_default
);
63 void moviefile::binary_io(int _stream
, rrdata_set
& rrd
) throw(std::bad_alloc
, std::runtime_error
)
65 binarystream::output
out(_stream
);
66 out
.string(gametype
->get_name());
67 moviefile_write_settings
<binarystream::output
>(out
, settings
, gametype
->get_type().get_settings(),
68 [](binarystream::output
& s
, const std::string
& name
, const std::string
& value
) -> void {
75 out
.extension(TAG_MOVIE_TIME
, [this](binarystream::output
& s
) {
76 s
.number(this->movie_rtc_second
);
77 s
.number(this->movie_rtc_subsecond
);
80 out
.extension(TAG_PROJECT_ID
, [this](binarystream::output
& s
) {
81 s
.string_implicit(this->projectid
);
84 out
.extension(TAG_CORE_VERSION
, [this](binarystream::output
& s
) {
85 this->coreversion
= this->gametype
->get_type().get_core_identifier();
86 s
.string_implicit(this->coreversion
);
89 for(unsigned i
= 0; i
< ROM_SLOT_COUNT
; i
++) {
90 out
.extension(TAG_ROMHASH
, [this, i
](binarystream::output
& s
) {
91 if(!this->romimg_sha256
[i
].length()) return;
93 s
.string_implicit(this->romimg_sha256
[i
]);
95 out
.extension(TAG_ROMHASH
, [this, i
](binarystream::output
& s
) {
96 if(!this->romxml_sha256
[i
].length()) return;
98 s
.string_implicit(this->romxml_sha256
[i
]);
100 out
.extension(TAG_ROMHINT
, [this, i
](binarystream::output
& s
) {
101 if(!this->namehint
[i
].length()) return;
103 s
.string_implicit(this->namehint
[i
]);
107 out
.extension(TAG_RRDATA
, [this, &rrd
](binarystream::output
& s
) {
108 std::vector
<char> _rrd
;
110 s
.blob_implicit(_rrd
);
113 for(auto i
: movie_sram
)
114 out
.extension(TAG_MOVIE_SRAM
, [&i
](binarystream::output
& s
) {
116 s
.blob_implicit(i
.second
);
119 out
.extension(TAG_ANCHOR_SAVE
, [this](binarystream::output
& s
) {
120 s
.blob_implicit(this->anchor_savestate
);
123 out
.extension(TAG_SAVESTATE
, [this](binarystream::output
& s
) {
124 s
.number(this->save_frame
);
125 s
.number(this->lagged_frames
);
126 s
.number(this->rtc_second
);
127 s
.number(this->rtc_subsecond
);
128 s
.number(this->pollcounters
.size());
129 for(auto i
: this->pollcounters
)
131 s
.byte(this->poll_flag
? 0x01 : 0x00);
132 s
.blob_implicit(this->savestate
);
133 }, true, out
.numberbytes(save_frame
) + out
.numberbytes(lagged_frames
) + out
.numberbytes(rtc_second
) +
134 out
.numberbytes(rtc_subsecond
) + out
.numberbytes(pollcounters
.size()) +
135 4 * pollcounters
.size() + 1 + savestate
.size());
137 out
.extension(TAG_HOSTMEMORY
, [this](binarystream::output
& s
) {
138 s
.blob_implicit(this->host_memory
);
141 out
.extension(TAG_SCREENSHOT
, [this](binarystream::output
& s
) {
142 s
.blob_implicit(this->screenshot
);
143 }, true, screenshot
.size());
146 out
.extension(TAG_SAVE_SRAM
, [&i
](binarystream::output
& s
) {
148 s
.blob_implicit(i
.second
);
153 out
.extension(TAG_GAMENAME
, [this](binarystream::output
& s
) {
154 s
.string_implicit(this->gamename
);
157 for(auto i
: subtitles
)
158 out
.extension(TAG_SUBTITLE
, [&i
](binarystream::output
& s
) {
159 s
.number(i
.first
.get_frame());
160 s
.number(i
.first
.get_length());
161 s
.string_implicit(i
.second
);
164 for(auto i
: authors
)
165 out
.extension(TAG_AUTHOR
, [&i
](binarystream::output
& s
) {
167 s
.string_implicit(i
.second
);
170 for(auto i
: active_macros
)
171 out
.extension(TAG_MACRO
, [&i
](binarystream::output
& s
) {
173 s
.string_implicit(i
.first
);
176 for(auto i
: ramcontent
) {
177 out
.extension(TAG_RAMCONTENT
, [&i
](binarystream::output
& s
) {
179 s
.blob_implicit(i
.second
);
183 int64_t next_bnum
= 0;
184 std::map
<std::string
, uint64_t> branch_table
;
185 for(auto& i
: branches
) {
186 branch_table
[i
.first
] = next_bnum
++;
187 out
.extension(TAG_BRANCH_NAME
, [&i
](binarystream::output
& s
) {
188 s
.string_implicit(i
.first
);
189 }, false, i
.first
.length());
190 uint32_t tag
= (&i
.second
== input
) ? TAG_MOVIE
: TAG_BRANCH
;
191 out
.extension(tag
, [&i
](binarystream::output
& s
) {
192 i
.second
.save_binary(s
);
193 }, true, i
.second
.binary_size());
197 void moviefile::binary_io(int _stream
, core_type
& romtype
) throw(std::bad_alloc
, std::runtime_error
)
199 binarystream::input
in(_stream
);
200 std::string tmp
= in
.string();
201 std::string next_branch
;
202 std::map
<uint64_t, std::string
> branch_table
;
203 uint64_t next_bnum
= 0;
205 gametype
= &romtype
.lookup_sysregion(tmp
);
206 } catch(std::bad_alloc
& e
) {
208 } catch(std::exception
& e
) {
209 throw std::runtime_error("Illegal game type '" + tmp
+ "'");
212 std::string name
= in
.string();
213 settings
[name
] = in
.string();
215 auto ctrldata
= gametype
->get_type().controllerconfig(settings
);
216 port_type_set
& ports
= port_type_set::make(ctrldata
.ports
, ctrldata
.portindex());
220 {TAG_ANCHOR_SAVE
, [this](binarystream::input
& s
) {
221 s
.blob_implicit(this->anchor_savestate
);
222 }},{TAG_AUTHOR
, [this](binarystream::input
& s
) {
223 std::string a
= s
.string();
224 std::string b
= s
.string_implicit();
225 this->authors
.push_back(std::make_pair(a
, b
));
226 }},{TAG_CORE_VERSION
, [this](binarystream::input
& s
) {
227 this->coreversion
= s
.string_implicit();
228 }},{TAG_GAMENAME
, [this](binarystream::input
& s
) {
229 this->gamename
= s
.string_implicit();
230 }},{TAG_HOSTMEMORY
, [this](binarystream::input
& s
) {
231 s
.blob_implicit(this->host_memory
);
232 }},{TAG_MACRO
, [this](binarystream::input
& s
) {
233 uint64_t n
= s
.number();
234 this->active_macros
[s
.string_implicit()] = n
;
235 }},{TAG_BRANCH_NAME
, [this, &branch_table
, &next_bnum
, &next_branch
](binarystream::input
& s
) {
236 branch_table
[next_bnum
++] = next_branch
= s
.string_implicit();
237 }},{TAG_MOVIE
, [this, &ports
, &next_branch
](binarystream::input
& s
) {
238 branches
[next_branch
].clear(ports
);
239 branches
[next_branch
].load_binary(s
);
240 input
= &branches
[next_branch
];
241 }},{TAG_BRANCH
, [this, &ports
, &next_branch
](binarystream::input
& s
) {
242 branches
[next_branch
].clear(ports
);
243 branches
[next_branch
].load_binary(s
);
244 }},{TAG_MOVIE_SRAM
, [this](binarystream::input
& s
) {
245 std::string a
= s
.string();
246 s
.blob_implicit(this->movie_sram
[a
]);
247 }},{TAG_RAMCONTENT
, [this](binarystream::input
& s
) {
248 std::string a
= s
.string();
249 s
.blob_implicit(this->ramcontent
[a
]);
250 }},{TAG_MOVIE_TIME
, [this](binarystream::input
& s
) {
251 this->movie_rtc_second
= s
.number();
252 this->movie_rtc_subsecond
= s
.number();
253 }},{TAG_PROJECT_ID
, [this](binarystream::input
& s
) {
254 this->projectid
= s
.string_implicit();
255 }},{TAG_ROMHASH
, [this](binarystream::input
& s
) {
256 uint8_t n
= s
.byte();
257 std::string h
= s
.string_implicit();
258 if(n
> 2 * ROM_SLOT_COUNT
)
261 romxml_sha256
[n
>> 1] = h
;
263 romimg_sha256
[n
>> 1] = h
;
264 }},{TAG_ROMHINT
, [this](binarystream::input
& s
) {
265 uint8_t n
= s
.byte();
266 std::string h
= s
.string_implicit();
267 if(n
> ROM_SLOT_COUNT
)
270 }},{TAG_RRDATA
, [this](binarystream::input
& s
) {
271 s
.blob_implicit(this->c_rrdata
);
272 this->rerecords
= (stringfmt() << rrdata_set::count(c_rrdata
)).str();
273 }},{TAG_SAVE_SRAM
, [this](binarystream::input
& s
) {
274 std::string a
= s
.string();
275 s
.blob_implicit(this->sram
[a
]);
276 }},{TAG_SAVESTATE
, [this](binarystream::input
& s
) {
277 this->is_savestate
= true;
278 this->save_frame
= s
.number();
279 this->lagged_frames
= s
.number();
280 this->rtc_second
= s
.number();
281 this->rtc_subsecond
= s
.number();
282 this->pollcounters
.resize(s
.number());
283 for(auto& i
: this->pollcounters
)
285 this->poll_flag
= (s
.byte() != 0);
286 s
.blob_implicit(this->savestate
);
287 }},{TAG_SCREENSHOT
, [this](binarystream::input
& s
) {
288 s
.blob_implicit(this->screenshot
);
289 }},{TAG_SUBTITLE
, [this](binarystream::input
& s
) {
290 uint64_t f
= s
.number();
291 uint64_t l
= s
.number();
292 std::string x
= s
.string_implicit();
293 this->subtitles
[moviefile_subtiming(f
, l
)] = x
;
295 }, binarystream::null_default
);
297 create_default_branch(ports
);
300 moviefile_branch_extractor_binary::moviefile_branch_extractor_binary(const std::string
& filename
)
302 s
= open(filename
.c_str(), O_RDONLY
| EXTRA_OPENFLAGS
);
305 (stringfmt() << "Can't open file '" << filename
<< "' for reading: " << strerror(err
)).throwex();
309 moviefile_branch_extractor_binary::~moviefile_branch_extractor_binary()
313 std::set
<std::string
> moviefile_branch_extractor_binary::enumerate()
315 std::set
<std::string
> r
;
317 if(lseek(s
, 5, SEEK_SET
) < 0) {
319 (stringfmt() << "Can't read the file: " << strerror(err
)).throwex();
321 binarystream::input
b(s
);
328 //Okay, read the extension packets.
330 {TAG_BRANCH_NAME
, [this, &name
](binarystream::input
& s
) {
331 name
= s
.string_implicit();
332 }},{TAG_MOVIE
, [this, &r
, &name
](binarystream::input
& s
) {
334 }},{TAG_BRANCH
, [this, &r
, &name
](binarystream::input
& s
) {
337 }, binarystream::null_default
);
342 void moviefile_branch_extractor_binary::read(const std::string
& name
, controller_frame_vector
& v
)
345 if(lseek(s
, 5, SEEK_SET
) < 0) {
347 (stringfmt() << "Can't read the file: " << strerror(err
)).throwex();
349 binarystream::input
b(s
);
357 //Okay, read the extension packets.
359 {TAG_BRANCH_NAME
, [this, &mname
](binarystream::input
& s
) {
360 mname
= s
.string_implicit();
361 }},{TAG_MOVIE
, [this, &v
, &mname
, &name
, &done
](binarystream::input
& s
) {
367 }},{TAG_BRANCH
, [this, &v
, &mname
, &name
, &done
](binarystream::input
& s
) {
374 }, binarystream::null_default
);
376 (stringfmt() << "Can't find branch '" << name
<< "' in file.").throwex();