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)
14 void emerg_write_bytes(int handle
, const uint8_t* d
, size_t dsize
)
17 ssize_t r
= write(handle
, d
, dsize
);
24 void emerg_write_number(int handle
, uint64_t num
)
29 bool cont
= (num
> 127);
30 data
[len
++] = (cont
? 0x80 : 0x00) | (num
& 0x7F);
33 emerg_write_bytes(handle
, data
, len
);
35 size_t number_size(uint64_t num
)
44 void emerg_write_number32(int handle
, uint32_t num
)
47 serialization::u32b(buf
, num
);
48 emerg_write_bytes(handle
, (const uint8_t*)buf
, 4);
50 void emerg_write_member(int handle
, uint32_t tag
, uint64_t size
)
52 emerg_write_number32(handle
, 0xaddb2d86);
53 emerg_write_number32(handle
, tag
);
54 emerg_write_number(handle
, size
);
56 void emerg_write_blob_implicit(int handle
, const std::vector
<char>& v
)
58 emerg_write_bytes(handle
, (const uint8_t*)&v
[0], v
.size());
60 void emerg_write_byte(int handle
, uint8_t byte
)
62 emerg_write_bytes(handle
, &byte
, 1);
64 size_t string_size(const std::string
& str
)
66 return number_size(str
.length()) + str
.length();
68 void emerg_write_string_implicit(int handle
, const std::string
& str
)
70 for(size_t i
= 0; i
< str
.length(); i
++)
71 emerg_write_byte(handle
, str
[i
]);
73 void emerg_write_string(int handle
, const std::string
& str
)
75 emerg_write_number(handle
, str
.length());
76 emerg_write_string_implicit(handle
, str
);
78 void emerg_write_movie(int handle
, const controller_frame_vector
& v
, uint32_t tag
)
80 uint64_t pages
= v
.get_page_count();
81 uint64_t stride
= v
.get_stride();
82 uint64_t pageframes
= v
.get_frames_per_page();
83 uint64_t vsize
= v
.size();
84 emerg_write_member(handle
, tag
, vsize
* stride
);
87 uint64_t count
= (vsize
> pageframes
) ? pageframes
: vsize
;
88 size_t bytes
= count
* stride
;
89 const unsigned char* content
= v
.get_page_buffer(pagenum
++);
90 emerg_write_bytes(handle
, content
, bytes
);
94 uint64_t append_number(char* ptr
, uint64_t n
)
102 for(unsigned i
= digits
; i
> 0; i
--) {
103 ptr
[i
- 1] = (n
% 10) + '0';
109 uint64_t map_index(const std::map
<std::string
, T
>& b
, const std::string
& n
)
117 return 0xFFFFFFFFFFFFFFFFULL
;
121 void emerg_save_movie(const moviefile
& mv
, rrdata_set
& rrd
)
123 //Whee, assume state of the emulator is totally busted.
125 return; //No valid movie. Trying to save would segfault.
126 char header
[] = {'l', 's', 'm', 'v', '\x1a'};
128 char filename_buf
[512];
132 strcpy(filename_buf
+ strlen(filename_buf
), "crashsave-");
133 append_number(filename_buf
+ strlen(filename_buf
), time(NULL
));
134 strcpy(filename_buf
+ strlen(filename_buf
), "-");
135 append_number(filename_buf
+ strlen(filename_buf
), number
++);
136 strcpy(filename_buf
+ strlen(filename_buf
), ".lsmv");
137 fd
= open(filename_buf
, O_WRONLY
| O_CREAT
| O_EXCL
, 0666);
138 if(fd
< 0 && errno
== EEXIST
) goto name_again
;
139 if(fd
< 0) return; //Can't open.
141 emerg_write_bytes(fd
, (const uint8_t*)header
, sizeof(header
));
142 emerg_write_string(fd
, mv
.gametype
->get_name());
143 for(auto& i
: mv
.settings
) {
144 emerg_write_byte(fd
, 1);
145 emerg_write_string(fd
, i
.first
);
146 emerg_write_string(fd
, i
.second
);
148 emerg_write_byte(fd
, 0);
150 for(auto& i
: mv
.branches
) {
151 emerg_write_member(fd
, TAG_BRANCH_NAME
, i
.first
.length());
152 emerg_write_string_implicit(fd
, i
.first
);
153 emerg_write_movie(fd
, i
.second
, (&i
.second
== mv
.input
) ? TAG_MOVIE
: TAG_BRANCH
);
155 //Movie starting time.
156 emerg_write_member(fd
, TAG_MOVIE_TIME
, number_size(mv
.movie_rtc_second
) +
157 number_size(mv
.movie_rtc_subsecond
));
158 emerg_write_number(fd
, mv
.movie_rtc_second
);
159 emerg_write_number(fd
, mv
.movie_rtc_subsecond
);
161 emerg_write_member(fd
, TAG_PROJECT_ID
, mv
.projectid
.length());
162 emerg_write_string_implicit(fd
, mv
.projectid
);
164 for(auto& i
: mv
.movie_sram
) {
165 emerg_write_member(fd
, TAG_MOVIE_SRAM
, string_size(i
.first
) + i
.second
.size());
166 emerg_write_string(fd
, i
.first
);
167 emerg_write_blob_implicit(fd
, i
.second
);
170 emerg_write_member(fd
, TAG_ANCHOR_SAVE
, mv
.anchor_savestate
.size());
171 emerg_write_blob_implicit(fd
, mv
.anchor_savestate
);
173 emerg_write_member(fd
, TAG_RRDATA
, rrd
.size_emerg());
174 rrdata_set::esave_state estate
;
177 size_t w
= rrd
.write_emerg(estate
, buf
, sizeof(buf
));
179 emerg_write_bytes(fd
, (const uint8_t*)buf
, w
);
182 emerg_write_member(fd
, TAG_CORE_VERSION
, mv
.coreversion
.length());
183 emerg_write_string_implicit(fd
, mv
.coreversion
);
185 for(unsigned i
= 0; i
< ROM_SLOT_COUNT
; i
++) {
186 if(mv
.romimg_sha256
[i
].length()) {
187 emerg_write_member(fd
, TAG_ROMHASH
, mv
.romimg_sha256
[i
].length() + 1);
188 emerg_write_byte(fd
, 2 * i
);
189 emerg_write_string_implicit(fd
, mv
.romimg_sha256
[i
]);
191 if(mv
.romxml_sha256
[i
].length()) {
192 emerg_write_member(fd
, TAG_ROMHASH
, mv
.romxml_sha256
[i
].length() + 1);
193 emerg_write_byte(fd
, 2 * i
+ 1);
194 emerg_write_string_implicit(fd
, mv
.romxml_sha256
[i
]);
196 if(mv
.namehint
[i
].length()) {
197 emerg_write_member(fd
, TAG_ROMHINT
, mv
.namehint
[i
].length() + 1);
198 emerg_write_byte(fd
, i
);
199 emerg_write_string_implicit(fd
, mv
.namehint
[i
]);
203 emerg_write_member(fd
, TAG_GAMENAME
, mv
.gamename
.size());
204 emerg_write_string_implicit(fd
, mv
.gamename
);
206 for(auto& i
: mv
.subtitles
) {
207 emerg_write_member(fd
, TAG_SUBTITLE
, number_size(i
.first
.get_frame()) +
208 number_size(i
.first
.get_length()) + i
.second
.length());
209 emerg_write_number(fd
, i
.first
.get_frame());
210 emerg_write_number(fd
, i
.first
.get_length());
211 emerg_write_string_implicit(fd
, i
.second
);
214 for(auto& i
: mv
.authors
) {
215 emerg_write_member(fd
, TAG_AUTHOR
, string_size(i
.first
) + i
.second
.size());
216 emerg_write_string(fd
, i
.first
);
217 emerg_write_string_implicit(fd
, i
.second
);
221 for(auto& i
: mv
.ramcontent
) {
222 emerg_write_member(fd
, TAG_RAMCONTENT
, string_size(i
.first
) + i
.second
.size());
223 emerg_write_string(fd
, i
.first
);
224 emerg_write_blob_implicit(fd
, i
.second
);