1 #include "core/moviefile.hpp"
2 #include "core/moviefile-binary.hpp"
3 #include "library/serialization.hpp"
4 #include "interface/romtype.hpp"
8 #if defined(_WIN32) || defined(_WIN64) || defined(TEST_WIN32_CODE)
10 //FUCK YOU. SERIOUSLY.
11 #define EXTRA_OPENFLAGS O_BINARY
13 #define EXTRA_OPENFLAGS 0
18 void emerg_write_bytes(int handle
, const uint8_t* d
, size_t dsize
)
21 ssize_t r
= write(handle
, d
, dsize
);
28 void emerg_write_number(int handle
, uint64_t num
)
33 bool cont
= (num
> 127);
34 data
[len
++] = (cont
? 0x80 : 0x00) | (num
& 0x7F);
37 emerg_write_bytes(handle
, data
, len
);
39 size_t number_size(uint64_t num
)
48 void emerg_write_number32(int handle
, uint32_t num
)
51 serialization::u32b(buf
, num
);
52 emerg_write_bytes(handle
, (const uint8_t*)buf
, 4);
54 void emerg_write_member(int handle
, uint32_t tag
, uint64_t size
)
56 emerg_write_number32(handle
, 0xaddb2d86);
57 emerg_write_number32(handle
, tag
);
58 emerg_write_number(handle
, size
);
60 void emerg_write_blob_implicit(int handle
, const std::vector
<char>& v
)
62 emerg_write_bytes(handle
, (const uint8_t*)&v
[0], v
.size());
64 void emerg_write_byte(int handle
, uint8_t byte
)
66 emerg_write_bytes(handle
, &byte
, 1);
68 size_t string_size(const std::string
& str
)
70 return number_size(str
.length()) + str
.length();
72 void emerg_write_string_implicit(int handle
, const std::string
& str
)
74 for(size_t i
= 0; i
< str
.length(); i
++)
75 emerg_write_byte(handle
, str
[i
]);
77 void emerg_write_string(int handle
, const std::string
& str
)
79 emerg_write_number(handle
, str
.length());
80 emerg_write_string_implicit(handle
, str
);
82 void emerg_write_movie(int handle
, const controller_frame_vector
& v
, uint32_t tag
)
84 uint64_t stride
= v
.get_stride();
85 uint64_t pageframes
= v
.get_frames_per_page();
86 uint64_t vsize
= v
.size();
87 emerg_write_member(handle
, tag
, vsize
* stride
);
90 uint64_t count
= (vsize
> pageframes
) ? pageframes
: vsize
;
91 size_t bytes
= count
* stride
;
92 const unsigned char* content
= v
.get_page_buffer(pagenum
++);
93 emerg_write_bytes(handle
, content
, bytes
);
97 uint64_t append_number(char* ptr
, uint64_t n
)
105 for(unsigned i
= digits
; i
> 0; i
--) {
106 ptr
[i
- 1] = (n
% 10) + '0';
113 uint64_t map_index(const std::map
<std::string
, T
>& b
, const std::string
& n
)
121 return 0xFFFFFFFFFFFFFFFFULL
;
125 void emerg_save_movie(const moviefile
& mv
, rrdata_set
& rrd
)
127 //Whee, assume state of the emulator is totally busted.
129 return; //No valid movie. Trying to save would segfault.
130 char header
[] = {'l', 's', 'm', 'v', '\x1a'};
132 char filename_buf
[512];
136 strcpy(filename_buf
+ strlen(filename_buf
), "crashsave-");
137 append_number(filename_buf
+ strlen(filename_buf
), time(NULL
));
138 strcpy(filename_buf
+ strlen(filename_buf
), "-");
139 append_number(filename_buf
+ strlen(filename_buf
), number
++);
140 strcpy(filename_buf
+ strlen(filename_buf
), ".lsmv");
141 fd
= open(filename_buf
, O_WRONLY
| O_CREAT
| O_EXCL
| EXTRA_OPENFLAGS
, 0666);
142 if(fd
< 0 && errno
== EEXIST
) goto name_again
;
143 if(fd
< 0) return; //Can't open.
145 emerg_write_bytes(fd
, (const uint8_t*)header
, sizeof(header
));
146 emerg_write_string(fd
, mv
.gametype
->get_name());
147 for(auto& i
: mv
.settings
) {
148 emerg_write_byte(fd
, 1);
149 emerg_write_string(fd
, i
.first
);
150 emerg_write_string(fd
, i
.second
);
152 emerg_write_byte(fd
, 0);
154 for(auto& i
: mv
.branches
) {
155 emerg_write_member(fd
, TAG_BRANCH_NAME
, i
.first
.length());
156 emerg_write_string_implicit(fd
, i
.first
);
157 emerg_write_movie(fd
, i
.second
, (&i
.second
== mv
.input
) ? TAG_MOVIE
: TAG_BRANCH
);
159 //Movie starting time.
160 emerg_write_member(fd
, TAG_MOVIE_TIME
, number_size(mv
.movie_rtc_second
) +
161 number_size(mv
.movie_rtc_subsecond
));
162 emerg_write_number(fd
, mv
.movie_rtc_second
);
163 emerg_write_number(fd
, mv
.movie_rtc_subsecond
);
165 emerg_write_member(fd
, TAG_PROJECT_ID
, mv
.projectid
.length());
166 emerg_write_string_implicit(fd
, mv
.projectid
);
168 for(auto& i
: mv
.movie_sram
) {
169 emerg_write_member(fd
, TAG_MOVIE_SRAM
, string_size(i
.first
) + i
.second
.size());
170 emerg_write_string(fd
, i
.first
);
171 emerg_write_blob_implicit(fd
, i
.second
);
174 emerg_write_member(fd
, TAG_ANCHOR_SAVE
, mv
.anchor_savestate
.size());
175 emerg_write_blob_implicit(fd
, mv
.anchor_savestate
);
177 emerg_write_member(fd
, TAG_RRDATA
, rrd
.size_emerg());
178 rrdata_set::esave_state estate
;
181 size_t w
= rrd
.write_emerg(estate
, buf
, sizeof(buf
));
183 emerg_write_bytes(fd
, (const uint8_t*)buf
, w
);
186 emerg_write_member(fd
, TAG_CORE_VERSION
, mv
.coreversion
.length());
187 emerg_write_string_implicit(fd
, mv
.coreversion
);
189 for(unsigned i
= 0; i
< ROM_SLOT_COUNT
; i
++) {
190 if(mv
.romimg_sha256
[i
].length()) {
191 emerg_write_member(fd
, TAG_ROMHASH
, mv
.romimg_sha256
[i
].length() + 1);
192 emerg_write_byte(fd
, 2 * i
);
193 emerg_write_string_implicit(fd
, mv
.romimg_sha256
[i
]);
195 if(mv
.romxml_sha256
[i
].length()) {
196 emerg_write_member(fd
, TAG_ROMHASH
, mv
.romxml_sha256
[i
].length() + 1);
197 emerg_write_byte(fd
, 2 * i
+ 1);
198 emerg_write_string_implicit(fd
, mv
.romxml_sha256
[i
]);
200 if(mv
.namehint
[i
].length()) {
201 emerg_write_member(fd
, TAG_ROMHINT
, mv
.namehint
[i
].length() + 1);
202 emerg_write_byte(fd
, i
);
203 emerg_write_string_implicit(fd
, mv
.namehint
[i
]);
207 emerg_write_member(fd
, TAG_GAMENAME
, mv
.gamename
.size());
208 emerg_write_string_implicit(fd
, mv
.gamename
);
210 for(auto& i
: mv
.subtitles
) {
211 emerg_write_member(fd
, TAG_SUBTITLE
, number_size(i
.first
.get_frame()) +
212 number_size(i
.first
.get_length()) + i
.second
.length());
213 emerg_write_number(fd
, i
.first
.get_frame());
214 emerg_write_number(fd
, i
.first
.get_length());
215 emerg_write_string_implicit(fd
, i
.second
);
218 for(auto& i
: mv
.authors
) {
219 emerg_write_member(fd
, TAG_AUTHOR
, string_size(i
.first
) + i
.second
.size());
220 emerg_write_string(fd
, i
.first
);
221 emerg_write_string_implicit(fd
, i
.second
);
225 for(auto& i
: mv
.ramcontent
) {
226 emerg_write_member(fd
, TAG_RAMCONTENT
, string_size(i
.first
) + i
.second
.size());
227 emerg_write_string(fd
, i
.first
);
228 emerg_write_blob_implicit(fd
, i
.second
);