1 #include "core/moviefile-binary.hpp"
2 #include "core/moviefile.hpp"
3 #include "library/serialization.hpp"
7 #if defined(_WIN32) || defined(_WIN64) || defined(TEST_WIN32_CODE)
10 #define EXTRA_OPENFLAGS O_BINARY
12 #define EXTRA_OPENFLAGS 0
17 void emerg_write_bytes(int handle
, const uint8_t* d
, size_t dsize
)
20 ssize_t r
= write(handle
, d
, dsize
);
27 void emerg_write_number(int handle
, uint64_t num
)
32 bool cont
= (num
> 127);
33 data
[len
++] = (cont
? 0x80 : 0x00) | (num
& 0x7F);
36 emerg_write_bytes(handle
, data
, len
);
38 size_t number_size(uint64_t num
)
47 void emerg_write_number32(int handle
, uint32_t num
)
50 serialization::u32b(buf
, num
);
51 emerg_write_bytes(handle
, (const uint8_t*)buf
, 4);
53 void emerg_write_member(int handle
, uint32_t tag
, uint64_t size
)
55 emerg_write_number32(handle
, 0xaddb2d86);
56 emerg_write_number32(handle
, tag
);
57 emerg_write_number(handle
, size
);
59 void emerg_write_blob_implicit(int handle
, const std::vector
<char>& v
)
61 emerg_write_bytes(handle
, (const uint8_t*)&v
[0], v
.size());
63 void emerg_write_byte(int handle
, uint8_t byte
)
65 emerg_write_bytes(handle
, &byte
, 1);
67 size_t string_size(const std::string
& str
)
69 return number_size(str
.length()) + str
.length();
71 void emerg_write_string_implicit(int handle
, const std::string
& str
)
73 for(size_t i
= 0; i
< str
.length(); i
++)
74 emerg_write_byte(handle
, str
[i
]);
76 void emerg_write_string(int handle
, const std::string
& str
)
78 emerg_write_number(handle
, str
.length());
79 emerg_write_string_implicit(handle
, str
);
81 void emerg_write_movie(int handle
, const portctrl::frame_vector
& v
, uint32_t tag
)
83 uint64_t stride
= v
.get_stride();
84 uint64_t pageframes
= v
.get_frames_per_page();
85 uint64_t vsize
= v
.size();
86 emerg_write_member(handle
, tag
, vsize
* stride
);
89 uint64_t count
= (vsize
> pageframes
) ? pageframes
: vsize
;
90 size_t bytes
= count
* stride
;
91 const unsigned char* content
= v
.get_page_buffer(pagenum
++);
92 emerg_write_bytes(handle
, content
, bytes
);
96 uint64_t append_number(char* ptr
, uint64_t n
)
104 for(unsigned i
= digits
; i
> 0; i
--) {
105 ptr
[i
- 1] = (n
% 10) + '0';
112 uint64_t map_index(const std::map
<std::string
, T
>& b
, const std::string
& n
)
120 return 0xFFFFFFFFFFFFFFFFULL
;
124 void emerg_save_movie(const moviefile
& mv
, rrdata_set
& rrd
)
126 //Whee, assume state of the emulator is totally busted.
128 return; //No valid movie. Trying to save would segfault.
129 char header
[] = {'l', 's', 'm', 'v', '\x1a'};
131 char filename_buf
[512];
135 strcpy(filename_buf
+ strlen(filename_buf
), "crashsave-");
136 append_number(filename_buf
+ strlen(filename_buf
), time(NULL
));
137 strcpy(filename_buf
+ strlen(filename_buf
), "-");
138 append_number(filename_buf
+ strlen(filename_buf
), number
++);
139 strcpy(filename_buf
+ strlen(filename_buf
), ".lsmv");
140 fd
= open(filename_buf
, O_WRONLY
| O_CREAT
| O_EXCL
| EXTRA_OPENFLAGS
, 0666);
141 if(fd
< 0 && errno
== EEXIST
) goto name_again
;
142 if(fd
< 0) return; //Can't open.
144 emerg_write_bytes(fd
, (const uint8_t*)header
, sizeof(header
));
145 emerg_write_string(fd
, mv
.gametype
->get_name());
146 for(auto& i
: mv
.settings
) {
147 emerg_write_byte(fd
, 1);
148 emerg_write_string(fd
, i
.first
);
149 emerg_write_string(fd
, i
.second
);
151 emerg_write_byte(fd
, 0);
153 for(auto& i
: mv
.branches
) {
154 emerg_write_member(fd
, TAG_BRANCH_NAME
, i
.first
.length());
155 emerg_write_string_implicit(fd
, i
.first
);
156 emerg_write_movie(fd
, i
.second
, (&i
.second
== mv
.input
) ? TAG_MOVIE
: TAG_BRANCH
);
158 //Movie starting time.
159 emerg_write_member(fd
, TAG_MOVIE_TIME
, number_size(mv
.movie_rtc_second
) +
160 number_size(mv
.movie_rtc_subsecond
));
161 emerg_write_number(fd
, mv
.movie_rtc_second
);
162 emerg_write_number(fd
, mv
.movie_rtc_subsecond
);
164 emerg_write_member(fd
, TAG_PROJECT_ID
, mv
.projectid
.length());
165 emerg_write_string_implicit(fd
, mv
.projectid
);
167 for(auto& i
: mv
.movie_sram
) {
168 emerg_write_member(fd
, TAG_MOVIE_SRAM
, string_size(i
.first
) + i
.second
.size());
169 emerg_write_string(fd
, i
.first
);
170 emerg_write_blob_implicit(fd
, i
.second
);
173 emerg_write_member(fd
, TAG_ANCHOR_SAVE
, mv
.anchor_savestate
.size());
174 emerg_write_blob_implicit(fd
, mv
.anchor_savestate
);
176 emerg_write_member(fd
, TAG_RRDATA
, rrd
.size_emerg());
177 rrdata_set::esave_state estate
;
180 size_t w
= rrd
.write_emerg(estate
, buf
, sizeof(buf
));
182 emerg_write_bytes(fd
, (const uint8_t*)buf
, w
);
185 emerg_write_member(fd
, TAG_CORE_VERSION
, mv
.coreversion
.length());
186 emerg_write_string_implicit(fd
, mv
.coreversion
);
188 for(unsigned i
= 0; i
< ROM_SLOT_COUNT
; i
++) {
189 if(mv
.romimg_sha256
[i
].length()) {
190 emerg_write_member(fd
, TAG_ROMHASH
, mv
.romimg_sha256
[i
].length() + 1);
191 emerg_write_byte(fd
, 2 * i
);
192 emerg_write_string_implicit(fd
, mv
.romimg_sha256
[i
]);
194 if(mv
.romxml_sha256
[i
].length()) {
195 emerg_write_member(fd
, TAG_ROMHASH
, mv
.romxml_sha256
[i
].length() + 1);
196 emerg_write_byte(fd
, 2 * i
+ 1);
197 emerg_write_string_implicit(fd
, mv
.romxml_sha256
[i
]);
199 if(mv
.namehint
[i
].length()) {
200 emerg_write_member(fd
, TAG_ROMHINT
, mv
.namehint
[i
].length() + 1);
201 emerg_write_byte(fd
, i
);
202 emerg_write_string_implicit(fd
, mv
.namehint
[i
]);
206 emerg_write_member(fd
, TAG_GAMENAME
, mv
.gamename
.size());
207 emerg_write_string_implicit(fd
, mv
.gamename
);
209 for(auto& i
: mv
.subtitles
) {
210 emerg_write_member(fd
, TAG_SUBTITLE
, number_size(i
.first
.get_frame()) +
211 number_size(i
.first
.get_length()) + i
.second
.length());
212 emerg_write_number(fd
, i
.first
.get_frame());
213 emerg_write_number(fd
, i
.first
.get_length());
214 emerg_write_string_implicit(fd
, i
.second
);
217 for(auto& i
: mv
.authors
) {
218 emerg_write_member(fd
, TAG_AUTHOR
, string_size(i
.first
) + i
.second
.size());
219 emerg_write_string(fd
, i
.first
);
220 emerg_write_string_implicit(fd
, i
.second
);
224 for(auto& i
: mv
.ramcontent
) {
225 emerg_write_member(fd
, TAG_RAMCONTENT
, string_size(i
.first
) + i
.second
.size());
226 emerg_write_string(fd
, i
.first
);
227 emerg_write_blob_implicit(fd
, i
.second
);