1 /* szx.c: Routines for .szx snapshots
2 Copyright (c) 1998-2012 Philip Kendall, Fredrick Meunier, Stuart Brady
3
4 $Id: szx.c 4904 2013-03-08 20:21:02Z pak21 $
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License along
17 with this program; if not, write to the Free Software Foundation, Inc.,
18 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
20 Author contact information:
21
22 E-mail: philip-fuse@shadowmagic.org.uk
23
24 */
25
26 #include <config.h>
27
28 #include <string.h>
29
30 #include "internals.h"
31
32 /* Used for passing internal data around */
33
34 typedef struct szx_context {
35
36 int swap_af;
37
38 } szx_context;
39
40 /* The machine numbers used in the .szx format */
41
42 typedef enum szx_machine_type {
43
44 SZX_MACHINE_16 = 0,
45 SZX_MACHINE_48,
46 SZX_MACHINE_128,
47 SZX_MACHINE_PLUS2,
48 SZX_MACHINE_PLUS2A,
49 SZX_MACHINE_PLUS3,
50 SZX_MACHINE_PLUS3E,
51 SZX_MACHINE_PENTAGON,
52 SZX_MACHINE_TC2048,
53 SZX_MACHINE_TC2068,
54 SZX_MACHINE_SCORPION,
55 SZX_MACHINE_SE,
56 SZX_MACHINE_TS2068,
57 SZX_MACHINE_PENTAGON512,
58 SZX_MACHINE_PENTAGON1024,
59 SZX_MACHINE_48_NTSC,
60 SZX_MACHINE_128KE,
61
62 } szx_machine_type;
63
64 static const char *signature = "ZXST";
65 static const size_t signature_length = 4;
66
67 static const libspectrum_byte ZXSTMF_ALTERNATETIMINGS = 1;
68
69 static const char *libspectrum_string = "libspectrum: ";
70
71 static const libspectrum_byte SZX_VERSION_MAJOR = 1;
72 static const libspectrum_byte SZX_VERSION_MINOR = 5;
73
74 /* Constants etc for each chunk type */
75
76 #define ZXSTBID_CREATOR "CRTR"
77
78 #define ZXSTBID_Z80REGS "Z80R"
79 static const libspectrum_byte ZXSTZF_EILAST = 1;
80 static const libspectrum_byte ZXSTZF_HALTED = 2;
81 static const libspectrum_byte ZXSTZF_FSET = 4;
82
83 #define ZXSTBID_SPECREGS "SPCR"
84
85 #define ZXSTBID_RAMPAGE "RAMP"
86 static const libspectrum_word ZXSTRF_COMPRESSED = 1;
87
88 #define ZXSTBID_AY "AY\0\0"
89 static const libspectrum_byte ZXSTAYF_FULLERBOX = 1;
90 static const libspectrum_byte ZXSTAYF_128AY = 2;
91
92 #define ZXSTBID_MULTIFACE "MFCE"
93 #define ZXSTBID_USPEECH "USPE"
94 #define ZXSTBID_SPECDRUM "DRUM"
95 #define ZXSTBID_ZXTAPE "TAPE"
96
97 #define ZXSTBID_KEYBOARD "KEYB"
98 static const libspectrum_dword ZXSTKF_ISSUE2 = 1;
99
100 #define ZXSTBID_JOYSTICK "JOY\0"
101 static const libspectrum_dword ZXSTJOYF_ALWAYSPORT31 = 1;
102
103 typedef enum szx_joystick_type {
104
105 ZXJT_KEMPSTON = 0,
106 ZXJT_FULLER,
107 ZXJT_CURSOR,
108 ZXJT_SINCLAIR1,
109 ZXJT_SINCLAIR2,
110 ZXJT_SPECTRUMPLUS,
111 ZXJT_TIMEX1,
112 ZXJT_TIMEX2,
113 ZXJT_NONE,
114
115 } szx_joystick_type;
116
117 #define ZXSTBID_IF2ROM "IF2R"
118
119 #define ZXSTBID_MOUSE "AMXM"
120 typedef enum szx_mouse_type {
121
122 ZXSTM_NONE = 0,
123 ZXSTM_AMX,
124 ZXSTM_KEMPSTON,
125
126 } szx_mouse_type;
127
128 #define ZXSTBID_ROM "ROM\0"
129
130 #define ZXSTBID_ZXPRINTER "ZXPR"
131 static const libspectrum_word ZXSTPRF_ENABLED = 1;
132
133 #define ZXSTBID_IF1 "IF1\0"
134 static const libspectrum_word ZXSTIF1F_ENABLED = 1;
135 static const libspectrum_word ZXSTIF1F_COMPRESSED = 2;
136 static const libspectrum_word ZXSTIF1F_PAGED = 4;
137
138 #define ZXSTBID_MICRODRIVE "MDRV"
139 #define ZXSTBID_PLUS3DISK "+3\0\0"
140 #define ZXSTBID_DSKFILE "DSK\0"
141 #define ZXSTBID_LEC "LEC\0"
142 static const libspectrum_word ZXSTLECF_PAGED = 1;
143
144 #define ZXSTBID_LECRAMPAGE "LCRP"
145 static const libspectrum_word ZXSTLCRPF_COMPRESSED = 1;
146
147 #define ZXSTBID_TIMEXREGS "SCLD"
148
149 #define ZXSTBID_BETA128 "B128"
150 static const libspectrum_dword ZXSTBETAF_CONNECTED = 1;
151 static const libspectrum_dword ZXSTBETAF_CUSTOMROM = 2;
152 static const libspectrum_dword ZXSTBETAF_PAGED = 4;
153 static const libspectrum_dword ZXSTBETAF_AUTOBOOT = 8;
154 static const libspectrum_dword ZXSTBETAF_SEEKLOWER = 16;
155 static const libspectrum_dword ZXSTBETAF_COMPRESSED = 32;
156
157 #define ZXSTBID_BETADISK "BDSK"
158 #define ZXSTBID_GS "GS\0\0"
159 #define ZXSTBID_GSRAMPAGE "GSRP"
160 #define ZXSTBID_COVOX "COVX"
161
162 #define ZXSTBID_DOCK "DOCK"
163 static const libspectrum_word ZXSTDOCKF_RAM = 2;
164 static const libspectrum_word ZXSTDOCKF_EXROMDOCK = 4;
165
166 #define ZXSTBID_ZXATASP "ZXAT"
167 static const libspectrum_word ZXSTZXATF_UPLOAD = 1;
168 static const libspectrum_word ZXSTZXATF_WRITEPROTECT = 2;
169
170 #define ZXSTBID_ZXATASPRAMPAGE "ATRP"
171
172 #define ZXSTBID_ZXCF "ZXCF"
173 static const libspectrum_word ZXSTZXCFF_UPLOAD = 1;
174
175 #define ZXSTBID_ZXCFRAMPAGE "CFRP"
176
177 #define ZXSTBID_PLUSD "PLSD"
178 static const libspectrum_dword ZXSTPLUSDF_PAGED = 1;
179 static const libspectrum_dword ZXSTPLUSDF_COMPRESSED = 2;
180 static const libspectrum_dword ZXSTPLUSDF_SEEKLOWER = 4;
181 static const libspectrum_byte ZXSTPDRT_GDOS = 0;
182 static const libspectrum_byte ZXSTPDRT_UNIDOS = 1;
183 static const libspectrum_byte ZXSTPDRT_CUSTOM = 2;
184
185 #define ZXSTBID_PLUSDDISK "PDSK"
186
187 #define ZXSTBID_OPUS "OPUS"
188 static const libspectrum_dword ZXSTOPUSF_PAGED = 1;
189 static const libspectrum_dword ZXSTOPUSF_COMPRESSED = 2;
190 static const libspectrum_dword ZXSTOPUSF_SEEKLOWER = 4;
191 static const libspectrum_dword ZXSTOPUSF_CUSTOMROM = 8;
192
193 #define ZXSTBID_OPUSDISK "ODSK"
194
195 #define ZXSTBID_SIMPLEIDE "SIDE"
196 static const libspectrum_word ZXSTSIDE_ENABLED = 1;
197
198 #define ZXSTBID_DIVIDE "DIDE"
199 static const libspectrum_word ZXSTDIVIDE_EPROM_WRITEPROTECT = 1;
200 static const libspectrum_word ZXSTDIVIDE_PAGED = 2;
201 static const libspectrum_word ZXSTDIVIDE_COMPRESSED = 4;
202
203 #define ZXSTBID_DIVIDERAMPAGE "DIRP"
204
205 #define ZXSTBID_SPECTRANET "SNET"
206 static const libspectrum_word ZXSTSNET_PAGED = 1;
207 static const libspectrum_word ZXSTSNET_PAGED_VIA_IO = 2;
208 static const libspectrum_word ZXSTSNET_PROGRAMMABLE_TRAP_ACTIVE = 4;
209 static const libspectrum_word ZXSTSNET_PROGRAMMABLE_TRAP_MSB = 8;
210 static const libspectrum_word ZXSTSNET_ALL_DISABLED = 16;
211 static const libspectrum_word ZXSTSNET_RST8_DISABLED = 32;
212 static const libspectrum_word ZXSTSNET_DENY_DOWNSTREAM_A15 = 64;
213 static const libspectrum_word ZXSTSNET_NMI_FLIPFLOP = 128;
214
215 #define ZXSTBID_SPECTRANETFLASHPAGE "SNEF"
216 static const libspectrum_byte ZXSTSNEF_FLASH_COMPRESSED = 1;
217
218 #define ZXSTBID_SPECTRANETRAMPAGE "SNER"
219 static const libspectrum_byte ZXSTSNER_RAM_COMPRESSED = 1;
220
221 static libspectrum_error
222 read_chunk( libspectrum_snap *snap, libspectrum_word version,
223 const libspectrum_byte **buffer, const libspectrum_byte *end,
224 szx_context *ctx );
225
226 typedef libspectrum_error (*read_chunk_fn)( libspectrum_snap *snap,
227 libspectrum_word version,
228 const libspectrum_byte **buffer,
229 const libspectrum_byte *end,
230 size_t data_length,
231 szx_context *ctx );
232
233 static libspectrum_error
234 write_file_header( libspectrum_byte **buffer, libspectrum_byte **ptr,
235 size_t *length, int *out_flags, libspectrum_snap *snap );
236
237 static libspectrum_error
238 write_crtr_chunk( libspectrum_byte **bufer, libspectrum_byte **ptr,
239 size_t *length, libspectrum_creator *creator );
240 static libspectrum_error
241 write_z80r_chunk( libspectrum_byte **buffer, libspectrum_byte **ptr,
242 size_t *length, libspectrum_snap *snap );
243 static libspectrum_error
244 write_spcr_chunk( libspectrum_byte **buffer, libspectrum_byte **ptr,
245 size_t *length, libspectrum_snap *snap );
246 static libspectrum_error
247 write_amxm_chunk( libspectrum_byte **buffer, libspectrum_byte **ptr,
248 size_t *length, libspectrum_snap *snap );
249 static libspectrum_error
250 write_joy_chunk( libspectrum_byte **buffer, libspectrum_byte **ptr,
251 size_t *length, int *out_flags, libspectrum_snap *snap );
252 static libspectrum_error
253 write_keyb_chunk( libspectrum_byte **buffer, libspectrum_byte **ptr,
254 size_t *length, int *out_flags, libspectrum_snap *snap );
255 static libspectrum_error
256 write_ram_pages( libspectrum_byte **buffer, libspectrum_byte **ptr,
257 size_t *length, libspectrum_snap *snap, int compress );
258 static libspectrum_error
259 write_ramp_chunk( libspectrum_byte **buffer, libspectrum_byte **ptr,
260 size_t *length, libspectrum_snap *snap, int page,
261 int compress );
262 static libspectrum_error
263 write_ram_page( libspectrum_byte **buffer, libspectrum_byte **ptr,
264 size_t *length, const char *id, const libspectrum_byte *data,
265 size_t data_length, int page, int compress, int extra_flags );
266 static libspectrum_error
267 write_rom_chunk( libspectrum_byte **buffer, libspectrum_byte **ptr,
268 size_t *length, int *out_flags, libspectrum_snap *snap,
269 int compress );
270 static libspectrum_error
271 write_ay_chunk( libspectrum_byte **buffer, libspectrum_byte **ptr,
272 size_t *length, libspectrum_snap *snap );
273 static libspectrum_error
274 write_scld_chunk( libspectrum_byte **buffer, libspectrum_byte **ptr,
275 size_t *length, libspectrum_snap *snap );
276 static libspectrum_error
277 write_b128_chunk( libspectrum_byte **buffer, libspectrum_byte **ptr,
278 size_t *length, libspectrum_snap *snap, int compress );
279 static libspectrum_error
280 write_opus_chunk( libspectrum_byte **buffer, libspectrum_byte **ptr,
281 size_t *length, libspectrum_snap *snap, int compress );
282 static libspectrum_error
283 write_plsd_chunk( libspectrum_byte **buffer, libspectrum_byte **ptr,
284 size_t *length, libspectrum_snap *snap, int compress );
285 static libspectrum_error
286 write_if1_chunk( libspectrum_byte **buffer, libspectrum_byte **ptr,
287 size_t *length, libspectrum_snap *snap, int compress );
288 static libspectrum_error
289 write_zxat_chunk( libspectrum_byte **buffer, libspectrum_byte **ptr,
290 size_t *length, libspectrum_snap *snap );
291 static libspectrum_error
292 write_atrp_chunk( libspectrum_byte **buffer, libspectrum_byte **ptr,
293 size_t *length, libspectrum_snap *snap, int page,
294 int compress );
295 static libspectrum_error
296 write_zxcf_chunk( libspectrum_byte **buffer, libspectrum_byte **ptr,
297 size_t *length, libspectrum_snap *snap );
298 static libspectrum_error
299 write_cfrp_chunk( libspectrum_byte **buffer, libspectrum_byte **ptr,
300 size_t *length, libspectrum_snap *snap, int page,
301 int compress );
302 static libspectrum_error
303 write_side_chunk( libspectrum_byte **buffer, libspectrum_byte **ptr,
304 size_t *length, libspectrum_snap *snap );
305 static libspectrum_error
306 write_drum_chunk( libspectrum_byte **buffer, libspectrum_byte **ptr,
307 size_t *length, libspectrum_snap *snap );
308 static libspectrum_error
309 write_snet_chunk( libspectrum_byte **buffer, libspectrum_byte **ptr,
310 size_t *length, libspectrum_snap *snap, int compress );
311 static libspectrum_error
312 write_snef_chunk( libspectrum_byte **buffer, libspectrum_byte **ptr,
313 size_t *length, libspectrum_snap *snap, int compress );
314 static libspectrum_error
315 write_sner_chunk( libspectrum_byte **buffer, libspectrum_byte **ptr,
316 size_t *length, libspectrum_snap *snap, int compress );
317
318 #ifdef HAVE_ZLIB_H
319
320 static libspectrum_error
321 write_if2r_chunk( libspectrum_byte **buffer, libspectrum_byte **ptr,
322 size_t *length, libspectrum_snap *snap );
323
324 #endif /* #ifdef HAVE_ZLIB_H */
325
326 static libspectrum_error
327 write_dock_chunk( libspectrum_byte **buffer, libspectrum_byte **ptr,
328 size_t *length, libspectrum_snap *snap, int exrom_dock,
329 const libspectrum_byte *data, int page, int writeable,
330 int compress );
331 static libspectrum_error
332 write_dide_chunk( libspectrum_byte **buffer, libspectrum_byte **ptr,
333 size_t *length, libspectrum_snap *snap, int compress );
334 static libspectrum_error
335 write_dirp_chunk( libspectrum_byte **buffer, libspectrum_byte **ptr,
336 size_t *length, libspectrum_snap *snap, int page,
337 int compress );
338 static libspectrum_error
339 write_zxpr_chunk( libspectrum_byte **buffer, libspectrum_byte **ptr,
340 size_t *length, int *out_flags, libspectrum_snap *snap );
341
342 static void
343 write_chunk_header( libspectrum_byte **buffer, libspectrum_byte **ptr,
344 size_t *length, const char *id,
345 libspectrum_dword block_length );
346
347 static libspectrum_error
read_ram_page(libspectrum_byte ** data,size_t * page,const libspectrum_byte ** buffer,size_t data_length,size_t uncompressed_length,libspectrum_word * flags)348 read_ram_page( libspectrum_byte **data, size_t *page,
349 const libspectrum_byte **buffer, size_t data_length,
350 size_t uncompressed_length, libspectrum_word *flags )
351 {
352 #ifdef HAVE_ZLIB_H
353
354 libspectrum_error error;
355
356 #endif /* #ifdef HAVE_ZLIB_H */
357
358 if( data_length < 3 ) {
359 libspectrum_print_error( LIBSPECTRUM_ERROR_UNKNOWN,
360 "%s:read_ram_page: length %lu too short",
361 __FILE__, (unsigned long)data_length );
362 return LIBSPECTRUM_ERROR_UNKNOWN;
363 }
364
365 *flags = libspectrum_read_word( buffer );
366
367 *page = **buffer; (*buffer)++;
368
369 if( *flags & ZXSTRF_COMPRESSED ) {
370
371 #ifdef HAVE_ZLIB_H
372
373 error = libspectrum_zlib_inflate( *buffer, data_length - 3, data,
374 &uncompressed_length );
375 if( error ) return error;
376
377 *buffer += data_length - 3;
378
379 #else /* #ifdef HAVE_ZLIB_H */
380
381 libspectrum_print_error(
382 LIBSPECTRUM_ERROR_UNKNOWN,
383 "%s:read_ram_page: zlib needed for decompression\n",
384 __FILE__
385 );
386 return LIBSPECTRUM_ERROR_UNKNOWN;
387
388 #endif /* #ifdef HAVE_ZLIB_H */
389
390 } else {
391
392 if( data_length < 3 + uncompressed_length ) {
393 libspectrum_print_error( LIBSPECTRUM_ERROR_UNKNOWN,
394 "%s:read_ram_page: length %lu too short",
395 __FILE__, (unsigned long)data_length );
396 return LIBSPECTRUM_ERROR_UNKNOWN;
397 }
398
399 *data = libspectrum_malloc( uncompressed_length * sizeof( **data ) );
400 memcpy( *data, *buffer, uncompressed_length );
401 *buffer += uncompressed_length;
402
403 }
404
405 return LIBSPECTRUM_ERROR_NONE;
406 }
407
408 static libspectrum_error
read_atrp_chunk(libspectrum_snap * snap,libspectrum_word version GCC_UNUSED,const libspectrum_byte ** buffer,const libspectrum_byte * end GCC_UNUSED,size_t data_length,szx_context * ctx GCC_UNUSED)409 read_atrp_chunk( libspectrum_snap *snap, libspectrum_word version GCC_UNUSED,
410 const libspectrum_byte **buffer,
411 const libspectrum_byte *end GCC_UNUSED, size_t data_length,
412 szx_context *ctx GCC_UNUSED )
413 {
414 libspectrum_byte *data;
415 size_t page;
416 libspectrum_error error;
417 libspectrum_word flags;
418
419 error = read_ram_page( &data, &page, buffer, data_length, 0x4000, &flags );
420 if( error ) return error;
421
422 if( page >= SNAPSHOT_ZXATASP_PAGES ) {
423 libspectrum_print_error( LIBSPECTRUM_ERROR_CORRUPT,
424 "%s:read_atrp_chunk: unknown page number %lu",
425 __FILE__, (unsigned long)page );
426 libspectrum_free( data );
427 return LIBSPECTRUM_ERROR_CORRUPT;
428 }
429
430 libspectrum_snap_set_zxatasp_ram( snap, page, data );
431
432 return LIBSPECTRUM_ERROR_NONE;
433 }
434
435 static libspectrum_error
read_ay_chunk(libspectrum_snap * snap,libspectrum_word version GCC_UNUSED,const libspectrum_byte ** buffer,const libspectrum_byte * end GCC_UNUSED,size_t data_length,szx_context * ctx GCC_UNUSED)436 read_ay_chunk( libspectrum_snap *snap, libspectrum_word version GCC_UNUSED,
437 const libspectrum_byte **buffer,
438 const libspectrum_byte *end GCC_UNUSED, size_t data_length,
439 szx_context *ctx GCC_UNUSED )
440 {
441 size_t i;
442 libspectrum_byte flags;
443
444 if( data_length != 18 ) {
445 libspectrum_print_error( LIBSPECTRUM_ERROR_UNKNOWN,
446 "szx_read_ay_chunk: unknown length %lu",
447 (unsigned long)data_length );
448 return LIBSPECTRUM_ERROR_UNKNOWN;
449 }
450
451 flags = **buffer; (*buffer)++;
452 libspectrum_snap_set_fuller_box_active( snap, flags & ZXSTAYF_FULLERBOX );
453 libspectrum_snap_set_melodik_active( snap, !!( flags & ZXSTAYF_128AY ) );
454
455 libspectrum_snap_set_out_ay_registerport( snap, **buffer ); (*buffer)++;
456
457 for( i = 0; i < 16; i++ ) {
458 libspectrum_snap_set_ay_registers( snap, i, **buffer ); (*buffer)++;
459 }
460
461 return LIBSPECTRUM_ERROR_NONE;
462 }
463
464 static libspectrum_error
read_b128_chunk(libspectrum_snap * snap,libspectrum_word version GCC_UNUSED,const libspectrum_byte ** buffer,const libspectrum_byte * end GCC_UNUSED,size_t data_length,szx_context * ctx GCC_UNUSED)465 read_b128_chunk( libspectrum_snap *snap, libspectrum_word version GCC_UNUSED,
466 const libspectrum_byte **buffer,
467 const libspectrum_byte *end GCC_UNUSED, size_t data_length,
468 szx_context *ctx GCC_UNUSED )
469 {
470 #ifdef HAVE_ZLIB_H
471 libspectrum_error error;
472 #endif
473 libspectrum_byte *rom_data = NULL;
474 libspectrum_dword flags;
475 const size_t expected_length = 0x4000;
476
477 if( data_length < 10 ) {
478 libspectrum_print_error( LIBSPECTRUM_ERROR_UNKNOWN,
479 "szx_read_b128_chunk: length %lu too short",
480 (unsigned long)data_length );
481 return LIBSPECTRUM_ERROR_UNKNOWN;
482 }
483
484 flags = libspectrum_read_dword( buffer );
485 libspectrum_snap_set_beta_active( snap, 1 );
486 libspectrum_snap_set_beta_paged( snap, flags & ZXSTBETAF_PAGED );
487 libspectrum_snap_set_beta_autoboot( snap, flags & ZXSTBETAF_AUTOBOOT );
488 libspectrum_snap_set_beta_direction( snap,
489 !( flags & ZXSTBETAF_SEEKLOWER ) );
490
491 libspectrum_snap_set_beta_custom_rom( snap,
492 !!( flags & ZXSTBETAF_CUSTOMROM ) );
493
494 libspectrum_snap_set_beta_drive_count( snap, **buffer ); (*buffer)++;
495 libspectrum_snap_set_beta_system( snap, **buffer ); (*buffer)++;
496 libspectrum_snap_set_beta_track ( snap, **buffer ); (*buffer)++;
497 libspectrum_snap_set_beta_sector( snap, **buffer ); (*buffer)++;
498 libspectrum_snap_set_beta_data ( snap, **buffer ); (*buffer)++;
499 libspectrum_snap_set_beta_status( snap, **buffer ); (*buffer)++;
500
501 if( libspectrum_snap_beta_custom_rom( snap ) ) {
502
503 if( flags & ZXSTBETAF_COMPRESSED ) {
504
505 #ifdef HAVE_ZLIB_H
506
507 size_t uncompressed_length = 0;
508
509 error = libspectrum_zlib_inflate( *buffer, data_length - 10, &rom_data,
510 &uncompressed_length );
511 if( error ) return error;
512
513 if( uncompressed_length != expected_length ) {
514 libspectrum_print_error( LIBSPECTRUM_ERROR_UNKNOWN,
515 "%s:read_b128_chunk: invalid ROM length "
516 "in compressed file, should be %lu, file "
517 "has %lu",
518 __FILE__,
519 (unsigned long)expected_length,
520 (unsigned long)uncompressed_length );
521 return LIBSPECTRUM_ERROR_UNKNOWN;
522 }
523
524 #else
525
526 libspectrum_print_error(
527 LIBSPECTRUM_ERROR_UNKNOWN,
528 "%s:read_b128_chunk: zlib needed for decompression\n",
529 __FILE__
530 );
531 return LIBSPECTRUM_ERROR_UNKNOWN;
532
533 #endif
534
535 } else {
536
537 if( data_length < 10 + expected_length ) {
538 libspectrum_print_error( LIBSPECTRUM_ERROR_UNKNOWN,
539 "%s:read_b128_chunk: length %lu too short, "
540 "expected %lu",
541 __FILE__, (unsigned long)data_length,
542 (unsigned long)10 + expected_length );
543 return LIBSPECTRUM_ERROR_UNKNOWN;
544 }
545
546 rom_data = libspectrum_malloc( expected_length );
547 memcpy( rom_data, *buffer, expected_length );
548
549 }
550
551 }
552
553 libspectrum_snap_set_beta_rom( snap, 0, rom_data );
554
555 /* Skip any extra data (most likely a custom ROM) */
556 *buffer += data_length - 10;
557
558 return LIBSPECTRUM_ERROR_NONE;
559 }
560
561 static libspectrum_error
read_crtr_chunk(libspectrum_snap * snap,libspectrum_word version GCC_UNUSED,const libspectrum_byte ** buffer,const libspectrum_byte * end GCC_UNUSED,size_t data_length,szx_context * ctx)562 read_crtr_chunk( libspectrum_snap *snap, libspectrum_word version GCC_UNUSED,
563 const libspectrum_byte **buffer,
564 const libspectrum_byte *end GCC_UNUSED, size_t data_length,
565 szx_context *ctx )
566 {
567 if( data_length < 36 ) {
568 libspectrum_print_error( LIBSPECTRUM_ERROR_UNKNOWN,
569 "%s:read_crtr_chunk: length %lu too short",
570 __FILE__, (unsigned long)data_length );
571 return LIBSPECTRUM_ERROR_UNKNOWN;
572 }
573
574 *buffer += 36;
575 data_length -= 36;
576
577 /* This is ugly, but I can't see a better way to do it */
578 if( sizeof( libspectrum_byte ) == sizeof( char ) ) {
579 char *custom = libspectrum_malloc( data_length + 1 );
580 memcpy( custom, *buffer, data_length );
581 custom[data_length] = 0;
582
583 char *libspectrum = strstr( custom, libspectrum_string );
584 if( libspectrum ) {
585 int matches, v1, v2, v3;
586 libspectrum += strlen( libspectrum_string );
587 matches = sscanf( libspectrum, "%d.%d.%d", &v1, &v2, &v3 );
588 if( matches == 3 ) {
589 if( v1 == 0 ) {
590 if( v2 < 5 || ( v2 == 5 && v3 == 0 ) ) {
591 ctx->swap_af = 1;
592 }
593 }
594 }
595 }
596
597 libspectrum_free( custom );
598 }
599
600 *buffer += data_length;
601
602 return LIBSPECTRUM_ERROR_NONE;
603 }
604
605 static libspectrum_error
read_opus_chunk(libspectrum_snap * snap,libspectrum_word version GCC_UNUSED,const libspectrum_byte ** buffer,const libspectrum_byte * end GCC_UNUSED,size_t data_length,szx_context * ctx GCC_UNUSED)606 read_opus_chunk( libspectrum_snap *snap, libspectrum_word version GCC_UNUSED,
607 const libspectrum_byte **buffer,
608 const libspectrum_byte *end GCC_UNUSED, size_t data_length,
609 szx_context *ctx GCC_UNUSED )
610 {
611 #ifdef HAVE_ZLIB_H
612 libspectrum_error error;
613 #endif
614 libspectrum_byte *ram_data = NULL, *rom_data = NULL;
615 libspectrum_dword flags;
616 size_t disc_ram_length;
617 size_t disc_rom_length;
618 size_t expected_length = 0x800;
619
620 if( data_length < 23 ) {
621 libspectrum_print_error( LIBSPECTRUM_ERROR_UNKNOWN,
622 "szx_read_opus_chunk: length %lu too short",
623 (unsigned long)data_length );
624 return LIBSPECTRUM_ERROR_UNKNOWN;
625 }
626
627 libspectrum_snap_set_opus_active( snap, 1 );
628
629 flags = libspectrum_read_dword( buffer );
630 libspectrum_snap_set_opus_paged( snap, flags & ZXSTOPUSF_PAGED );
631 libspectrum_snap_set_opus_direction( snap,
632 !( flags & ZXSTOPUSF_SEEKLOWER ) );
633
634 disc_ram_length = libspectrum_read_dword( buffer );
635 disc_rom_length = libspectrum_read_dword( buffer );
636
637 libspectrum_snap_set_opus_custom_rom( snap, flags & ZXSTOPUSF_CUSTOMROM );
638 if( libspectrum_snap_opus_custom_rom( snap ) && !disc_rom_length ) {
639 libspectrum_print_error( LIBSPECTRUM_ERROR_UNKNOWN,
640 "szx_read_opus_chunk: block flagged as custom "
641 "ROM but there is no custom ROM stored in the "
642 "snapshot" );
643 return LIBSPECTRUM_ERROR_UNKNOWN;
644 }
645
646 libspectrum_snap_set_opus_control_a( snap, **buffer ); (*buffer)++;
647 libspectrum_snap_set_opus_data_reg_a( snap, **buffer ); (*buffer)++;
648 libspectrum_snap_set_opus_data_dir_a( snap, **buffer ); (*buffer)++;
649 libspectrum_snap_set_opus_control_b( snap, **buffer ); (*buffer)++;
650 libspectrum_snap_set_opus_data_reg_b( snap, **buffer ); (*buffer)++;
651 libspectrum_snap_set_opus_data_dir_b( snap, **buffer ); (*buffer)++;
652 libspectrum_snap_set_opus_drive_count( snap, **buffer ); (*buffer)++;
653 libspectrum_snap_set_opus_track ( snap, **buffer ); (*buffer)++;
654 libspectrum_snap_set_opus_sector( snap, **buffer ); (*buffer)++;
655 libspectrum_snap_set_opus_data ( snap, **buffer ); (*buffer)++;
656 libspectrum_snap_set_opus_status( snap, **buffer ); (*buffer)++;
657
658 if( flags & ZXSTOPUSF_COMPRESSED ) {
659
660 #ifdef HAVE_ZLIB_H
661
662 size_t uncompressed_length = 0;
663
664 if( (!libspectrum_snap_opus_custom_rom( snap ) &&
665 disc_rom_length != 0 ) ||
666 (libspectrum_snap_opus_custom_rom( snap ) &&
667 disc_rom_length == 0 ) ) {
668 libspectrum_print_error( LIBSPECTRUM_ERROR_UNKNOWN,
669 "%s:read_opus_chunk: invalid ROM length "
670 "in compressed file, should be %lu, file "
671 "has %lu",
672 __FILE__,
673 0UL,
674 (unsigned long)disc_rom_length );
675 return LIBSPECTRUM_ERROR_UNKNOWN;
676 }
677
678 if( data_length < 23 + disc_ram_length + disc_rom_length ) {
679 libspectrum_print_error( LIBSPECTRUM_ERROR_UNKNOWN,
680 "%s:read_opus_chunk: length %lu too short, "
681 "expected %lu" ,
682 __FILE__, (unsigned long)data_length,
683 (unsigned long)23 + disc_ram_length +
684 disc_rom_length );
685 return LIBSPECTRUM_ERROR_UNKNOWN;
686 }
687
688 error = libspectrum_zlib_inflate( *buffer, disc_ram_length, &ram_data,
689 &uncompressed_length );
690 if( error ) return error;
691
692 if( uncompressed_length != expected_length ) {
693 libspectrum_print_error( LIBSPECTRUM_ERROR_UNKNOWN,
694 "%s:read_opus_chunk: invalid RAM length "
695 "in compressed file, should be %lu, file "
696 "has %lu",
697 __FILE__,
698 (unsigned long)expected_length,
699 (unsigned long)uncompressed_length );
700 return LIBSPECTRUM_ERROR_UNKNOWN;
701 }
702
703 *buffer += disc_ram_length;
704
705 if( libspectrum_snap_opus_custom_rom( snap ) ) {
706 error = libspectrum_zlib_inflate( *buffer, disc_rom_length, &rom_data,
707 &uncompressed_length );
708 if( error ) return error;
709
710 expected_length = 0x2000;
711
712 if( uncompressed_length != expected_length ) {
713 libspectrum_print_error( LIBSPECTRUM_ERROR_UNKNOWN,
714 "%s:read_plsd_chunk: invalid ROM length "
715 "in compressed file, should be %lu, file "
716 "has %lu",
717 __FILE__,
718 (unsigned long)expected_length,
719 (unsigned long)disc_rom_length );
720 return LIBSPECTRUM_ERROR_UNKNOWN;
721 }
722
723 *buffer += disc_rom_length;
724 }
725
726 #else /* #ifdef HAVE_ZLIB_H */
727
728 libspectrum_print_error(
729 LIBSPECTRUM_ERROR_UNKNOWN,
730 "%s:read_opus_chunk: zlib needed for decompression\n",
731 __FILE__
732 );
733 return LIBSPECTRUM_ERROR_UNKNOWN;
734
735 #endif /* #ifdef HAVE_ZLIB_H */
736
737 } else {
738
739 if( disc_ram_length != expected_length ) {
740 libspectrum_print_error( LIBSPECTRUM_ERROR_UNKNOWN,
741 "%s:read_opus_chunk: invalid RAM length "
742 "in uncompressed file, should be %lu, file "
743 "has %lu",
744 __FILE__,
745 (unsigned long)expected_length,
746 (unsigned long)disc_rom_length );
747 return LIBSPECTRUM_ERROR_UNKNOWN;
748 }
749
750 expected_length = 0x2000;
751
752 if( (libspectrum_snap_opus_custom_rom( snap ) &&
753 disc_rom_length != expected_length ) ||
754 (!libspectrum_snap_opus_custom_rom( snap ) &&
755 disc_rom_length != 0 ) ) {
756 libspectrum_print_error( LIBSPECTRUM_ERROR_UNKNOWN,
757 "%s:read_opus_chunk: invalid ROM length "
758 "in uncompressed file, should be %lu, file "
759 "has %lu",
760 __FILE__,
761 libspectrum_snap_opus_custom_rom( snap ) ?
762 expected_length : 0UL,
763 (unsigned long)disc_rom_length );
764 return LIBSPECTRUM_ERROR_UNKNOWN;
765 }
766
767 if( data_length < 23 + disc_ram_length + disc_rom_length ) {
768 libspectrum_print_error( LIBSPECTRUM_ERROR_UNKNOWN,
769 "%s:read_opus_chunk: length %lu too short, "
770 "expected %lu" ,
771 __FILE__, (unsigned long)data_length,
772 (unsigned long)23 + disc_ram_length + disc_rom_length );
773 return LIBSPECTRUM_ERROR_UNKNOWN;
774 }
775
776 expected_length = 0x800;
777
778 ram_data = libspectrum_malloc( expected_length );
779 memcpy( ram_data, *buffer, expected_length );
780 *buffer += expected_length;
781
782 if( libspectrum_snap_opus_custom_rom( snap ) ) {
783 expected_length = 0x2000;
784 rom_data = libspectrum_malloc( expected_length );
785 memcpy( rom_data, *buffer, expected_length );
786 *buffer += expected_length;
787 }
788
789 }
790
791 libspectrum_snap_set_opus_ram( snap, 0, ram_data );
792 libspectrum_snap_set_opus_rom( snap, 0, rom_data );
793
794 return LIBSPECTRUM_ERROR_NONE;
795 }
796
797 static libspectrum_error
read_plsd_chunk(libspectrum_snap * snap,libspectrum_word version GCC_UNUSED,const libspectrum_byte ** buffer,const libspectrum_byte * end GCC_UNUSED,size_t data_length,szx_context * ctx GCC_UNUSED)798 read_plsd_chunk( libspectrum_snap *snap, libspectrum_word version GCC_UNUSED,
799 const libspectrum_byte **buffer,
800 const libspectrum_byte *end GCC_UNUSED, size_t data_length,
801 szx_context *ctx GCC_UNUSED )
802 {
803 #ifdef HAVE_ZLIB_H
804 libspectrum_error error;
805 #endif
806 libspectrum_byte *ram_data = NULL, *rom_data = NULL;
807 libspectrum_byte rom_type;
808 libspectrum_dword flags;
809 size_t disc_ram_length;
810 size_t disc_rom_length;
811 const size_t expected_length = 0x2000;
812
813 if( data_length < 19 ) {
814 libspectrum_print_error( LIBSPECTRUM_ERROR_UNKNOWN,
815 "szx_read_plusd_chunk: length %lu too short",
816 (unsigned long)data_length );
817 return LIBSPECTRUM_ERROR_UNKNOWN;
818 }
819
820 libspectrum_snap_set_plusd_active( snap, 1 );
821
822 flags = libspectrum_read_dword( buffer );
823 libspectrum_snap_set_plusd_paged( snap, flags & ZXSTPLUSDF_PAGED );
824 libspectrum_snap_set_plusd_direction( snap,
825 !( flags & ZXSTPLUSDF_SEEKLOWER ) );
826
827 disc_ram_length = libspectrum_read_dword( buffer );
828 disc_rom_length = libspectrum_read_dword( buffer );
829 rom_type = *(*buffer)++;
830
831 libspectrum_snap_set_plusd_custom_rom( snap, rom_type == ZXSTPDRT_CUSTOM );
832 if( libspectrum_snap_plusd_custom_rom( snap ) && !disc_rom_length ) {
833 libspectrum_print_error( LIBSPECTRUM_ERROR_UNKNOWN,
834 "szx_read_plusd_chunk: block flagged as custom "
835 "ROM but there is no custom ROM stored in the "
836 "snapshot" );
837 return LIBSPECTRUM_ERROR_UNKNOWN;
838 }
839
840 libspectrum_snap_set_plusd_control( snap, **buffer ); (*buffer)++;
841 libspectrum_snap_set_plusd_drive_count( snap, **buffer ); (*buffer)++;
842 libspectrum_snap_set_plusd_track ( snap, **buffer ); (*buffer)++;
843 libspectrum_snap_set_plusd_sector( snap, **buffer ); (*buffer)++;
844 libspectrum_snap_set_plusd_data ( snap, **buffer ); (*buffer)++;
845 libspectrum_snap_set_plusd_status( snap, **buffer ); (*buffer)++;
846
847 if( flags & ZXSTPLUSDF_COMPRESSED ) {
848
849 #ifdef HAVE_ZLIB_H
850
851 size_t uncompressed_length = 0;
852
853 if( (!libspectrum_snap_plusd_custom_rom( snap ) &&
854 disc_rom_length != 0 ) ||
855 (libspectrum_snap_plusd_custom_rom( snap ) &&
856 disc_rom_length == 0 ) ) {
857 libspectrum_print_error( LIBSPECTRUM_ERROR_UNKNOWN,
858 "%s:read_plsd_chunk: invalid ROM length "
859 "in compressed file, should be %lu, file "
860 "has %lu",
861 __FILE__,
862 0UL,
863 (unsigned long)disc_rom_length );
864 return LIBSPECTRUM_ERROR_UNKNOWN;
865 }
866
867 if( data_length < 19 + disc_ram_length + disc_rom_length ) {
868 libspectrum_print_error( LIBSPECTRUM_ERROR_UNKNOWN,
869 "%s:read_plsd_chunk: length %lu too short, "
870 "expected %lu" ,
871 __FILE__, (unsigned long)data_length,
872 (unsigned long)19 + disc_ram_length +
873 disc_rom_length );
874 return LIBSPECTRUM_ERROR_UNKNOWN;
875 }
876
877 error = libspectrum_zlib_inflate( *buffer, disc_ram_length, &ram_data,
878 &uncompressed_length );
879 if( error ) return error;
880
881 if( uncompressed_length != expected_length ) {
882 libspectrum_print_error( LIBSPECTRUM_ERROR_UNKNOWN,
883 "%s:read_plsd_chunk: invalid RAM length "
884 "in compressed file, should be %lu, file "
885 "has %lu",
886 __FILE__,
887 (unsigned long)expected_length,
888 (unsigned long)uncompressed_length );
889 return LIBSPECTRUM_ERROR_UNKNOWN;
890 }
891
892 *buffer += disc_ram_length;
893
894 if( libspectrum_snap_plusd_custom_rom( snap ) ) {
895 error = libspectrum_zlib_inflate( *buffer, disc_rom_length, &rom_data,
896 &uncompressed_length );
897 if( error ) return error;
898
899 if( uncompressed_length != expected_length ) {
900 libspectrum_print_error( LIBSPECTRUM_ERROR_UNKNOWN,
901 "%s:read_plsd_chunk: invalid ROM length "
902 "in compressed file, should be %lu, file "
903 "has %lu",
904 __FILE__,
905 (unsigned long)expected_length,
906 (unsigned long)disc_rom_length );
907 return LIBSPECTRUM_ERROR_UNKNOWN;
908 }
909
910 *buffer += disc_rom_length;
911 }
912
913 #else /* #ifdef HAVE_ZLIB_H */
914
915 libspectrum_print_error(
916 LIBSPECTRUM_ERROR_UNKNOWN,
917 "%s:read_plsd_chunk: zlib needed for decompression\n",
918 __FILE__
919 );
920 return LIBSPECTRUM_ERROR_UNKNOWN;
921
922 #endif /* #ifdef HAVE_ZLIB_H */
923
924 } else {
925
926 if( disc_ram_length != expected_length ) {
927 libspectrum_print_error( LIBSPECTRUM_ERROR_UNKNOWN,
928 "%s:read_plsd_chunk: invalid RAM length "
929 "in uncompressed file, should be %lu, file "
930 "has %lu",
931 __FILE__,
932 (unsigned long)expected_length,
933 (unsigned long)disc_rom_length );
934 return LIBSPECTRUM_ERROR_UNKNOWN;
935 }
936
937 if( (libspectrum_snap_plusd_custom_rom( snap ) &&
938 disc_rom_length != expected_length ) ||
939 (!libspectrum_snap_plusd_custom_rom( snap ) &&
940 disc_rom_length != 0 ) ) {
941 libspectrum_print_error( LIBSPECTRUM_ERROR_UNKNOWN,
942 "%s:read_plsd_chunk: invalid ROM length "
943 "in uncompressed file, should be %lu, file "
944 "has %lu",
945 __FILE__,
946 libspectrum_snap_plusd_custom_rom( snap ) ?
947 expected_length : 0UL,
948 (unsigned long)disc_rom_length );
949 return LIBSPECTRUM_ERROR_UNKNOWN;
950 }
951
952 if( data_length < 19 + disc_ram_length + disc_rom_length ) {
953 libspectrum_print_error( LIBSPECTRUM_ERROR_UNKNOWN,
954 "%s:read_plsd_chunk: length %lu too short, "
955 "expected %lu" ,
956 __FILE__, (unsigned long)data_length,
957 (unsigned long)19 + disc_ram_length + disc_rom_length );
958 return LIBSPECTRUM_ERROR_UNKNOWN;
959 }
960
961 ram_data = libspectrum_malloc( expected_length );
962 memcpy( ram_data, *buffer, expected_length );
963 *buffer += expected_length;
964
965 if( libspectrum_snap_plusd_custom_rom( snap ) ) {
966 rom_data = libspectrum_malloc( expected_length );
967 memcpy( rom_data, *buffer, expected_length );
968 *buffer += expected_length;
969 }
970
971 }
972
973 libspectrum_snap_set_plusd_ram( snap, 0, ram_data );
974 libspectrum_snap_set_plusd_rom( snap, 0, rom_data );
975
976 return LIBSPECTRUM_ERROR_NONE;
977 }
978
979 static libspectrum_error
read_cfrp_chunk(libspectrum_snap * snap,libspectrum_word version GCC_UNUSED,const libspectrum_byte ** buffer,const libspectrum_byte * end GCC_UNUSED,size_t data_length,szx_context * ctx GCC_UNUSED)980 read_cfrp_chunk( libspectrum_snap *snap, libspectrum_word version GCC_UNUSED,
981 const libspectrum_byte **buffer,
982 const libspectrum_byte *end GCC_UNUSED, size_t data_length,
983 szx_context *ctx GCC_UNUSED )
984 {
985 libspectrum_byte *data;
986 size_t page;
987 libspectrum_error error;
988 libspectrum_word flags;
989
990 error = read_ram_page( &data, &page, buffer, data_length, 0x4000, &flags );
991 if( error ) return error;
992
993 if( page >= SNAPSHOT_ZXCF_PAGES ) {
994 libspectrum_print_error( LIBSPECTRUM_ERROR_CORRUPT,
995 "%s:read_cfrp_chunk: unknown page number %lu",
996 __FILE__, (unsigned long)page );
997 libspectrum_free( data );
998 return LIBSPECTRUM_ERROR_CORRUPT;
999 }
1000
1001 libspectrum_snap_set_zxcf_ram( snap, page, data );
1002
1003 return LIBSPECTRUM_ERROR_NONE;
1004 }
1005
1006 static libspectrum_error
read_side_chunk(libspectrum_snap * snap,libspectrum_word version GCC_UNUSED,const libspectrum_byte ** buffer,const libspectrum_byte * end GCC_UNUSED,size_t data_length,szx_context * ctx GCC_UNUSED)1007 read_side_chunk( libspectrum_snap *snap, libspectrum_word version GCC_UNUSED,
1008 const libspectrum_byte **buffer,
1009 const libspectrum_byte *end GCC_UNUSED, size_t data_length,
1010 szx_context *ctx GCC_UNUSED )
1011 {
1012 if( data_length ) {
1013 libspectrum_print_error( LIBSPECTRUM_ERROR_UNKNOWN,
1014 "%s:read_side_chunk: unknown length %lu",
1015 __FILE__, (unsigned long)data_length );
1016 return LIBSPECTRUM_ERROR_UNKNOWN;
1017 }
1018
1019 libspectrum_snap_set_simpleide_active( snap, 1 );
1020
1021 return LIBSPECTRUM_ERROR_NONE;
1022 }
1023
1024 static libspectrum_error
read_drum_chunk(libspectrum_snap * snap,libspectrum_word version GCC_UNUSED,const libspectrum_byte ** buffer,const libspectrum_byte * end GCC_UNUSED,size_t data_length,szx_context * ctx GCC_UNUSED)1025 read_drum_chunk( libspectrum_snap *snap, libspectrum_word version GCC_UNUSED,
1026 const libspectrum_byte **buffer,
1027 const libspectrum_byte *end GCC_UNUSED, size_t data_length,
1028 szx_context *ctx GCC_UNUSED )
1029 {
1030 if( data_length != 1 ) {
1031 libspectrum_print_error( LIBSPECTRUM_ERROR_UNKNOWN,
1032 "%s:read_drum_chunk: unknown length %lu",
1033 __FILE__, (unsigned long)data_length );
1034 return LIBSPECTRUM_ERROR_UNKNOWN;
1035 }
1036
1037 libspectrum_snap_set_specdrum_dac( snap, *(*buffer)++ );
1038
1039 libspectrum_snap_set_specdrum_active( snap, 1 );
1040
1041 return LIBSPECTRUM_ERROR_NONE;
1042 }
1043
1044
1045 static void
add_joystick(libspectrum_snap * snap,libspectrum_joystick type,int inputs)1046 add_joystick( libspectrum_snap *snap, libspectrum_joystick type, int inputs )
1047 {
1048 size_t i;
1049 size_t num_joysticks = libspectrum_snap_joystick_active_count( snap );
1050
1051 for( i = 0; i < num_joysticks; i++ ) {
1052 if( libspectrum_snap_joystick_list( snap, i ) == type ) {
1053 libspectrum_snap_set_joystick_inputs( snap, i, inputs |
1054 libspectrum_snap_joystick_inputs( snap, i ) );
1055 return;
1056 }
1057 }
1058
1059 libspectrum_snap_set_joystick_list( snap, num_joysticks, type );
1060 libspectrum_snap_set_joystick_inputs( snap, num_joysticks, inputs );
1061 libspectrum_snap_set_joystick_active_count( snap, num_joysticks + 1 );
1062 }
1063
1064 static libspectrum_error
read_joy_chunk(libspectrum_snap * snap,libspectrum_word version,const libspectrum_byte ** buffer,const libspectrum_byte * end GCC_UNUSED,size_t data_length,szx_context * ctx GCC_UNUSED)1065 read_joy_chunk( libspectrum_snap *snap, libspectrum_word version,
1066 const libspectrum_byte **buffer,
1067 const libspectrum_byte *end GCC_UNUSED, size_t data_length,
1068 szx_context *ctx GCC_UNUSED )
1069 {
1070 libspectrum_dword flags;
1071
1072 if( data_length != 6 ) {
1073 libspectrum_print_error( LIBSPECTRUM_ERROR_UNKNOWN,
1074 "%s:read_joy_chunk: unknown length %lu",
1075 __FILE__, (unsigned long)data_length );
1076 return LIBSPECTRUM_ERROR_UNKNOWN;
1077 }
1078
1079 flags = libspectrum_read_dword( buffer );
1080 if( flags & ZXSTJOYF_ALWAYSPORT31 ) {
1081 add_joystick( snap, LIBSPECTRUM_JOYSTICK_KEMPSTON,
1082 LIBSPECTRUM_JOYSTICK_INPUT_NONE );
1083 }
1084
1085 switch( **buffer ) {
1086 case ZXJT_KEMPSTON:
1087 add_joystick( snap, LIBSPECTRUM_JOYSTICK_KEMPSTON,
1088 LIBSPECTRUM_JOYSTICK_INPUT_JOYSTICK_1 );
1089 break;
1090 case ZXJT_FULLER:
1091 add_joystick( snap, LIBSPECTRUM_JOYSTICK_FULLER,
1092 LIBSPECTRUM_JOYSTICK_INPUT_JOYSTICK_1 );
1093 break;
1094 case ZXJT_CURSOR:
1095 add_joystick( snap, LIBSPECTRUM_JOYSTICK_CURSOR,
1096 LIBSPECTRUM_JOYSTICK_INPUT_JOYSTICK_1 );
1097 break;
1098 case ZXJT_SINCLAIR1:
1099 add_joystick( snap, LIBSPECTRUM_JOYSTICK_SINCLAIR_1,
1100 LIBSPECTRUM_JOYSTICK_INPUT_JOYSTICK_1 );
1101 break;
1102 case ZXJT_SINCLAIR2:
1103 add_joystick( snap, LIBSPECTRUM_JOYSTICK_SINCLAIR_2,
1104 LIBSPECTRUM_JOYSTICK_INPUT_JOYSTICK_1 );
1105 break;
1106 case ZXJT_TIMEX1:
1107 add_joystick( snap, LIBSPECTRUM_JOYSTICK_TIMEX_1,
1108 LIBSPECTRUM_JOYSTICK_INPUT_JOYSTICK_1 );
1109 break;
1110 case ZXJT_TIMEX2:
1111 add_joystick( snap, LIBSPECTRUM_JOYSTICK_TIMEX_2,
1112 LIBSPECTRUM_JOYSTICK_INPUT_JOYSTICK_1 );
1113 break;
1114 case ZXJT_NONE:
1115 break;
1116 }
1117 (*buffer)++;
1118
1119 switch( **buffer ) {
1120 case ZXJT_KEMPSTON:
1121 add_joystick( snap, LIBSPECTRUM_JOYSTICK_KEMPSTON,
1122 LIBSPECTRUM_JOYSTICK_INPUT_JOYSTICK_2 );
1123 break;
1124 case ZXJT_FULLER:
1125 add_joystick( snap, LIBSPECTRUM_JOYSTICK_FULLER,
1126 LIBSPECTRUM_JOYSTICK_INPUT_JOYSTICK_2 );
1127 break;
1128 case ZXJT_CURSOR:
1129 add_joystick( snap, LIBSPECTRUM_JOYSTICK_CURSOR,
1130 LIBSPECTRUM_JOYSTICK_INPUT_JOYSTICK_2 );
1131 break;
1132 case ZXJT_SINCLAIR1:
1133 add_joystick( snap, LIBSPECTRUM_JOYSTICK_SINCLAIR_1,
1134 LIBSPECTRUM_JOYSTICK_INPUT_JOYSTICK_2 );
1135 break;
1136 case ZXJT_SINCLAIR2:
1137 add_joystick( snap, LIBSPECTRUM_JOYSTICK_SINCLAIR_2,
1138 LIBSPECTRUM_JOYSTICK_INPUT_JOYSTICK_2 );
1139 break;
1140 case ZXJT_TIMEX1:
1141 add_joystick( snap, LIBSPECTRUM_JOYSTICK_TIMEX_1,
1142 LIBSPECTRUM_JOYSTICK_INPUT_JOYSTICK_2 );
1143 break;
1144 case ZXJT_TIMEX2:
1145 add_joystick( snap, LIBSPECTRUM_JOYSTICK_TIMEX_2,
1146 LIBSPECTRUM_JOYSTICK_INPUT_JOYSTICK_2 );
1147 break;
1148 case ZXJT_NONE:
1149 break;
1150 }
1151 (*buffer)++;
1152
1153 return LIBSPECTRUM_ERROR_NONE;
1154 }
1155
1156 static libspectrum_error
read_keyb_chunk(libspectrum_snap * snap,libspectrum_word version,const libspectrum_byte ** buffer,const libspectrum_byte * end GCC_UNUSED,size_t data_length,szx_context * ctx GCC_UNUSED)1157 read_keyb_chunk( libspectrum_snap *snap, libspectrum_word version,
1158 const libspectrum_byte **buffer,
1159 const libspectrum_byte *end GCC_UNUSED, size_t data_length,
1160 szx_context *ctx GCC_UNUSED )
1161 {
1162 size_t expected_length;
1163 libspectrum_dword flags;
1164
1165 expected_length = version >= 0x0101 ? 5 : 4;
1166
1167 if( data_length != expected_length ) {
1168 libspectrum_print_error( LIBSPECTRUM_ERROR_UNKNOWN,
1169 "%s:read_keyb_chunk: unknown length %lu",
1170 __FILE__, (unsigned long)data_length );
1171 return LIBSPECTRUM_ERROR_UNKNOWN;
1172 }
1173
1174 flags = libspectrum_read_dword( buffer );
1175 libspectrum_snap_set_issue2( snap, flags & ZXSTKF_ISSUE2 );
1176
1177 if( expected_length >= 5 ) {
1178 switch( **buffer ) {
1179 case ZXJT_KEMPSTON:
1180 add_joystick( snap, LIBSPECTRUM_JOYSTICK_KEMPSTON,
1181 LIBSPECTRUM_JOYSTICK_INPUT_KEYBOARD );
1182 break;
1183 case ZXJT_FULLER:
1184 add_joystick( snap, LIBSPECTRUM_JOYSTICK_FULLER,
1185 LIBSPECTRUM_JOYSTICK_INPUT_KEYBOARD );
1186 break;
1187 case ZXJT_CURSOR:
1188 add_joystick( snap, LIBSPECTRUM_JOYSTICK_CURSOR,
1189 LIBSPECTRUM_JOYSTICK_INPUT_KEYBOARD );
1190 break;
1191 case ZXJT_SINCLAIR1:
1192 add_joystick( snap, LIBSPECTRUM_JOYSTICK_SINCLAIR_1,
1193 LIBSPECTRUM_JOYSTICK_INPUT_KEYBOARD );
1194 break;
1195 case ZXJT_SINCLAIR2:
1196 add_joystick( snap, LIBSPECTRUM_JOYSTICK_SINCLAIR_2,
1197 LIBSPECTRUM_JOYSTICK_INPUT_KEYBOARD );
1198 break;
1199 case ZXJT_TIMEX1:
1200 add_joystick( snap, LIBSPECTRUM_JOYSTICK_TIMEX_1,
1201 LIBSPECTRUM_JOYSTICK_INPUT_KEYBOARD );
1202 break;
1203 case ZXJT_TIMEX2:
1204 add_joystick( snap, LIBSPECTRUM_JOYSTICK_TIMEX_2,
1205 LIBSPECTRUM_JOYSTICK_INPUT_KEYBOARD );
1206 break;
1207 case ZXJT_SPECTRUMPLUS: /* Actually, no joystick at all */
1208 break;
1209 }
1210 (*buffer)++;
1211 }
1212
1213 return LIBSPECTRUM_ERROR_NONE;
1214 }
1215
1216 static libspectrum_error
read_amxm_chunk(libspectrum_snap * snap,libspectrum_word version,const libspectrum_byte ** buffer,const libspectrum_byte * end GCC_UNUSED,size_t data_length,szx_context * ctx GCC_UNUSED)1217 read_amxm_chunk( libspectrum_snap *snap, libspectrum_word version,
1218 const libspectrum_byte **buffer,
1219 const libspectrum_byte *end GCC_UNUSED, size_t data_length,
1220 szx_context *ctx GCC_UNUSED )
1221 {
1222 if( data_length != 7 ) {
1223 libspectrum_print_error( LIBSPECTRUM_ERROR_UNKNOWN,
1224 "read_amxm_chunk: unknown length %lu",
1225 (unsigned long)data_length );
1226 return LIBSPECTRUM_ERROR_UNKNOWN;
1227 }
1228
1229 switch( **buffer ) {
1230 case ZXSTM_AMX:
1231 break;
1232 case ZXSTM_KEMPSTON:
1233 libspectrum_snap_set_kempston_mouse_active( snap, 1 );
1234 break;
1235 case ZXSTM_NONE:
1236 default:
1237 break;
1238 }
1239 (*buffer)++;
1240
1241 /* Z80 PIO CTRLA registers for AMX mouse */
1242 (*buffer)++; (*buffer)++; (*buffer)++;
1243
1244 /* Z80 PIO CTRLB registers for AMX mouse */
1245 (*buffer)++; (*buffer)++; (*buffer)++;
1246
1247 return LIBSPECTRUM_ERROR_NONE;
1248 }
1249
1250 static libspectrum_error
read_ramp_chunk(libspectrum_snap * snap,libspectrum_word version GCC_UNUSED,const libspectrum_byte ** buffer,const libspectrum_byte * end GCC_UNUSED,size_t data_length,szx_context * ctx GCC_UNUSED)1251 read_ramp_chunk( libspectrum_snap *snap, libspectrum_word version GCC_UNUSED,
1252 const libspectrum_byte **buffer,
1253 const libspectrum_byte *end GCC_UNUSED, size_t data_length,
1254 szx_context *ctx GCC_UNUSED )
1255 {
1256 libspectrum_byte *data;
1257 size_t page;
1258 libspectrum_error error;
1259 libspectrum_word flags;
1260
1261
1262 error = read_ram_page( &data, &page, buffer, data_length, 0x4000, &flags );
1263 if( error ) return error;
1264
1265 if( page > 63 ) {
1266 libspectrum_print_error( LIBSPECTRUM_ERROR_CORRUPT,
1267 "%s:read_ramp_chunk: unknown page number %lu",
1268 __FILE__, (unsigned long)page );
1269 libspectrum_free( data );
1270 return LIBSPECTRUM_ERROR_CORRUPT;
1271 }
1272
1273 libspectrum_snap_set_pages( snap, page, data );
1274
1275 return LIBSPECTRUM_ERROR_NONE;
1276 }
1277
1278 static libspectrum_error
read_scld_chunk(libspectrum_snap * snap,libspectrum_word version GCC_UNUSED,const libspectrum_byte ** buffer,const libspectrum_byte * end GCC_UNUSED,size_t data_length,szx_context * ctx GCC_UNUSED)1279 read_scld_chunk( libspectrum_snap *snap, libspectrum_word version GCC_UNUSED,
1280 const libspectrum_byte **buffer,
1281 const libspectrum_byte *end GCC_UNUSED, size_t data_length,
1282 szx_context *ctx GCC_UNUSED )
1283 {
1284 if( data_length != 2 ) {
1285 libspectrum_print_error( LIBSPECTRUM_ERROR_UNKNOWN,
1286 "szx_read_scld_chunk: unknown length %lu",
1287 (unsigned long)data_length );
1288 return LIBSPECTRUM_ERROR_UNKNOWN;
1289 }
1290
1291 libspectrum_snap_set_out_scld_hsr( snap, **buffer ); (*buffer)++;
1292 libspectrum_snap_set_out_scld_dec( snap, **buffer ); (*buffer)++;
1293
1294 return LIBSPECTRUM_ERROR_NONE;
1295 }
1296
1297 static libspectrum_error
read_spcr_chunk(libspectrum_snap * snap,libspectrum_word version,const libspectrum_byte ** buffer,const libspectrum_byte * end GCC_UNUSED,size_t data_length,szx_context * ctx GCC_UNUSED)1298 read_spcr_chunk( libspectrum_snap *snap, libspectrum_word version,
1299 const libspectrum_byte **buffer,
1300 const libspectrum_byte *end GCC_UNUSED, size_t data_length,
1301 szx_context *ctx GCC_UNUSED )
1302 {
1303 libspectrum_byte out_ula;
1304 int capabilities;
1305
1306 if( data_length != 8 ) {
1307 libspectrum_print_error(
1308 LIBSPECTRUM_ERROR_UNKNOWN,
1309 "szx_read_spcr_chunk: unknown length %lu", (unsigned long)data_length
1310 );
1311 return LIBSPECTRUM_ERROR_UNKNOWN;
1312 }
1313
1314 capabilities =
1315 libspectrum_machine_capabilities( libspectrum_snap_machine( snap ) );
1316
1317 out_ula = **buffer & 0x07; (*buffer)++;
1318
1319 libspectrum_snap_set_out_128_memoryport( snap, **buffer ); (*buffer)++;
1320
1321 if( ( capabilities & LIBSPECTRUM_MACHINE_CAPABILITY_PLUS3_MEMORY ) ||
1322 ( capabilities & LIBSPECTRUM_MACHINE_CAPABILITY_SCORP_MEMORY ) ||
1323 ( capabilities & LIBSPECTRUM_MACHINE_CAPABILITY_PENT1024_MEMORY ) )
1324 libspectrum_snap_set_out_plus3_memoryport( snap, **buffer );
1325 (*buffer)++;
1326
1327 if( version >= 0x0101 ) out_ula |= **buffer & 0xf8;
1328 (*buffer)++;
1329
1330 libspectrum_snap_set_out_ula( snap, out_ula );
1331
1332 *buffer += 4; /* Skip 'reserved' data */
1333
1334 return LIBSPECTRUM_ERROR_NONE;
1335 }
1336
1337 static libspectrum_error
read_z80r_chunk(libspectrum_snap * snap,libspectrum_word version,const libspectrum_byte ** buffer,const libspectrum_byte * end GCC_UNUSED,size_t data_length,szx_context * ctx)1338 read_z80r_chunk( libspectrum_snap *snap, libspectrum_word version,
1339 const libspectrum_byte **buffer,
1340 const libspectrum_byte *end GCC_UNUSED, size_t data_length,
1341 szx_context *ctx )
1342 {
1343 if( data_length != 37 ) {
1344 libspectrum_print_error( LIBSPECTRUM_ERROR_UNKNOWN,
1345 "szx_read_z80r_chunk: unknown length %lu",
1346 (unsigned long)data_length );
1347 return LIBSPECTRUM_ERROR_UNKNOWN;
1348 }
1349
1350 if( ctx->swap_af ) {
1351 libspectrum_snap_set_a( snap, **buffer ); (*buffer)++;
1352 libspectrum_snap_set_f( snap, **buffer ); (*buffer)++;
1353 } else {
1354 libspectrum_snap_set_f( snap, **buffer ); (*buffer)++;
1355 libspectrum_snap_set_a( snap, **buffer ); (*buffer)++;
1356 }
1357
1358 libspectrum_snap_set_bc ( snap, libspectrum_read_word( buffer ) );
1359 libspectrum_snap_set_de ( snap, libspectrum_read_word( buffer ) );
1360 libspectrum_snap_set_hl ( snap, libspectrum_read_word( buffer ) );
1361
1362 if( ctx->swap_af ) {
1363 libspectrum_snap_set_a_( snap, **buffer ); (*buffer)++;
1364 libspectrum_snap_set_f_( snap, **buffer ); (*buffer)++;
1365 } else {
1366 libspectrum_snap_set_f_( snap, **buffer ); (*buffer)++;
1367 libspectrum_snap_set_a_( snap, **buffer ); (*buffer)++;
1368 }
1369
1370 libspectrum_snap_set_bc_ ( snap, libspectrum_read_word( buffer ) );
1371 libspectrum_snap_set_de_ ( snap, libspectrum_read_word( buffer ) );
1372 libspectrum_snap_set_hl_ ( snap, libspectrum_read_word( buffer ) );
1373
1374 libspectrum_snap_set_ix ( snap, libspectrum_read_word( buffer ) );
1375 libspectrum_snap_set_iy ( snap, libspectrum_read_word( buffer ) );
1376 libspectrum_snap_set_sp ( snap, libspectrum_read_word( buffer ) );
1377 libspectrum_snap_set_pc ( snap, libspectrum_read_word( buffer ) );
1378
1379 libspectrum_snap_set_i ( snap, **buffer ); (*buffer)++;
1380 libspectrum_snap_set_r ( snap, **buffer ); (*buffer)++;
1381 libspectrum_snap_set_iff1( snap, **buffer ); (*buffer)++;
1382 libspectrum_snap_set_iff2( snap, **buffer ); (*buffer)++;
1383 libspectrum_snap_set_im ( snap, **buffer ); (*buffer)++;
1384
1385 libspectrum_snap_set_tstates( snap, libspectrum_read_dword( buffer ) );
1386
1387 if( version >= 0x0101 ) {
1388 (*buffer)++; /* Skip chHoldIntReqCycles */
1389
1390 /* Flags */
1391 libspectrum_snap_set_last_instruction_ei( snap, **buffer & ZXSTZF_EILAST );
1392 libspectrum_snap_set_halted( snap, **buffer & ZXSTZF_HALTED );
1393 libspectrum_snap_set_last_instruction_set_f( snap, **buffer & ZXSTZF_FSET );
1394 (*buffer)++;
1395
1396 if( version >= 0x0104 ) {
1397 libspectrum_snap_set_memptr( snap, libspectrum_read_word( buffer ) );
1398 } else {
1399 (*buffer)++; /* Skip the hidden register */
1400 (*buffer)++; /* Skip the reserved byte */
1401 }
1402
1403 } else {
1404 *buffer += 4; /* Skip the reserved dword */
1405 }
1406
1407 return LIBSPECTRUM_ERROR_NONE;
1408 }
1409
1410 static libspectrum_error
read_zxat_chunk(libspectrum_snap * snap,libspectrum_word version GCC_UNUSED,const libspectrum_byte ** buffer,const libspectrum_byte * end GCC_UNUSED,size_t data_length,szx_context * ctx GCC_UNUSED)1411 read_zxat_chunk( libspectrum_snap *snap, libspectrum_word version GCC_UNUSED,
1412 const libspectrum_byte **buffer,
1413 const libspectrum_byte *end GCC_UNUSED, size_t data_length,
1414 szx_context *ctx GCC_UNUSED )
1415 {
1416 libspectrum_word flags;
1417
1418 if( data_length != 8 ) {
1419 libspectrum_print_error( LIBSPECTRUM_ERROR_UNKNOWN,
1420 "%s:read_zxat_chunk: unknown length %lu",
1421 __FILE__, (unsigned long)data_length );
1422 return LIBSPECTRUM_ERROR_UNKNOWN;
1423 }
1424
1425 libspectrum_snap_set_zxatasp_active( snap, 1 );
1426
1427 flags = libspectrum_read_word( buffer );
1428 libspectrum_snap_set_zxatasp_upload( snap, flags & ZXSTZXATF_UPLOAD );
1429 libspectrum_snap_set_zxatasp_writeprotect( snap,
1430 flags & ZXSTZXATF_WRITEPROTECT );
1431
1432 libspectrum_snap_set_zxatasp_port_a( snap, **buffer ); (*buffer)++;
1433 libspectrum_snap_set_zxatasp_port_b( snap, **buffer ); (*buffer)++;
1434 libspectrum_snap_set_zxatasp_port_c( snap, **buffer ); (*buffer)++;
1435 libspectrum_snap_set_zxatasp_control( snap, **buffer ); (*buffer)++;
1436 libspectrum_snap_set_zxatasp_pages( snap, **buffer ); (*buffer)++;
1437 libspectrum_snap_set_zxatasp_current_page( snap, **buffer ); (*buffer)++;
1438
1439 return LIBSPECTRUM_ERROR_NONE;
1440 }
1441
1442 static libspectrum_error
read_zxcf_chunk(libspectrum_snap * snap,libspectrum_word version GCC_UNUSED,const libspectrum_byte ** buffer,const libspectrum_byte * end GCC_UNUSED,size_t data_length,szx_context * ctx GCC_UNUSED)1443 read_zxcf_chunk( libspectrum_snap *snap, libspectrum_word version GCC_UNUSED,
1444 const libspectrum_byte **buffer,
1445 const libspectrum_byte *end GCC_UNUSED, size_t data_length,
1446 szx_context *ctx GCC_UNUSED )
1447 {
1448 libspectrum_word flags;
1449
1450 if( data_length != 4 ) {
1451 libspectrum_print_error( LIBSPECTRUM_ERROR_UNKNOWN,
1452 "read_zxcf_chunk: unknown length %lu",
1453 (unsigned long)data_length );
1454 return LIBSPECTRUM_ERROR_UNKNOWN;
1455 }
1456
1457 libspectrum_snap_set_zxcf_active( snap, 1 );
1458
1459 flags = libspectrum_read_word( buffer );
1460 libspectrum_snap_set_zxcf_upload( snap, flags & ZXSTZXCFF_UPLOAD );
1461
1462 libspectrum_snap_set_zxcf_memctl( snap, **buffer ); (*buffer)++;
1463 libspectrum_snap_set_zxcf_pages( snap, **buffer ); (*buffer)++;
1464
1465 return LIBSPECTRUM_ERROR_NONE;
1466 }
1467
1468 static libspectrum_error
read_if1_chunk(libspectrum_snap * snap,libspectrum_word version GCC_UNUSED,const libspectrum_byte ** buffer,const libspectrum_byte * end GCC_UNUSED,size_t data_length,szx_context * ctx GCC_UNUSED)1469 read_if1_chunk( libspectrum_snap *snap, libspectrum_word version GCC_UNUSED,
1470 const libspectrum_byte **buffer,
1471 const libspectrum_byte *end GCC_UNUSED, size_t data_length,
1472 szx_context *ctx GCC_UNUSED )
1473 {
1474 libspectrum_word flags;
1475 libspectrum_word expected_length;
1476 libspectrum_byte *rom_data = NULL;
1477
1478 if( data_length < 40 ) {
1479 libspectrum_print_error(
1480 LIBSPECTRUM_ERROR_UNKNOWN,
1481 "read_if1_chunk: length %lu too short", (unsigned long)data_length
1482 );
1483 return LIBSPECTRUM_ERROR_UNKNOWN;
1484 }
1485
1486 flags = libspectrum_read_word( buffer );
1487 libspectrum_snap_set_interface1_drive_count( snap, **buffer ); (*buffer)++;
1488 *buffer += 3; /* Skip reserved byte space */
1489 *buffer += sizeof( libspectrum_dword ) * 8; /* Skip reserved dword space */
1490 expected_length = libspectrum_read_word( buffer );
1491
1492 libspectrum_snap_set_interface1_active( snap, flags & ZXSTIF1F_ENABLED );
1493
1494 libspectrum_snap_set_interface1_paged( snap, flags & ZXSTIF1F_PAGED );
1495
1496 if( expected_length ) {
1497 if( expected_length != 0x2000 && expected_length != 0x4000 ) {
1498 libspectrum_print_error( LIBSPECTRUM_ERROR_UNKNOWN,
1499 "%s:read_if1_chunk: invalid ROM length "
1500 "in file, should be 8192 or 16384 bytes, "
1501 "file has %lu",
1502 __FILE__,
1503 (unsigned long)expected_length );
1504 return LIBSPECTRUM_ERROR_UNKNOWN;
1505 }
1506
1507 libspectrum_snap_set_interface1_custom_rom( snap, 1 );
1508
1509 if( flags & ZXSTIF1F_COMPRESSED ) {
1510
1511 #ifdef HAVE_ZLIB_H
1512
1513 size_t uncompressed_length = 0;
1514
1515 libspectrum_error error =
1516 libspectrum_zlib_inflate( *buffer, data_length - 40, &rom_data,
1517 &uncompressed_length );
1518 if( error ) return error;
1519
1520 if( uncompressed_length != expected_length ) {
1521 libspectrum_print_error( LIBSPECTRUM_ERROR_UNKNOWN,
1522 "%s:read_if1_chunk: invalid ROM length "
1523 "in compressed file, should be %lu, file "
1524 "has %lu",
1525 __FILE__,
1526 (unsigned long)expected_length,
1527 (unsigned long)uncompressed_length );
1528 return LIBSPECTRUM_ERROR_UNKNOWN;
1529 }
1530
1531 libspectrum_snap_set_interface1_rom( snap, 0, rom_data );
1532 libspectrum_snap_set_interface1_rom_length( snap, 0,
1533 uncompressed_length );
1534
1535 *buffer += data_length - 40;
1536
1537 #else /* #ifdef HAVE_ZLIB_H */
1538
1539 libspectrum_print_error(
1540 LIBSPECTRUM_ERROR_UNKNOWN,
1541 "%s:read_if1_chunk: zlib needed for decompression\n",
1542 __FILE__
1543 );
1544 return LIBSPECTRUM_ERROR_UNKNOWN;
1545
1546 #endif /* #ifdef HAVE_ZLIB_H */
1547
1548 } else {
1549
1550 if( data_length < 40 + expected_length ) {
1551 libspectrum_print_error( LIBSPECTRUM_ERROR_UNKNOWN,
1552 "%s:read_if1_chunk: length %lu too short, "
1553 "expected %lu" ,
1554 __FILE__, (unsigned long)data_length,
1555 (unsigned long)40 + expected_length );
1556 return LIBSPECTRUM_ERROR_UNKNOWN;
1557 }
1558
1559 rom_data = libspectrum_malloc( expected_length );
1560 memcpy( rom_data, *buffer, expected_length );
1561
1562 libspectrum_snap_set_interface1_rom_length( snap, 0, expected_length );
1563
1564 *buffer += expected_length;
1565
1566 }
1567 }
1568
1569 return LIBSPECTRUM_ERROR_NONE;
1570 }
1571
1572 static void
szx_set_custom_rom(libspectrum_snap * snap,int page_no,libspectrum_byte * rom_data,libspectrum_word length)1573 szx_set_custom_rom( libspectrum_snap *snap, int page_no,
1574 libspectrum_byte *rom_data, libspectrum_word length )
1575 {
1576 if( length ) {
1577 libspectrum_byte *page = libspectrum_malloc( length );
1578 memcpy( page, rom_data, length );
1579
1580 libspectrum_snap_set_roms( snap, page_no, page );
1581 libspectrum_snap_set_rom_length( snap, page_no, length );
1582 }
1583 }
1584
1585 static libspectrum_error
szx_extract_roms(libspectrum_snap * snap,libspectrum_byte * rom_data,libspectrum_dword length,libspectrum_dword expected_length)1586 szx_extract_roms( libspectrum_snap *snap, libspectrum_byte *rom_data,
1587 libspectrum_dword length, libspectrum_dword expected_length )
1588 {
1589 int i;
1590 const size_t standard_rom_length = 0x4000;
1591 size_t num_16k_roms, additional_rom_length;
1592
1593 if( length != expected_length ) {
1594 libspectrum_print_error( LIBSPECTRUM_ERROR_UNKNOWN,
1595 "%s:szx_extract_roms: invalid ROM length %u, "
1596 "expected %u",
1597 __FILE__, length, expected_length );
1598 return LIBSPECTRUM_ERROR_UNKNOWN;
1599 }
1600
1601 num_16k_roms = length / standard_rom_length;
1602 additional_rom_length = length % standard_rom_length;
1603
1604 for( i = 0; i < num_16k_roms; i++ )
1605 szx_set_custom_rom( snap, i, rom_data + (i * standard_rom_length), standard_rom_length );
1606
1607 /* Timex 2068 machines have a 16k and an 8k ROM, all other machines just have
1608 multiples of 16k ROMs */
1609 if( additional_rom_length )
1610 szx_set_custom_rom( snap, i, rom_data + (i * standard_rom_length), additional_rom_length );
1611
1612 libspectrum_snap_set_custom_rom_pages( snap, num_16k_roms +
1613 !!additional_rom_length );
1614
1615 return LIBSPECTRUM_ERROR_NONE;
1616 }
1617
1618 static libspectrum_error
read_rom_chunk(libspectrum_snap * snap,libspectrum_word version GCC_UNUSED,const libspectrum_byte ** buffer,const libspectrum_byte * end GCC_UNUSED,size_t data_length,szx_context * ctx GCC_UNUSED)1619 read_rom_chunk( libspectrum_snap *snap, libspectrum_word version GCC_UNUSED,
1620 const libspectrum_byte **buffer,
1621 const libspectrum_byte *end GCC_UNUSED, size_t data_length,
1622 szx_context *ctx GCC_UNUSED )
1623 {
1624 libspectrum_word flags;
1625 libspectrum_dword expected_length;
1626 libspectrum_byte *rom_data = NULL;
1627 libspectrum_error retval = LIBSPECTRUM_ERROR_NONE;
1628
1629 if( data_length < 6 ) {
1630 libspectrum_print_error(
1631 LIBSPECTRUM_ERROR_UNKNOWN,
1632 "read_rom_chunk: length %lu too short", (unsigned long)data_length
1633 );
1634 return LIBSPECTRUM_ERROR_UNKNOWN;
1635 }
1636
1637 flags = libspectrum_read_word( buffer );
1638 expected_length = libspectrum_read_dword( buffer );
1639
1640 if( flags & ZXSTRF_COMPRESSED ) {
1641
1642 #ifdef HAVE_ZLIB_H
1643
1644 size_t uncompressed_length = 0;
1645
1646 libspectrum_error error =
1647 libspectrum_zlib_inflate( *buffer, data_length - 6, &rom_data,
1648 &uncompressed_length );
1649 if( error ) return error;
1650
1651 if( uncompressed_length != expected_length ) {
1652 libspectrum_print_error( LIBSPECTRUM_ERROR_UNKNOWN,
1653 "%s:read_rom_chunk: invalid ROM length "
1654 "in compressed file, should be %lu, file "
1655 "has %lu",
1656 __FILE__,
1657 (unsigned long)expected_length,
1658 (unsigned long)uncompressed_length );
1659 return LIBSPECTRUM_ERROR_UNKNOWN;
1660 }
1661
1662 *buffer += data_length - 6;
1663
1664 #else /* #ifdef HAVE_ZLIB_H */
1665
1666 libspectrum_print_error(
1667 LIBSPECTRUM_ERROR_UNKNOWN,
1668 "%s:read_rom_chunk: zlib needed for decompression\n",
1669 __FILE__
1670 );
1671 return LIBSPECTRUM_ERROR_UNKNOWN;
1672
1673 #endif /* #ifdef HAVE_ZLIB_H */
1674
1675 } else {
1676
1677 if( data_length < 6 + expected_length ) {
1678 libspectrum_print_error( LIBSPECTRUM_ERROR_UNKNOWN,
1679 "%s:read_rom_chunk: length %lu too short, "
1680 "expected %lu" ,
1681 __FILE__, (unsigned long)data_length,
1682 (unsigned long)6 + expected_length );
1683 return LIBSPECTRUM_ERROR_UNKNOWN;
1684 }
1685
1686 rom_data = libspectrum_malloc( expected_length );
1687 memcpy( rom_data, *buffer, expected_length );
1688 *buffer += expected_length;
1689 }
1690
1691 libspectrum_snap_set_custom_rom( snap, 1 );
1692
1693 switch ( libspectrum_snap_machine( snap ) ) {
1694 case LIBSPECTRUM_MACHINE_16:
1695 case LIBSPECTRUM_MACHINE_48:
1696 case LIBSPECTRUM_MACHINE_TC2048:
1697 retval = szx_extract_roms( snap, rom_data, expected_length, 0x4000 );
1698 break;
1699 case LIBSPECTRUM_MACHINE_128:
1700 case LIBSPECTRUM_MACHINE_PLUS2:
1701 case LIBSPECTRUM_MACHINE_SE:
1702 retval = szx_extract_roms( snap, rom_data, expected_length, 0x8000 );
1703 break;
1704 case LIBSPECTRUM_MACHINE_PLUS2A:
1705 case LIBSPECTRUM_MACHINE_PLUS3:
1706 case LIBSPECTRUM_MACHINE_PLUS3E:
1707 retval = szx_extract_roms( snap, rom_data, expected_length, 0x10000 );
1708 break;
1709 case LIBSPECTRUM_MACHINE_PENT:
1710 /* FIXME: This is a conflict with Fuse - szx specs say Pentagon 128k snaps
1711 will total 32k, Fuse also has the 'gluck.rom' */
1712 retval = szx_extract_roms( snap, rom_data, expected_length, 0x8000 );
1713 break;
1714 case LIBSPECTRUM_MACHINE_TC2068:
1715 case LIBSPECTRUM_MACHINE_TS2068:
1716 retval = szx_extract_roms( snap, rom_data, expected_length, 0x6000 );
1717 break;
1718 case LIBSPECTRUM_MACHINE_SCORP:
1719 case LIBSPECTRUM_MACHINE_PENT512:
1720 case LIBSPECTRUM_MACHINE_PENT1024:
1721 retval = szx_extract_roms( snap, rom_data, expected_length, 0x10000 );
1722 break;
1723 default:
1724 libspectrum_print_error( LIBSPECTRUM_ERROR_UNKNOWN,
1725 "%s:read_rom_chunk: don't know correct custom ROM "
1726 "length for this machine",
1727 __FILE__ );
1728 retval = LIBSPECTRUM_ERROR_UNKNOWN;
1729 break;
1730 }
1731
1732 libspectrum_free( rom_data );
1733
1734 return retval;
1735 }
1736
1737 static libspectrum_error
read_zxpr_chunk(libspectrum_snap * snap,libspectrum_word version,const libspectrum_byte ** buffer,const libspectrum_byte * end GCC_UNUSED,size_t data_length,szx_context * ctx GCC_UNUSED)1738 read_zxpr_chunk( libspectrum_snap *snap, libspectrum_word version,
1739 const libspectrum_byte **buffer,
1740 const libspectrum_byte *end GCC_UNUSED, size_t data_length,
1741 szx_context *ctx GCC_UNUSED )
1742 {
1743 libspectrum_word flags;
1744
1745 if( data_length != 2 ) {
1746 libspectrum_print_error( LIBSPECTRUM_ERROR_UNKNOWN,
1747 "%s:read_zxpr_chunk: unknown length %lu",
1748 __FILE__, (unsigned long)data_length );
1749 return LIBSPECTRUM_ERROR_UNKNOWN;
1750 }
1751
1752 flags = libspectrum_read_word( buffer );
1753 libspectrum_snap_set_zx_printer_active( snap, flags & ZXSTPRF_ENABLED );
1754
1755 return LIBSPECTRUM_ERROR_NONE;
1756 }
1757
1758 static libspectrum_error
read_if2r_chunk(libspectrum_snap * snap,libspectrum_word version GCC_UNUSED,const libspectrum_byte ** buffer,const libspectrum_byte * end GCC_UNUSED,size_t data_length,szx_context * ctx GCC_UNUSED)1759 read_if2r_chunk( libspectrum_snap *snap, libspectrum_word version GCC_UNUSED,
1760 const libspectrum_byte **buffer,
1761 const libspectrum_byte *end GCC_UNUSED, size_t data_length,
1762 szx_context *ctx GCC_UNUSED )
1763 {
1764
1765 #ifdef HAVE_ZLIB_H
1766
1767 libspectrum_byte *buffer2;
1768
1769 size_t uncompressed_length;
1770
1771 libspectrum_error error;
1772
1773 if( data_length < 4 ) {
1774 libspectrum_print_error(
1775 LIBSPECTRUM_ERROR_UNKNOWN,
1776 "read_if2r_chunk: length %lu too short", (unsigned long)data_length
1777 );
1778 return LIBSPECTRUM_ERROR_UNKNOWN;
1779 }
1780
1781 /* Skip the compressed length as we never actually use it - bug? */
1782 libspectrum_read_dword( buffer );
1783
1784 uncompressed_length = 0x4000;
1785
1786 error = libspectrum_zlib_inflate( *buffer, data_length - 4, &buffer2,
1787 &uncompressed_length );
1788 if( error ) return error;
1789
1790 *buffer += data_length - 4;
1791
1792 libspectrum_snap_set_interface2_active( snap, 1 );
1793
1794 libspectrum_snap_set_interface2_rom( snap, 0, buffer2 );
1795
1796 return LIBSPECTRUM_ERROR_NONE;
1797
1798 #else /* #ifdef HAVE_ZLIB_H */
1799
1800 libspectrum_print_error(
1801 LIBSPECTRUM_ERROR_UNKNOWN,
1802 "%s:read_if2r_chunk: zlib needed for decompression\n",
1803 __FILE__
1804 );
1805 return LIBSPECTRUM_ERROR_UNKNOWN;
1806
1807 #endif /* #ifdef HAVE_ZLIB_H */
1808
1809 }
1810
1811 static libspectrum_error
read_dock_chunk(libspectrum_snap * snap,libspectrum_word version GCC_UNUSED,const libspectrum_byte ** buffer,const libspectrum_byte * end GCC_UNUSED,size_t data_length,szx_context * ctx GCC_UNUSED)1812 read_dock_chunk( libspectrum_snap *snap, libspectrum_word version GCC_UNUSED,
1813 const libspectrum_byte **buffer,
1814 const libspectrum_byte *end GCC_UNUSED, size_t data_length,
1815 szx_context *ctx GCC_UNUSED )
1816 {
1817 libspectrum_byte *data;
1818 size_t page;
1819 libspectrum_error error;
1820 libspectrum_word flags;
1821 libspectrum_byte writeable;
1822
1823 error = read_ram_page( &data, &page, buffer, data_length, 0x2000, &flags );
1824 if( error ) return error;
1825
1826 if( page > 7 ) {
1827 libspectrum_print_error( LIBSPECTRUM_ERROR_CORRUPT,
1828 "%s:read_dock_chunk: unknown page number %ld",
1829 __FILE__, (unsigned long)page );
1830 libspectrum_free( data );
1831 return LIBSPECTRUM_ERROR_CORRUPT;
1832 }
1833
1834 libspectrum_snap_set_dock_active( snap, 1 );
1835
1836 writeable = flags & ZXSTDOCKF_RAM;
1837
1838 if( flags & ZXSTDOCKF_EXROMDOCK ) {
1839 libspectrum_snap_set_dock_ram( snap, page, writeable );
1840 libspectrum_snap_set_dock_cart( snap, page, data );
1841 } else {
1842 libspectrum_snap_set_exrom_ram( snap, page, writeable );
1843 libspectrum_snap_set_exrom_cart( snap, page, data );
1844 }
1845
1846 return LIBSPECTRUM_ERROR_NONE;
1847 }
1848
1849 static libspectrum_error
read_dide_chunk(libspectrum_snap * snap,libspectrum_word version GCC_UNUSED,const libspectrum_byte ** buffer,const libspectrum_byte * end GCC_UNUSED,size_t data_length,szx_context * ctx GCC_UNUSED)1850 read_dide_chunk( libspectrum_snap *snap, libspectrum_word version GCC_UNUSED,
1851 const libspectrum_byte **buffer,
1852 const libspectrum_byte *end GCC_UNUSED, size_t data_length,
1853 szx_context *ctx GCC_UNUSED )
1854 {
1855 #ifdef HAVE_ZLIB_H
1856 libspectrum_error error;
1857 #endif
1858 libspectrum_word flags;
1859 libspectrum_byte *eprom_data = NULL;
1860 const size_t expected_length = 0x2000;
1861
1862 if( data_length < 4 ) {
1863 libspectrum_print_error( LIBSPECTRUM_ERROR_UNKNOWN,
1864 "%s:read_dide_chunk: unknown length %lu",
1865 __FILE__, (unsigned long)data_length );
1866 return LIBSPECTRUM_ERROR_UNKNOWN;
1867 }
1868
1869 flags = libspectrum_read_word( buffer );
1870 libspectrum_snap_set_divide_active( snap, 1 );
1871 libspectrum_snap_set_divide_eprom_writeprotect(
1872 snap,
1873 !!(flags & ZXSTDIVIDE_EPROM_WRITEPROTECT)
1874 );
1875 libspectrum_snap_set_divide_paged( snap, !!(flags & ZXSTDIVIDE_PAGED) );
1876
1877 libspectrum_snap_set_divide_control( snap, **buffer ); (*buffer)++;
1878 libspectrum_snap_set_divide_pages( snap, **buffer ); (*buffer)++;
1879
1880 if( flags & ZXSTDIVIDE_COMPRESSED ) {
1881
1882 #ifdef HAVE_ZLIB_H
1883
1884 size_t uncompressed_length = 0;
1885
1886 error = libspectrum_zlib_inflate( *buffer, data_length - 4, &eprom_data,
1887 &uncompressed_length );
1888 if( error ) return error;
1889
1890 if( uncompressed_length != expected_length ) {
1891 libspectrum_print_error( LIBSPECTRUM_ERROR_UNKNOWN,
1892 "%s:read_dide_chunk: invalid EPROM length "
1893 "in compressed file, should be %lu, file "
1894 "has %lu",
1895 __FILE__,
1896 (unsigned long)expected_length,
1897 (unsigned long)uncompressed_length );
1898 return LIBSPECTRUM_ERROR_UNKNOWN;
1899 }
1900
1901 *buffer += data_length - 4;
1902
1903 #else
1904
1905 libspectrum_print_error(
1906 LIBSPECTRUM_ERROR_UNKNOWN,
1907 "%s:read_dide_chunk: zlib needed for decompression\n",
1908 __FILE__
1909 );
1910 return LIBSPECTRUM_ERROR_UNKNOWN;
1911
1912 #endif
1913
1914 } else {
1915
1916 if( data_length < 4 + expected_length ) {
1917 libspectrum_print_error( LIBSPECTRUM_ERROR_UNKNOWN,
1918 "%s:read_dide_chunk: length %lu too short, "
1919 "expected %lu",
1920 __FILE__, (unsigned long)data_length,
1921 (unsigned long)4 + expected_length );
1922 return LIBSPECTRUM_ERROR_UNKNOWN;
1923 }
1924
1925 eprom_data = libspectrum_malloc( expected_length );
1926 memcpy( eprom_data, *buffer, expected_length );
1927
1928 *buffer += expected_length;
1929
1930 }
1931
1932 libspectrum_snap_set_divide_eprom( snap, 0, eprom_data );
1933
1934 return LIBSPECTRUM_ERROR_NONE;
1935 }
1936
1937 static libspectrum_error
read_dirp_chunk(libspectrum_snap * snap,libspectrum_word version GCC_UNUSED,const libspectrum_byte ** buffer,const libspectrum_byte * end GCC_UNUSED,size_t data_length,szx_context * ctx GCC_UNUSED)1938 read_dirp_chunk( libspectrum_snap *snap, libspectrum_word version GCC_UNUSED,
1939 const libspectrum_byte **buffer,
1940 const libspectrum_byte *end GCC_UNUSED, size_t data_length,
1941 szx_context *ctx GCC_UNUSED )
1942 {
1943 libspectrum_byte *data;
1944 size_t page;
1945 libspectrum_error error;
1946 libspectrum_word flags;
1947
1948 error = read_ram_page( &data, &page, buffer, data_length, 0x2000, &flags );
1949 if( error ) return error;
1950
1951 if( page >= SNAPSHOT_DIVIDE_PAGES ) {
1952 libspectrum_print_error( LIBSPECTRUM_ERROR_CORRUPT,
1953 "%s:read_dirp_chunk: unknown page number %lu",
1954 __FILE__, (unsigned long)page );
1955 libspectrum_free( data );
1956 return LIBSPECTRUM_ERROR_CORRUPT;
1957 }
1958
1959 libspectrum_snap_set_divide_ram( snap, page, data );
1960
1961 return LIBSPECTRUM_ERROR_NONE;
1962 }
1963
1964 static libspectrum_error
read_snet_memory(libspectrum_snap * snap,const libspectrum_byte ** buffer,int compressed,size_t * data_remaining,void (* setter)(libspectrum_snap *,int,libspectrum_byte *))1965 read_snet_memory( libspectrum_snap *snap, const libspectrum_byte **buffer,
1966 int compressed, size_t *data_remaining,
1967 void (*setter)(libspectrum_snap*, int, libspectrum_byte*) )
1968 {
1969 size_t data_length;
1970 libspectrum_byte *data_out;
1971 const libspectrum_byte *data;
1972
1973 if( *data_remaining < 4 ) {
1974 libspectrum_print_error( LIBSPECTRUM_ERROR_UNKNOWN,
1975 "%s:read_snet_memory: not enough data for length", __FILE__ );
1976 return LIBSPECTRUM_ERROR_UNKNOWN;
1977 }
1978
1979 data_length = libspectrum_read_dword( buffer );
1980 *data_remaining -= 4;
1981
1982 if( *data_remaining < data_length ) {
1983 libspectrum_print_error( LIBSPECTRUM_ERROR_UNKNOWN,
1984 "%s:read_snet_memory: not enough data", __FILE__ );
1985 return LIBSPECTRUM_ERROR_UNKNOWN;
1986 }
1987 *data_remaining -= data_length;
1988
1989 if( compressed ) {
1990
1991 #ifdef HAVE_ZLIB_H
1992 libspectrum_error error;
1993 size_t uncompressed_length = 0;
1994 libspectrum_byte *uncompressed_data;
1995
1996 error = libspectrum_zlib_inflate( *buffer, data_length, &uncompressed_data,
1997 &uncompressed_length );
1998 if( error ) return error;
1999
2000 *buffer += data_length;
2001
2002 if( uncompressed_length != 0x20000 ) {
2003 libspectrum_print_error( LIBSPECTRUM_ERROR_UNKNOWN,
2004 "%s:read_snet_memory: data decompressed to %lu but should be 0x20000",
2005 __FILE__, (unsigned long)uncompressed_length );
2006 libspectrum_free( uncompressed_data );
2007 return LIBSPECTRUM_ERROR_UNKNOWN;
2008 }
2009
2010 data = uncompressed_data;
2011
2012 #else
2013
2014 libspectrum_print_error( LIBSPECTRUM_ERROR_UNKNOWN,
2015 "%s:read_snet_memory: zlib needed for decompression\n", __FILE__ );
2016 return LIBSPECTRUM_ERROR_UNKNOWN;
2017
2018 #endif
2019
2020 } else {
2021 if( data_length != 0x20000 ) {
2022 libspectrum_print_error( LIBSPECTRUM_ERROR_UNKNOWN,
2023 "%s:read_snet_memory: data has length %lu but should be 0x20000",
2024 __FILE__, (unsigned long)data_length );
2025 return LIBSPECTRUM_ERROR_NONE;
2026 }
2027
2028 data = *buffer;
2029 *buffer += data_length;
2030 }
2031
2032 data_out = libspectrum_malloc( 0x20000 );
2033 memcpy( data_out, data, 0x20000 );
2034 setter( snap, 0, data_out );
2035
2036 return LIBSPECTRUM_ERROR_NONE;
2037 }
2038
2039 static libspectrum_error
read_snet_chunk(libspectrum_snap * snap,libspectrum_word version GCC_UNUSED,const libspectrum_byte ** buffer,const libspectrum_byte * end GCC_UNUSED,size_t data_length,szx_context * ctx GCC_UNUSED)2040 read_snet_chunk( libspectrum_snap *snap, libspectrum_word version GCC_UNUSED,
2041 const libspectrum_byte **buffer,
2042 const libspectrum_byte *end GCC_UNUSED, size_t data_length,
2043 szx_context *ctx GCC_UNUSED )
2044 {
2045 libspectrum_word flags;
2046 libspectrum_byte *w5100;
2047
2048 if( data_length < 54 ) {
2049 libspectrum_print_error(
2050 LIBSPECTRUM_ERROR_UNKNOWN,
2051 "read_snet_chunk: length %lu too short", (unsigned long)data_length
2052 );
2053 return LIBSPECTRUM_ERROR_UNKNOWN;
2054 }
2055
2056 libspectrum_snap_set_spectranet_active( snap, 1 );
2057
2058 flags = libspectrum_read_word( buffer );
2059 libspectrum_snap_set_spectranet_paged( snap, flags & ZXSTSNET_PAGED );
2060 libspectrum_snap_set_spectranet_paged_via_io( snap, flags & ZXSTSNET_PAGED_VIA_IO );
2061 libspectrum_snap_set_spectranet_programmable_trap_active( snap,
2062 flags & ZXSTSNET_PROGRAMMABLE_TRAP_ACTIVE );
2063 libspectrum_snap_set_spectranet_programmable_trap_msb( snap,
2064 flags & ZXSTSNET_PROGRAMMABLE_TRAP_MSB );
2065 libspectrum_snap_set_spectranet_all_traps_disabled( snap, flags & ZXSTSNET_ALL_DISABLED );
2066 libspectrum_snap_set_spectranet_rst8_trap_disabled( snap, flags & ZXSTSNET_RST8_DISABLED );
2067 libspectrum_snap_set_spectranet_deny_downstream_a15( snap, flags & ZXSTSNET_DENY_DOWNSTREAM_A15 );
2068 libspectrum_snap_set_spectranet_nmi_flipflop( snap, flags & ZXSTSNET_NMI_FLIPFLOP );
2069
2070 libspectrum_snap_set_spectranet_page_a( snap, **buffer ); (*buffer)++;
2071 libspectrum_snap_set_spectranet_page_b( snap, **buffer ); (*buffer)++;
2072
2073 libspectrum_snap_set_spectranet_programmable_trap( snap,
2074 libspectrum_read_word( buffer ) );
2075
2076 w5100 = libspectrum_malloc( 0x30 * sizeof( libspectrum_byte ) );
2077 libspectrum_snap_set_spectranet_w5100( snap, 0, w5100 );
2078 memcpy( w5100, *buffer, 0x30 );
2079 (*buffer) += 0x30;
2080
2081 return LIBSPECTRUM_ERROR_NONE;
2082 }
2083
2084 static libspectrum_error
read_snef_chunk(libspectrum_snap * snap,libspectrum_word version GCC_UNUSED,const libspectrum_byte ** buffer,const libspectrum_byte * end GCC_UNUSED,size_t data_length,szx_context * ctx GCC_UNUSED)2085 read_snef_chunk( libspectrum_snap *snap, libspectrum_word version GCC_UNUSED,
2086 const libspectrum_byte **buffer,
2087 const libspectrum_byte *end GCC_UNUSED, size_t data_length,
2088 szx_context *ctx GCC_UNUSED )
2089 {
2090 libspectrum_byte flags;
2091 int flash_compressed;
2092 libspectrum_error error;
2093 size_t data_remaining;
2094
2095 if( data_length < 5 ) {
2096 libspectrum_print_error(
2097 LIBSPECTRUM_ERROR_UNKNOWN,
2098 "read_snef_chunk: length %lu too short", (unsigned long)data_length
2099 );
2100 return LIBSPECTRUM_ERROR_UNKNOWN;
2101 }
2102
2103 flags = **buffer; (*buffer)++;
2104 flash_compressed = flags & ZXSTSNEF_FLASH_COMPRESSED;
2105
2106 data_remaining = data_length - 1;
2107
2108 error = read_snet_memory( snap, buffer, flash_compressed, &data_remaining,
2109 libspectrum_snap_set_spectranet_flash );
2110 if( error )
2111 return error;
2112
2113 return LIBSPECTRUM_ERROR_NONE;
2114 }
2115
2116 static libspectrum_error
read_sner_chunk(libspectrum_snap * snap,libspectrum_word version GCC_UNUSED,const libspectrum_byte ** buffer,const libspectrum_byte * end GCC_UNUSED,size_t data_length,szx_context * ctx GCC_UNUSED)2117 read_sner_chunk( libspectrum_snap *snap, libspectrum_word version GCC_UNUSED,
2118 const libspectrum_byte **buffer,
2119 const libspectrum_byte *end GCC_UNUSED, size_t data_length,
2120 szx_context *ctx GCC_UNUSED )
2121 {
2122 libspectrum_byte flags;
2123 int ram_compressed;
2124 libspectrum_error error;
2125 size_t data_remaining;
2126
2127 if( data_length < 5 ) {
2128 libspectrum_print_error(
2129 LIBSPECTRUM_ERROR_UNKNOWN,
2130 "read_sner_chunk: length %lu too short", (unsigned long)data_length
2131 );
2132 return LIBSPECTRUM_ERROR_UNKNOWN;
2133 }
2134
2135 flags = **buffer; (*buffer)++;
2136 ram_compressed = flags & ZXSTSNER_RAM_COMPRESSED;
2137
2138 data_remaining = data_length - 1;
2139
2140 error = read_snet_memory( snap, buffer, ram_compressed, &data_remaining,
2141 libspectrum_snap_set_spectranet_ram );
2142 if( error )
2143 return error;
2144
2145 return LIBSPECTRUM_ERROR_NONE;
2146 }
2147
2148 static libspectrum_error
skip_chunk(libspectrum_snap * snap GCC_UNUSED,libspectrum_word version GCC_UNUSED,const libspectrum_byte ** buffer,const libspectrum_byte * end GCC_UNUSED,size_t data_length,szx_context * ctx GCC_UNUSED)2149 skip_chunk( libspectrum_snap *snap GCC_UNUSED,
2150 libspectrum_word version GCC_UNUSED,
2151 const libspectrum_byte **buffer,
2152 const libspectrum_byte *end GCC_UNUSED,
2153 size_t data_length,
2154 szx_context *ctx GCC_UNUSED )
2155 {
2156 *buffer += data_length;
2157 return LIBSPECTRUM_ERROR_NONE;
2158 }
2159
2160 struct read_chunk_t {
2161
2162 const char *id;
2163 read_chunk_fn function;
2164
2165 };
2166
2167 static struct read_chunk_t read_chunks[] = {
2168
2169 { ZXSTBID_AY, read_ay_chunk },
2170 { ZXSTBID_BETA128, read_b128_chunk },
2171 { ZXSTBID_BETADISK, skip_chunk },
2172 { ZXSTBID_COVOX, skip_chunk },
2173 { ZXSTBID_CREATOR, read_crtr_chunk },
2174 { ZXSTBID_DIVIDE, read_dide_chunk },
2175 { ZXSTBID_DIVIDERAMPAGE, read_dirp_chunk },
2176 { ZXSTBID_DOCK, read_dock_chunk },
2177 { ZXSTBID_DSKFILE, skip_chunk },
2178 { ZXSTBID_LEC, skip_chunk },
2179 { ZXSTBID_LECRAMPAGE, skip_chunk },
2180 { ZXSTBID_GS, skip_chunk },
2181 { ZXSTBID_GSRAMPAGE, skip_chunk },
2182 { ZXSTBID_IF1, read_if1_chunk },
2183 { ZXSTBID_IF2ROM, read_if2r_chunk },
2184 { ZXSTBID_JOYSTICK, read_joy_chunk },
2185 { ZXSTBID_KEYBOARD, read_keyb_chunk },
2186 { ZXSTBID_MICRODRIVE, skip_chunk },
2187 { ZXSTBID_MOUSE, read_amxm_chunk },
2188 { ZXSTBID_MULTIFACE, skip_chunk },
2189 { ZXSTBID_OPUS, read_opus_chunk },
2190 { ZXSTBID_OPUSDISK, skip_chunk },
2191 { ZXSTBID_PLUS3DISK, skip_chunk },
2192 { ZXSTBID_PLUSD, read_plsd_chunk },
2193 { ZXSTBID_PLUSDDISK, skip_chunk },
2194 { ZXSTBID_RAMPAGE, read_ramp_chunk },
2195 { ZXSTBID_ROM, read_rom_chunk },
2196 { ZXSTBID_SIMPLEIDE, read_side_chunk },
2197 { ZXSTBID_SPECDRUM, read_drum_chunk },
2198 { ZXSTBID_SPECREGS, read_spcr_chunk },
2199 { ZXSTBID_SPECTRANET, read_snet_chunk },
2200 { ZXSTBID_SPECTRANETFLASHPAGE, read_snef_chunk },
2201 { ZXSTBID_SPECTRANETRAMPAGE, read_sner_chunk },
2202 { ZXSTBID_TIMEXREGS, read_scld_chunk },
2203 { ZXSTBID_USPEECH, skip_chunk },
2204 { ZXSTBID_Z80REGS, read_z80r_chunk },
2205 { ZXSTBID_ZXATASPRAMPAGE, read_atrp_chunk },
2206 { ZXSTBID_ZXATASP, read_zxat_chunk },
2207 { ZXSTBID_ZXCF, read_zxcf_chunk },
2208 { ZXSTBID_ZXCFRAMPAGE, read_cfrp_chunk },
2209 { ZXSTBID_ZXPRINTER, read_zxpr_chunk },
2210 { ZXSTBID_ZXTAPE, skip_chunk },
2211
2212 };
2213
2214 static size_t read_chunks_count =
2215 sizeof( read_chunks ) / sizeof( struct read_chunk_t );
2216
2217 static libspectrum_error
read_chunk_header(char * id,libspectrum_dword * data_length,const libspectrum_byte ** buffer,const libspectrum_byte * end)2218 read_chunk_header( char *id, libspectrum_dword *data_length,
2219 const libspectrum_byte **buffer,
2220 const libspectrum_byte *end )
2221 {
2222 if( end - *buffer < 8 ) {
2223 libspectrum_print_error(
2224 LIBSPECTRUM_ERROR_CORRUPT,
2225 "szx_read_chunk_header: not enough data for chunk header"
2226 );
2227 return LIBSPECTRUM_ERROR_CORRUPT;
2228 }
2229
2230 memcpy( id, *buffer, 4 ); id[4] = '\0'; *buffer += 4;
2231 *data_length = libspectrum_read_dword( buffer );
2232
2233 return LIBSPECTRUM_ERROR_NONE;
2234 }
2235
2236 static libspectrum_error
read_chunk(libspectrum_snap * snap,libspectrum_word version,const libspectrum_byte ** buffer,const libspectrum_byte * end,szx_context * ctx)2237 read_chunk( libspectrum_snap *snap, libspectrum_word version,
2238 const libspectrum_byte **buffer, const libspectrum_byte *end,
2239 szx_context *ctx )
2240 {
2241 char id[5];
2242 libspectrum_dword data_length;
2243 libspectrum_error error;
2244 size_t i; int done;
2245
2246 error = read_chunk_header( id, &data_length, buffer, end );
2247 if( error ) return error;
2248
2249 if( *buffer + data_length > end || *buffer + data_length < *buffer ) {
2250 libspectrum_print_error(
2251 LIBSPECTRUM_ERROR_CORRUPT,
2252 "szx_read_chunk: chunk length goes beyond end of file"
2253 );
2254 return LIBSPECTRUM_ERROR_CORRUPT;
2255 }
2256
2257 done = 0;
2258
2259 for( i = 0; !done && i < read_chunks_count; i++ ) {
2260
2261 if( !memcmp( id, read_chunks[i].id, 4 ) ) {
2262 error = read_chunks[i].function( snap, version, buffer, end,
2263 data_length, ctx );
2264 if( error ) return error;
2265 done = 1;
2266 }
2267
2268 }
2269
2270 if( !done ) {
2271 libspectrum_print_error( LIBSPECTRUM_ERROR_UNKNOWN,
2272 "szx_read_chunk: unknown chunk id '%s'", id );
2273 *buffer += data_length;
2274 }
2275
2276 return LIBSPECTRUM_ERROR_NONE;
2277 }
2278
2279 libspectrum_error
libspectrum_szx_read(libspectrum_snap * snap,const libspectrum_byte * buffer,size_t length)2280 libspectrum_szx_read( libspectrum_snap *snap, const libspectrum_byte *buffer,
2281 size_t length )
2282 {
2283 libspectrum_word version;
2284 libspectrum_byte machine;
2285 libspectrum_byte flags;
2286
2287 libspectrum_error error;
2288 const libspectrum_byte *end = buffer + length;
2289 szx_context *ctx;
2290
2291 if( end - buffer < 8 ) {
2292 libspectrum_print_error(
2293 LIBSPECTRUM_ERROR_CORRUPT,
2294 "libspectrum_szx_read: not enough data for SZX header"
2295 );
2296 return LIBSPECTRUM_ERROR_CORRUPT;
2297 }
2298
2299 if( memcmp( buffer, signature, signature_length ) ) {
2300 libspectrum_print_error(
2301 LIBSPECTRUM_ERROR_SIGNATURE,
2302 "libspectrum_szx_read: wrong signature"
2303 );
2304 return LIBSPECTRUM_ERROR_SIGNATURE;
2305 }
2306 buffer += signature_length;
2307
2308 version = (*buffer++) << 8; version |= *buffer++;
2309
2310 machine = *buffer++;
2311
2312 switch( machine ) {
2313
2314 case SZX_MACHINE_16:
2315 libspectrum_snap_set_machine( snap, LIBSPECTRUM_MACHINE_16 );
2316 break;
2317
2318 case SZX_MACHINE_48:
2319 libspectrum_snap_set_machine( snap, LIBSPECTRUM_MACHINE_48 );
2320 break;
2321
2322 case SZX_MACHINE_48_NTSC:
2323 libspectrum_snap_set_machine( snap, LIBSPECTRUM_MACHINE_48_NTSC );
2324 break;
2325
2326 case SZX_MACHINE_128:
2327 libspectrum_snap_set_machine( snap, LIBSPECTRUM_MACHINE_128 );
2328 break;
2329
2330 case SZX_MACHINE_PLUS2:
2331 libspectrum_snap_set_machine( snap, LIBSPECTRUM_MACHINE_PLUS2 );
2332 break;
2333
2334 case SZX_MACHINE_PLUS2A:
2335 libspectrum_snap_set_machine( snap, LIBSPECTRUM_MACHINE_PLUS2A );
2336 break;
2337
2338 case SZX_MACHINE_PLUS3:
2339 libspectrum_snap_set_machine( snap, LIBSPECTRUM_MACHINE_PLUS3 );
2340 break;
2341
2342 case SZX_MACHINE_PLUS3E:
2343 libspectrum_snap_set_machine( snap, LIBSPECTRUM_MACHINE_PLUS3E );
2344 break;
2345
2346 case SZX_MACHINE_PENTAGON:
2347 libspectrum_snap_set_machine( snap, LIBSPECTRUM_MACHINE_PENT );
2348 break;
2349
2350 case SZX_MACHINE_TC2048:
2351 libspectrum_snap_set_machine( snap, LIBSPECTRUM_MACHINE_TC2048 );
2352 break;
2353
2354 case SZX_MACHINE_TC2068:
2355 libspectrum_snap_set_machine( snap, LIBSPECTRUM_MACHINE_TC2068 );
2356 break;
2357
2358 case SZX_MACHINE_TS2068:
2359 libspectrum_snap_set_machine( snap, LIBSPECTRUM_MACHINE_TS2068 );
2360 break;
2361
2362 case SZX_MACHINE_SCORPION:
2363 libspectrum_snap_set_machine( snap, LIBSPECTRUM_MACHINE_SCORP );
2364 break;
2365
2366 case SZX_MACHINE_SE:
2367 libspectrum_snap_set_machine( snap, LIBSPECTRUM_MACHINE_SE );
2368 break;
2369
2370 case SZX_MACHINE_PENTAGON512:
2371 libspectrum_snap_set_machine( snap, LIBSPECTRUM_MACHINE_PENT512 );
2372 break;
2373
2374 case SZX_MACHINE_PENTAGON1024:
2375 libspectrum_snap_set_machine( snap, LIBSPECTRUM_MACHINE_PENT1024 );
2376 break;
2377
2378 case SZX_MACHINE_128KE:
2379 libspectrum_snap_set_machine( snap, LIBSPECTRUM_MACHINE_128E );
2380 break;
2381
2382 default:
2383 libspectrum_print_error(
2384 LIBSPECTRUM_ERROR_UNKNOWN,
2385 "libspectrum_szx_read: unknown machine type %d", (int)*buffer
2386 );
2387 return LIBSPECTRUM_ERROR_UNKNOWN;
2388 }
2389
2390 flags = *buffer++;
2391
2392 switch( machine ) {
2393
2394 case SZX_MACHINE_16:
2395 case SZX_MACHINE_48:
2396 case SZX_MACHINE_48_NTSC:
2397 case SZX_MACHINE_128:
2398 libspectrum_snap_set_late_timings( snap, flags & ZXSTMF_ALTERNATETIMINGS );
2399 break;
2400
2401 default:
2402 break;
2403 }
2404
2405 ctx = libspectrum_malloc( sizeof( *ctx ) );
2406 ctx->swap_af = 0;
2407
2408 while( buffer < end ) {
2409 error = read_chunk( snap, version, &buffer, end, ctx );
2410 if( error ) {
2411 libspectrum_free( ctx );
2412 return error;
2413 }
2414 }
2415
2416 libspectrum_free( ctx );
2417 return LIBSPECTRUM_ERROR_NONE;
2418 }
2419
2420 libspectrum_error
libspectrum_szx_write(libspectrum_byte ** buffer,size_t * length,int * out_flags,libspectrum_snap * snap,libspectrum_creator * creator,int in_flags)2421 libspectrum_szx_write( libspectrum_byte **buffer, size_t *length,
2422 int *out_flags, libspectrum_snap *snap,
2423 libspectrum_creator *creator, int in_flags )
2424 {
2425 libspectrum_byte *ptr = *buffer;
2426 int capabilities, compress;
2427 libspectrum_error error;
2428 size_t i;
2429
2430 *out_flags = 0;
2431
2432 capabilities =
2433 libspectrum_machine_capabilities( libspectrum_snap_machine( snap ) );
2434
2435 compress = !( in_flags & LIBSPECTRUM_FLAG_SNAPSHOT_NO_COMPRESSION );
2436
2437 error = write_file_header( buffer, &ptr, length, out_flags, snap );
2438 if( error ) return error;
2439
2440 if( creator ) {
2441 error = write_crtr_chunk( buffer, &ptr, length, creator );
2442 if( error ) return error;
2443 }
2444
2445 error = write_z80r_chunk( buffer, &ptr, length, snap );
2446 if( error ) return error;
2447
2448 error = write_spcr_chunk( buffer, &ptr, length, snap );
2449 if( error ) return error;
2450
2451 error = write_joy_chunk( buffer, &ptr, length, out_flags, snap );
2452 if( error ) return error;
2453
2454 error = write_keyb_chunk( buffer, &ptr, length, out_flags, snap );
2455 if( error ) return error;
2456
2457 if( libspectrum_snap_custom_rom( snap ) ) {
2458 error = write_rom_chunk( buffer, &ptr, length, out_flags, snap, compress );
2459 if( error ) return error;
2460 }
2461
2462
2463 error = write_ram_pages( buffer, &ptr, length, snap, compress );
2464 if( error ) return error;
2465
2466 if( libspectrum_snap_fuller_box_active( snap ) ||
2467 libspectrum_snap_melodik_active( snap ) ||
2468 capabilities & LIBSPECTRUM_MACHINE_CAPABILITY_AY ) {
2469 error = write_ay_chunk( buffer, &ptr, length, snap );
2470 if( error ) return error;
2471 }
2472
2473 if( capabilities & ( LIBSPECTRUM_MACHINE_CAPABILITY_TIMEX_MEMORY |
2474 LIBSPECTRUM_MACHINE_CAPABILITY_SE_MEMORY ) ) {
2475 error = write_scld_chunk( buffer, &ptr, length, snap );
2476 if( error ) return error;
2477 }
2478
2479 if( libspectrum_snap_beta_active( snap ) ) {
2480 error = write_b128_chunk( buffer, &ptr, length, snap, compress );
2481 if( error ) return error;
2482 }
2483
2484 if( libspectrum_snap_zxatasp_active( snap ) ) {
2485 error = write_zxat_chunk( buffer, &ptr, length, snap );
2486 if( error ) return error;
2487
2488 for( i = 0; i < libspectrum_snap_zxatasp_pages( snap ); i++ ) {
2489 error = write_atrp_chunk( buffer, &ptr, length, snap, i, compress );
2490 if( error ) return error;
2491 }
2492 }
2493
2494 if( libspectrum_snap_zxcf_active( snap ) ) {
2495 error = write_zxcf_chunk( buffer, &ptr, length, snap );
2496 if( error ) return error;
2497
2498 for( i = 0; i < libspectrum_snap_zxcf_pages( snap ); i++ ) {
2499 error = write_cfrp_chunk( buffer, &ptr, length, snap, i, compress );
2500 if( error ) return error;
2501 }
2502 }
2503
2504 if( libspectrum_snap_interface2_active( snap ) ) {
2505 #ifdef HAVE_ZLIB_H
2506 error = write_if2r_chunk( buffer, &ptr, length, snap );
2507 if( error ) return error;
2508 #else
2509 /* IF2R blocks only support writing compressed images */
2510 *out_flags |= LIBSPECTRUM_FLAG_SNAPSHOT_MAJOR_INFO_LOSS;
2511 #endif /* #ifdef HAVE_ZLIB_H */
2512 }
2513
2514 if( libspectrum_snap_dock_active( snap ) ) {
2515 for( i = 0; i < 8; i++ ) {
2516 if( libspectrum_snap_exrom_cart( snap, i ) ) {
2517 error = write_dock_chunk( buffer, &ptr, length, snap, 0,
2518 libspectrum_snap_exrom_cart( snap, i ), i,
2519 libspectrum_snap_exrom_ram( snap, i ),
2520 compress );
2521 if( error ) return error;
2522 }
2523 if( libspectrum_snap_dock_cart( snap, i ) ) {
2524 error = write_dock_chunk( buffer, &ptr, length, snap, 1,
2525 libspectrum_snap_dock_cart( snap, i ), i,
2526 libspectrum_snap_dock_ram( snap, i ),
2527 compress );
2528 if( error ) return error;
2529 }
2530 }
2531 }
2532
2533 if( libspectrum_snap_interface1_active( snap ) ) {
2534 error = write_if1_chunk( buffer, &ptr, length, snap, compress );
2535 if( error ) return error;
2536 }
2537
2538 if( libspectrum_snap_opus_active( snap ) ) {
2539 error = write_opus_chunk( buffer, &ptr, length, snap, compress );
2540 if( error ) return error;
2541 }
2542
2543 if( libspectrum_snap_plusd_active( snap ) ) {
2544 error = write_plsd_chunk( buffer, &ptr, length, snap, compress );
2545 if( error ) return error;
2546 }
2547
2548 if( libspectrum_snap_kempston_mouse_active( snap ) ) {
2549 error = write_amxm_chunk( buffer, &ptr, length, snap );
2550 if( error ) return error;
2551 }
2552
2553 if( libspectrum_snap_simpleide_active( snap ) ) {
2554 error = write_side_chunk( buffer, &ptr, length, snap );
2555 if( error ) return error;
2556 }
2557
2558 if( libspectrum_snap_specdrum_active( snap ) ) {
2559 error = write_drum_chunk( buffer, &ptr, length, snap );
2560 if( error ) return error;
2561 }
2562
2563 if( libspectrum_snap_divide_active( snap ) ) {
2564 error = write_dide_chunk( buffer, &ptr, length, snap, compress );
2565 if( error ) return error;
2566
2567 for( i = 0; i < libspectrum_snap_divide_pages( snap ); i++ ) {
2568 error = write_dirp_chunk( buffer, &ptr, length, snap, i, compress );
2569 if( error ) return error;
2570 }
2571 }
2572
2573 if( libspectrum_snap_spectranet_active( snap ) ) {
2574 error = write_snet_chunk( buffer, &ptr, length, snap, compress );
2575 if( error ) return error;
2576 error = write_snef_chunk( buffer, &ptr, length, snap, compress );
2577 if( error ) return error;
2578 error = write_sner_chunk( buffer, &ptr, length, snap, compress );
2579 if( error ) return error;
2580 }
2581
2582 error = write_zxpr_chunk( buffer, &ptr, length, out_flags, snap );
2583 if( error ) return error;
2584
2585 /* Set length to be actual length, not allocated length */
2586 *length = ptr - *buffer;
2587
2588 return LIBSPECTRUM_ERROR_NONE;
2589 }
2590
2591 static libspectrum_error
write_file_header(libspectrum_byte ** buffer,libspectrum_byte ** ptr,size_t * length,int * out_flags,libspectrum_snap * snap)2592 write_file_header( libspectrum_byte **buffer, libspectrum_byte **ptr,
2593 size_t *length, int *out_flags, libspectrum_snap *snap )
2594 {
2595 libspectrum_byte flags;
2596
2597 libspectrum_make_room( buffer, 8, ptr, length );
2598
2599 memcpy( *ptr, signature, 4 ); *ptr += 4;
2600
2601 *(*ptr)++ = SZX_VERSION_MAJOR; *(*ptr)++ = SZX_VERSION_MINOR;
2602
2603 switch( libspectrum_snap_machine( snap ) ) {
2604
2605 case LIBSPECTRUM_MACHINE_16: **ptr = SZX_MACHINE_16; break;
2606 case LIBSPECTRUM_MACHINE_48: **ptr = SZX_MACHINE_48; break;
2607 case LIBSPECTRUM_MACHINE_48_NTSC: **ptr = SZX_MACHINE_48_NTSC; break;
2608 case LIBSPECTRUM_MACHINE_128: **ptr = SZX_MACHINE_128; break;
2609 case LIBSPECTRUM_MACHINE_128E: **ptr = SZX_MACHINE_128KE; break;
2610 case LIBSPECTRUM_MACHINE_PLUS2: **ptr = SZX_MACHINE_PLUS2; break;
2611 case LIBSPECTRUM_MACHINE_PLUS2A: **ptr = SZX_MACHINE_PLUS2A; break;
2612 case LIBSPECTRUM_MACHINE_PLUS3: **ptr = SZX_MACHINE_PLUS3; break;
2613 case LIBSPECTRUM_MACHINE_PLUS3E: **ptr = SZX_MACHINE_PLUS3E; break;
2614 case LIBSPECTRUM_MACHINE_PENT: **ptr = SZX_MACHINE_PENTAGON; break;
2615 case LIBSPECTRUM_MACHINE_TC2048: **ptr = SZX_MACHINE_TC2048; break;
2616 case LIBSPECTRUM_MACHINE_TC2068: **ptr = SZX_MACHINE_TC2068; break;
2617 case LIBSPECTRUM_MACHINE_TS2068: **ptr = SZX_MACHINE_TS2068; break;
2618 case LIBSPECTRUM_MACHINE_SCORP: **ptr = SZX_MACHINE_SCORPION; break;
2619 case LIBSPECTRUM_MACHINE_SE: **ptr = SZX_MACHINE_SE; break;
2620 case LIBSPECTRUM_MACHINE_PENT512: **ptr = SZX_MACHINE_PENTAGON512; break;
2621 case LIBSPECTRUM_MACHINE_PENT1024: **ptr = SZX_MACHINE_PENTAGON1024; break;
2622
2623 case LIBSPECTRUM_MACHINE_UNKNOWN:
2624 libspectrum_print_error( LIBSPECTRUM_ERROR_LOGIC,
2625 "Emulated machine type is set to 'unknown'!" );
2626 return LIBSPECTRUM_ERROR_LOGIC;
2627 }
2628 (*ptr)++;
2629
2630 /* Flags byte */
2631 flags = 0;
2632 if( libspectrum_snap_late_timings( snap ) ) flags |= ZXSTMF_ALTERNATETIMINGS;
2633 *(*ptr)++ = flags;
2634
2635 return LIBSPECTRUM_ERROR_NONE;
2636 }
2637
2638 static libspectrum_error
write_crtr_chunk(libspectrum_byte ** buffer,libspectrum_byte ** ptr,size_t * length,libspectrum_creator * creator)2639 write_crtr_chunk( libspectrum_byte **buffer, libspectrum_byte **ptr,
2640 size_t *length, libspectrum_creator *creator )
2641 {
2642 size_t custom_length;
2643
2644 custom_length = libspectrum_creator_custom_length( creator );
2645
2646 write_chunk_header( buffer, ptr, length, ZXSTBID_CREATOR, 36 + custom_length );
2647
2648 memcpy( *ptr, libspectrum_creator_program( creator ), 32 ); *ptr += 32;
2649 libspectrum_write_word( ptr, libspectrum_creator_major( creator ) );
2650 libspectrum_write_word( ptr, libspectrum_creator_minor( creator ) );
2651
2652 if( custom_length ) {
2653 memcpy( *ptr, libspectrum_creator_custom( creator ), custom_length );
2654 *ptr += custom_length;
2655 }
2656
2657 return LIBSPECTRUM_ERROR_NONE;
2658 }
2659
2660 static libspectrum_error
write_z80r_chunk(libspectrum_byte ** buffer,libspectrum_byte ** ptr,size_t * length,libspectrum_snap * snap)2661 write_z80r_chunk( libspectrum_byte **buffer, libspectrum_byte **ptr,
2662 size_t *length, libspectrum_snap *snap )
2663 {
2664 libspectrum_dword tstates;
2665 libspectrum_byte flags;
2666
2667 write_chunk_header( buffer, ptr, length, ZXSTBID_Z80REGS, 37 );
2668
2669 *(*ptr)++ = libspectrum_snap_f ( snap );
2670 *(*ptr)++ = libspectrum_snap_a ( snap );
2671 libspectrum_write_word( ptr, libspectrum_snap_bc ( snap ) );
2672 libspectrum_write_word( ptr, libspectrum_snap_de ( snap ) );
2673 libspectrum_write_word( ptr, libspectrum_snap_hl ( snap ) );
2674
2675 *(*ptr)++ = libspectrum_snap_f_( snap );
2676 *(*ptr)++ = libspectrum_snap_a_( snap );
2677 libspectrum_write_word( ptr, libspectrum_snap_bc_ ( snap ) );
2678 libspectrum_write_word( ptr, libspectrum_snap_de_ ( snap ) );
2679 libspectrum_write_word( ptr, libspectrum_snap_hl_ ( snap ) );
2680
2681 libspectrum_write_word( ptr, libspectrum_snap_ix ( snap ) );
2682 libspectrum_write_word( ptr, libspectrum_snap_iy ( snap ) );
2683 libspectrum_write_word( ptr, libspectrum_snap_sp ( snap ) );
2684 libspectrum_write_word( ptr, libspectrum_snap_pc ( snap ) );
2685
2686 *(*ptr)++ = libspectrum_snap_i ( snap );
2687 *(*ptr)++ = libspectrum_snap_r ( snap );
2688 *(*ptr)++ = libspectrum_snap_iff1( snap );
2689 *(*ptr)++ = libspectrum_snap_iff2( snap );
2690 *(*ptr)++ = libspectrum_snap_im ( snap );
2691
2692 tstates = libspectrum_snap_tstates( snap );
2693
2694 libspectrum_write_dword( ptr, tstates );
2695
2696 /* Number of tstates remaining in which an interrupt can occur */
2697 if( tstates < 48 ) {
2698 *(*ptr)++ = (unsigned char)(48 - tstates);
2699 } else {
2700 *(*ptr)++ = '\0';
2701 }
2702
2703 flags = '\0';
2704 if( libspectrum_snap_last_instruction_ei( snap ) ) flags |= ZXSTZF_EILAST;
2705 if( libspectrum_snap_halted( snap ) ) flags |= ZXSTZF_HALTED;
2706 if( libspectrum_snap_last_instruction_set_f( snap ) ) flags |= ZXSTZF_FSET;
2707 *(*ptr)++ = flags;
2708
2709 libspectrum_write_word( ptr, libspectrum_snap_memptr( snap ) );
2710
2711 return LIBSPECTRUM_ERROR_NONE;
2712 }
2713
2714 static libspectrum_error
write_spcr_chunk(libspectrum_byte ** buffer,libspectrum_byte ** ptr,size_t * length,libspectrum_snap * snap)2715 write_spcr_chunk( libspectrum_byte **buffer, libspectrum_byte **ptr,
2716 size_t *length, libspectrum_snap *snap )
2717 {
2718 int capabilities;
2719
2720 write_chunk_header( buffer, ptr, length, ZXSTBID_SPECREGS, 8 );
2721
2722 capabilities =
2723 libspectrum_machine_capabilities( libspectrum_snap_machine( snap ) );
2724
2725 /* Border colour */
2726 *(*ptr)++ = libspectrum_snap_out_ula( snap ) & 0x07;
2727
2728 if( capabilities & LIBSPECTRUM_MACHINE_CAPABILITY_128_MEMORY ) {
2729 *(*ptr)++ = libspectrum_snap_out_128_memoryport( snap );
2730 } else {
2731 *(*ptr)++ = '\0';
2732 }
2733
2734 if( capabilities & LIBSPECTRUM_MACHINE_CAPABILITY_PLUS3_MEMORY ||
2735 capabilities & LIBSPECTRUM_MACHINE_CAPABILITY_SCORP_MEMORY ||
2736 capabilities & LIBSPECTRUM_MACHINE_CAPABILITY_PENT1024_MEMORY ) {
2737 *(*ptr)++ = libspectrum_snap_out_plus3_memoryport( snap );
2738 } else {
2739 *(*ptr)++ = '\0';
2740 }
2741
2742 *(*ptr)++ = libspectrum_snap_out_ula( snap );
2743
2744 /* Reserved bytes */
2745 libspectrum_write_dword( ptr, 0 );
2746
2747 return LIBSPECTRUM_ERROR_NONE;
2748 }
2749
2750 static void
write_joystick(libspectrum_byte ** ptr,int * out_flags,libspectrum_snap * snap,const int connection)2751 write_joystick( libspectrum_byte **ptr, int *out_flags, libspectrum_snap *snap,
2752 const int connection )
2753 {
2754 size_t num_joysticks = libspectrum_snap_joystick_active_count( snap );
2755 int found = 0;
2756 int i;
2757
2758 for( i = 0; i < num_joysticks; i++ ) {
2759 if( libspectrum_snap_joystick_inputs( snap, i ) & connection ) {
2760 switch( libspectrum_snap_joystick_list( snap, i ) ) {
2761 case LIBSPECTRUM_JOYSTICK_CURSOR:
2762 if( !found ) { *(*ptr)++ = ZXJT_CURSOR; found = 1; }
2763 else *out_flags |= LIBSPECTRUM_FLAG_SNAPSHOT_MINOR_INFO_LOSS;
2764 break;
2765 case LIBSPECTRUM_JOYSTICK_KEMPSTON:
2766 if( !found ) { *(*ptr)++ = ZXJT_KEMPSTON; found = 1; }
2767 else *out_flags |= LIBSPECTRUM_FLAG_SNAPSHOT_MINOR_INFO_LOSS;
2768 break;
2769 case LIBSPECTRUM_JOYSTICK_SINCLAIR_1:
2770 if( !found ) { *(*ptr)++ = ZXJT_SINCLAIR1; found = 1; }
2771 else *out_flags |= LIBSPECTRUM_FLAG_SNAPSHOT_MINOR_INFO_LOSS;
2772 break;
2773 case LIBSPECTRUM_JOYSTICK_SINCLAIR_2:
2774 if( !found ) { *(*ptr)++ = ZXJT_SINCLAIR2; found = 1; }
2775 else *out_flags |= LIBSPECTRUM_FLAG_SNAPSHOT_MINOR_INFO_LOSS;
2776 break;
2777 case LIBSPECTRUM_JOYSTICK_TIMEX_1:
2778 if( !found ) { *(*ptr)++ = ZXJT_TIMEX1; found = 1; }
2779 else *out_flags |= LIBSPECTRUM_FLAG_SNAPSHOT_MINOR_INFO_LOSS;
2780 break;
2781 case LIBSPECTRUM_JOYSTICK_TIMEX_2:
2782 if( !found ) { *(*ptr)++ = ZXJT_TIMEX2; found = 1; }
2783 else *out_flags |= LIBSPECTRUM_FLAG_SNAPSHOT_MINOR_INFO_LOSS;
2784 break;
2785 case LIBSPECTRUM_JOYSTICK_FULLER:
2786 if( !found ) { *(*ptr)++ = ZXJT_FULLER; found = 1; }
2787 else *out_flags |= LIBSPECTRUM_FLAG_SNAPSHOT_MINOR_INFO_LOSS;
2788 break;
2789 case LIBSPECTRUM_JOYSTICK_NONE: /* Shouldn't happen */
2790 default:
2791 *(*ptr)++ = ZXJT_NONE;
2792 break;
2793 }
2794 }
2795 }
2796
2797 if( !found ) *(*ptr)++ = ZXJT_NONE;
2798 }
2799
2800 static libspectrum_error
write_joy_chunk(libspectrum_byte ** buffer,libspectrum_byte ** ptr,size_t * length,int * out_flags,libspectrum_snap * snap)2801 write_joy_chunk( libspectrum_byte **buffer, libspectrum_byte **ptr,
2802 size_t *length, int *out_flags, libspectrum_snap *snap )
2803 {
2804 libspectrum_dword flags;
2805 size_t num_joysticks = libspectrum_snap_joystick_active_count( snap );
2806 int i;
2807
2808 write_chunk_header( buffer, ptr, length, ZXSTBID_JOYSTICK, 6 );
2809
2810 flags = 0;
2811 for( i = 0; i < num_joysticks; i++ ) {
2812 if( libspectrum_snap_joystick_list( snap, i ) ==
2813 LIBSPECTRUM_JOYSTICK_KEMPSTON )
2814 flags |= ZXSTJOYF_ALWAYSPORT31;
2815 }
2816 libspectrum_write_dword( ptr, flags );
2817
2818 write_joystick( ptr, out_flags, snap, LIBSPECTRUM_JOYSTICK_INPUT_JOYSTICK_1 );
2819 write_joystick( ptr, out_flags, snap, LIBSPECTRUM_JOYSTICK_INPUT_JOYSTICK_2 );
2820
2821 return LIBSPECTRUM_ERROR_NONE;
2822 }
2823
2824 static libspectrum_error
write_amxm_chunk(libspectrum_byte ** buffer,libspectrum_byte ** ptr,size_t * length,libspectrum_snap * snap)2825 write_amxm_chunk( libspectrum_byte **buffer, libspectrum_byte **ptr,
2826 size_t *length, libspectrum_snap *snap )
2827 {
2828 write_chunk_header( buffer, ptr, length, ZXSTBID_MOUSE, 7 );
2829
2830 if( libspectrum_snap_kempston_mouse_active( snap ) )
2831 *(*ptr)++ = ZXSTM_KEMPSTON;
2832 else
2833 *(*ptr)++ = ZXSTM_NONE;
2834
2835 /* Z80 PIO CTRLA registers for AMX mouse */
2836 *(*ptr)++ = '\0'; *(*ptr)++ = '\0'; *(*ptr)++ = '\0';
2837
2838 /* Z80 PIO CTRLB registers for AMX mouse */
2839 *(*ptr)++ = '\0'; *(*ptr)++ = '\0'; *(*ptr)++ = '\0';
2840
2841 return LIBSPECTRUM_ERROR_NONE;
2842 }
2843
2844 static libspectrum_error
write_keyb_chunk(libspectrum_byte ** buffer,libspectrum_byte ** ptr,size_t * length,int * out_flags,libspectrum_snap * snap)2845 write_keyb_chunk( libspectrum_byte **buffer, libspectrum_byte **ptr,
2846 size_t *length, int *out_flags, libspectrum_snap *snap )
2847 {
2848 libspectrum_dword flags;
2849
2850 write_chunk_header( buffer, ptr, length, ZXSTBID_KEYBOARD, 5 );
2851
2852 flags = 0;
2853 if( libspectrum_snap_issue2( snap ) ) flags |= ZXSTKF_ISSUE2;
2854
2855 libspectrum_write_dword( ptr, flags );
2856
2857 write_joystick( ptr, out_flags, snap, LIBSPECTRUM_JOYSTICK_INPUT_KEYBOARD );
2858
2859 return LIBSPECTRUM_ERROR_NONE;
2860 }
2861
2862 static libspectrum_error
write_zxpr_chunk(libspectrum_byte ** buffer,libspectrum_byte ** ptr,size_t * length,int * out_flags,libspectrum_snap * snap)2863 write_zxpr_chunk( libspectrum_byte **buffer, libspectrum_byte **ptr,
2864 size_t *length, int *out_flags, libspectrum_snap *snap )
2865 {
2866 libspectrum_word flags;
2867
2868 write_chunk_header( buffer, ptr, length, ZXSTBID_ZXPRINTER, 2 );
2869
2870 flags = 0;
2871 if( libspectrum_snap_zx_printer_active( snap ) ) flags |= ZXSTPRF_ENABLED;
2872
2873 libspectrum_write_word( ptr, flags );
2874
2875 return LIBSPECTRUM_ERROR_NONE;
2876 }
2877
2878 static libspectrum_error
write_rom_chunk(libspectrum_byte ** buffer,libspectrum_byte ** ptr,size_t * length,int * out_flags,libspectrum_snap * snap,int compress)2879 write_rom_chunk( libspectrum_byte **buffer, libspectrum_byte **ptr, size_t *length,
2880 int *out_flags, libspectrum_snap *snap, int compress )
2881 {
2882 #ifdef HAVE_ZLIB_H
2883 libspectrum_error error;
2884 #endif
2885 size_t i, data_length = 0;
2886 size_t uncompressed_data_length = 0;
2887 libspectrum_byte *data, *rom_base;
2888 int flags = 0;
2889
2890 for( i = 0; i< libspectrum_snap_custom_rom_pages( snap ); i++ ) {
2891 data_length += libspectrum_snap_rom_length( snap, i );
2892 }
2893
2894 /* Check that we have the expected number of ROMs per the machine type */
2895 switch( libspectrum_snap_machine( snap ) ) {
2896
2897 case LIBSPECTRUM_MACHINE_16:
2898 case LIBSPECTRUM_MACHINE_48:
2899 case LIBSPECTRUM_MACHINE_48_NTSC:
2900 case LIBSPECTRUM_MACHINE_TC2048:
2901 /* 1 ROM = 16k */
2902 if( ( libspectrum_snap_custom_rom_pages( snap ) != 1 ||
2903 data_length != 0x4000 ) ) {
2904 *out_flags |= LIBSPECTRUM_FLAG_SNAPSHOT_MAJOR_INFO_LOSS;
2905 return LIBSPECTRUM_ERROR_NONE;
2906 }
2907 break;
2908 case LIBSPECTRUM_MACHINE_128:
2909 case LIBSPECTRUM_MACHINE_128E:
2910 case LIBSPECTRUM_MACHINE_PENT:
2911 case LIBSPECTRUM_MACHINE_PLUS2:
2912 case LIBSPECTRUM_MACHINE_SE:
2913 /* 2 ROMs = 32k */
2914 if( ( libspectrum_snap_custom_rom_pages( snap ) != 2 ||
2915 data_length != 0x8000 ) ) {
2916 *out_flags |= LIBSPECTRUM_FLAG_SNAPSHOT_MAJOR_INFO_LOSS;
2917 return LIBSPECTRUM_ERROR_NONE;
2918 }
2919 break;
2920 case LIBSPECTRUM_MACHINE_PLUS2A:
2921 case LIBSPECTRUM_MACHINE_PLUS3:
2922 case LIBSPECTRUM_MACHINE_PLUS3E:
2923 /* 4 ROMs = 64k */
2924 if( ( libspectrum_snap_custom_rom_pages( snap ) != 4 ||
2925 data_length != 0x10000 ) ) {
2926 *out_flags |= LIBSPECTRUM_FLAG_SNAPSHOT_MAJOR_INFO_LOSS;
2927 return LIBSPECTRUM_ERROR_NONE;
2928 }
2929 break;
2930 case LIBSPECTRUM_MACHINE_PENT512:
2931 case LIBSPECTRUM_MACHINE_PENT1024:
2932 /* 3 ROMs = 48k */
2933 if( ( libspectrum_snap_custom_rom_pages( snap ) != 3 ||
2934 data_length != 0xc000 ) ) {
2935 *out_flags |= LIBSPECTRUM_FLAG_SNAPSHOT_MAJOR_INFO_LOSS;
2936 return LIBSPECTRUM_ERROR_NONE;
2937 }
2938 break;
2939 case LIBSPECTRUM_MACHINE_TC2068:
2940 case LIBSPECTRUM_MACHINE_TS2068:
2941 /* 2 ROMs = 24k */
2942 if( ( libspectrum_snap_custom_rom_pages( snap ) != 2 ||
2943 data_length != 0x6000 ) ) {
2944 *out_flags |= LIBSPECTRUM_FLAG_SNAPSHOT_MAJOR_INFO_LOSS;
2945 return LIBSPECTRUM_ERROR_NONE;
2946 }
2947 break;
2948 case LIBSPECTRUM_MACHINE_SCORP:
2949 /* 4 ROMs = 64k */
2950 if( ( libspectrum_snap_custom_rom_pages( snap ) != 4 ||
2951 data_length != 0x10000 ) ) {
2952 *out_flags |= LIBSPECTRUM_FLAG_SNAPSHOT_MAJOR_INFO_LOSS;
2953 return LIBSPECTRUM_ERROR_NONE;
2954 }
2955 break;
2956
2957 case LIBSPECTRUM_MACHINE_UNKNOWN:
2958 libspectrum_print_error( LIBSPECTRUM_ERROR_LOGIC,
2959 "Emulated machine type is set to 'unknown'!" );
2960 return LIBSPECTRUM_ERROR_LOGIC;
2961 }
2962
2963 uncompressed_data_length = data_length;
2964
2965 data = libspectrum_malloc( data_length );
2966 rom_base = data;
2967
2968 /* Copy the rom data into a single block ready for putting in the szx */
2969 for( i = 0; i< libspectrum_snap_custom_rom_pages( snap ); i++ ) {
2970 memcpy( rom_base, libspectrum_snap_roms( snap, i ),
2971 libspectrum_snap_rom_length( snap, i ) );
2972 rom_base += libspectrum_snap_rom_length( snap, i );
2973 }
2974
2975 #ifdef HAVE_ZLIB_H
2976
2977 if( compress ) {
2978
2979 libspectrum_byte *compressed_data;
2980 size_t compressed_length;
2981
2982 error = libspectrum_zlib_compress( data, data_length,
2983 &compressed_data, &compressed_length );
2984 if( error ) return error;
2985
2986 if( compress & LIBSPECTRUM_FLAG_SNAPSHOT_ALWAYS_COMPRESS ||
2987 compressed_length < data_length ) {
2988 libspectrum_byte *old_data = data;
2989 flags |= ZXSTRF_COMPRESSED;
2990 data = compressed_data;
2991 data_length = compressed_length;
2992 libspectrum_free( old_data );
2993 } else {
2994 libspectrum_free( compressed_data );
2995 }
2996
2997 }
2998
2999 #endif /* #ifdef HAVE_ZLIB_H */
3000
3001 write_chunk_header( buffer, ptr, length, ZXSTBID_ROM, 6+data_length );
3002
3003 libspectrum_write_word( ptr, flags );
3004 libspectrum_write_dword( ptr, uncompressed_data_length );
3005
3006 memcpy( *ptr, data, data_length ); *ptr += data_length;
3007
3008 libspectrum_free( data );
3009
3010 return LIBSPECTRUM_ERROR_NONE;
3011 }
3012
3013 static libspectrum_error
write_ram_pages(libspectrum_byte ** buffer,libspectrum_byte ** ptr,size_t * length,libspectrum_snap * snap,int compress)3014 write_ram_pages( libspectrum_byte **buffer, libspectrum_byte **ptr,
3015 size_t *length, libspectrum_snap *snap, int compress )
3016 {
3017 libspectrum_machine machine;
3018 int i, capabilities;
3019 libspectrum_error error;
3020
3021 machine = libspectrum_snap_machine( snap );
3022 capabilities = libspectrum_machine_capabilities( machine );
3023
3024 error = write_ramp_chunk( buffer, ptr, length, snap, 5, compress );
3025 if( error ) return error;
3026
3027 if( machine != LIBSPECTRUM_MACHINE_16 ) {
3028 error = write_ramp_chunk( buffer, ptr, length, snap, 2, compress );
3029 if( error ) return error;
3030 error = write_ramp_chunk( buffer, ptr, length, snap, 0, compress );
3031 if( error ) return error;
3032 }
3033
3034 if( capabilities & LIBSPECTRUM_MACHINE_CAPABILITY_128_MEMORY ) {
3035 error = write_ramp_chunk( buffer, ptr, length, snap, 1, compress );
3036 if( error ) return error;
3037 error = write_ramp_chunk( buffer, ptr, length, snap, 3, compress );
3038 if( error ) return error;
3039 error = write_ramp_chunk( buffer, ptr, length, snap, 4, compress );
3040 if( error ) return error;
3041 error = write_ramp_chunk( buffer, ptr, length, snap, 6, compress );
3042 if( error ) return error;
3043 error = write_ramp_chunk( buffer, ptr, length, snap, 7, compress );
3044 if( error ) return error;
3045
3046 if( capabilities & LIBSPECTRUM_MACHINE_CAPABILITY_SCORP_MEMORY ) {
3047 for( i = 8; i < 16; i++ ) {
3048 error = write_ramp_chunk( buffer, ptr, length, snap, i, compress );
3049 if( error ) return error;
3050 }
3051 } else if( capabilities & LIBSPECTRUM_MACHINE_CAPABILITY_PENT512_MEMORY ) {
3052 for( i = 8; i < 32; i++ ) {
3053 error = write_ramp_chunk( buffer, ptr, length, snap, i, compress );
3054 if( error ) return error;
3055 }
3056
3057 if( capabilities & LIBSPECTRUM_MACHINE_CAPABILITY_PENT1024_MEMORY ) {
3058 for( i = 32; i < 64; i++ ) {
3059 error = write_ramp_chunk( buffer, ptr, length, snap, i, compress );
3060 if( error ) return error;
3061 }
3062 }
3063 }
3064
3065 }
3066
3067 if( capabilities & LIBSPECTRUM_MACHINE_CAPABILITY_SE_MEMORY ) {
3068 error = write_ramp_chunk( buffer, ptr, length, snap, 8, compress );
3069 if( error ) return error;
3070 }
3071
3072 return LIBSPECTRUM_ERROR_NONE;
3073 }
3074
3075 static libspectrum_error
write_ramp_chunk(libspectrum_byte ** buffer,libspectrum_byte ** ptr,size_t * length,libspectrum_snap * snap,int page,int compress)3076 write_ramp_chunk( libspectrum_byte **buffer, libspectrum_byte **ptr,
3077 size_t *length, libspectrum_snap *snap, int page,
3078 int compress )
3079 {
3080 libspectrum_error error;
3081 const libspectrum_byte *data;
3082
3083 data = libspectrum_snap_pages( snap, page );
3084
3085 error = write_ram_page( buffer, ptr, length, ZXSTBID_RAMPAGE, data, 0x4000,
3086 page, compress, 0x00 );
3087 if( error ) return error;
3088
3089 return LIBSPECTRUM_ERROR_NONE;
3090 }
3091
3092 static libspectrum_error
write_ram_page(libspectrum_byte ** buffer,libspectrum_byte ** ptr,size_t * length,const char * id,const libspectrum_byte * data,size_t data_length,int page,int compress,int extra_flags)3093 write_ram_page( libspectrum_byte **buffer, libspectrum_byte **ptr,
3094 size_t *length, const char *id, const libspectrum_byte *data,
3095 size_t data_length, int page, int compress, int extra_flags )
3096 {
3097 #ifdef HAVE_ZLIB_H
3098 libspectrum_error error;
3099 #endif
3100 libspectrum_byte *block_length, *flags, *compressed_data;
3101 int use_compression;
3102
3103 if( !data ) return LIBSPECTRUM_ERROR_NONE;
3104
3105 /* 8 for the chunk header, 3 for the flags and the page number */
3106 libspectrum_make_room( buffer, 8 + 3, ptr, length );
3107
3108 memcpy( *ptr, id, 4 ); (*ptr) += 4;
3109
3110 /* Store this location for later */
3111 block_length = *ptr; *ptr += 4;
3112
3113 /* And this one */
3114 flags = *ptr; *ptr += 2;
3115
3116 *(*ptr)++ = (libspectrum_byte)page;
3117
3118 use_compression = 0;
3119 compressed_data = NULL;
3120
3121 #ifdef HAVE_ZLIB_H
3122
3123 if( compress ) {
3124
3125 size_t compressed_length;
3126
3127 error = libspectrum_zlib_compress( data, data_length,
3128 &compressed_data, &compressed_length );
3129 if( error ) return error;
3130
3131 if( compress & LIBSPECTRUM_FLAG_SNAPSHOT_ALWAYS_COMPRESS ||
3132 compressed_length < data_length ) {
3133 use_compression = 1;
3134 data = compressed_data;
3135 data_length = compressed_length;
3136 }
3137 }
3138
3139 #endif /* #ifdef HAVE_ZLIB_H */
3140
3141 if( use_compression ) extra_flags |= ZXSTRF_COMPRESSED;
3142
3143 libspectrum_write_dword( &block_length, 3 + data_length );
3144 libspectrum_write_word( &flags, extra_flags );
3145
3146 libspectrum_make_room( buffer, data_length, ptr, length );
3147
3148 memcpy( *ptr, data, data_length ); *ptr += data_length;
3149
3150 if( compressed_data ) libspectrum_free( compressed_data );
3151
3152 return LIBSPECTRUM_ERROR_NONE;
3153 }
3154
3155 static libspectrum_error
write_ay_chunk(libspectrum_byte ** buffer,libspectrum_byte ** ptr,size_t * length,libspectrum_snap * snap)3156 write_ay_chunk( libspectrum_byte **buffer, libspectrum_byte **ptr,
3157 size_t *length, libspectrum_snap *snap )
3158 {
3159 size_t i;
3160 libspectrum_byte flags;
3161
3162 write_chunk_header( buffer, ptr, length, ZXSTBID_AY, 18 );
3163
3164 flags = 0;
3165 if( libspectrum_snap_fuller_box_active( snap ) ) flags |= ZXSTAYF_FULLERBOX;
3166 if( libspectrum_snap_melodik_active( snap ) ) flags |= ZXSTAYF_128AY;
3167 *(*ptr)++ = flags;
3168
3169 *(*ptr)++ = libspectrum_snap_out_ay_registerport( snap );
3170
3171 for( i = 0; i < 16; i++ )
3172 *(*ptr)++ = libspectrum_snap_ay_registers( snap, i );
3173
3174 return LIBSPECTRUM_ERROR_NONE;
3175 }
3176
3177 static libspectrum_error
write_scld_chunk(libspectrum_byte ** buffer,libspectrum_byte ** ptr,size_t * length,libspectrum_snap * snap)3178 write_scld_chunk( libspectrum_byte **buffer, libspectrum_byte **ptr,
3179 size_t *length, libspectrum_snap *snap )
3180 {
3181 write_chunk_header( buffer, ptr, length, ZXSTBID_TIMEXREGS, 2 );
3182
3183 *(*ptr)++ = libspectrum_snap_out_scld_hsr( snap );
3184 *(*ptr)++ = libspectrum_snap_out_scld_dec( snap );
3185
3186 return LIBSPECTRUM_ERROR_NONE;
3187 }
3188
3189 static libspectrum_error
write_b128_chunk(libspectrum_byte ** buffer,libspectrum_byte ** ptr,size_t * length,libspectrum_snap * snap,int compress)3190 write_b128_chunk( libspectrum_byte **buffer, libspectrum_byte **ptr,
3191 size_t *length, libspectrum_snap *snap, int compress )
3192 {
3193 #ifdef HAVE_ZLIB_H
3194 libspectrum_error error;
3195 #endif
3196 libspectrum_byte *rom_data = NULL;
3197 libspectrum_byte *compressed_rom_data = NULL;
3198 size_t block_size;
3199 libspectrum_word beta_rom_length = 0;
3200 libspectrum_word uncompressed_rom_length = 0;
3201 libspectrum_dword flags;
3202 int use_compression = 0;
3203
3204 if( libspectrum_snap_beta_custom_rom( snap ) ) {
3205 rom_data = libspectrum_snap_beta_rom( snap, 0 );
3206 uncompressed_rom_length = beta_rom_length = 0x4000;
3207
3208 #ifdef HAVE_ZLIB_H
3209
3210 if( rom_data && compress ) {
3211
3212 size_t compressed_rom_length;
3213
3214 error = libspectrum_zlib_compress( rom_data, uncompressed_rom_length,
3215 &compressed_rom_data,
3216 &compressed_rom_length );
3217 if( error ) return error;
3218
3219 if( compress & LIBSPECTRUM_FLAG_SNAPSHOT_ALWAYS_COMPRESS ||
3220 compressed_rom_length < uncompressed_rom_length ) {
3221 use_compression = 1;
3222 rom_data = compressed_rom_data;
3223 beta_rom_length = compressed_rom_length;
3224 }
3225
3226 }
3227
3228 #endif
3229
3230 }
3231
3232 block_size = 10 + beta_rom_length;
3233
3234 write_chunk_header( buffer, ptr, length, ZXSTBID_BETA128, block_size );
3235
3236 flags = ZXSTBETAF_CONNECTED; /* Betadisk interface connected */
3237 if( libspectrum_snap_beta_paged( snap ) ) flags |= ZXSTBETAF_PAGED;
3238 if( libspectrum_snap_beta_autoboot( snap ) ) flags |= ZXSTBETAF_AUTOBOOT;
3239 if( !libspectrum_snap_beta_direction( snap ) ) flags |= ZXSTBETAF_SEEKLOWER;
3240 if( libspectrum_snap_beta_custom_rom( snap ) ) flags |= ZXSTBETAF_CUSTOMROM;
3241 if( use_compression ) flags |= ZXSTBETAF_COMPRESSED;
3242 libspectrum_write_dword( ptr, flags );
3243
3244 *(*ptr)++ = libspectrum_snap_beta_drive_count( snap );
3245 *(*ptr)++ = libspectrum_snap_beta_system( snap );
3246 *(*ptr)++ = libspectrum_snap_beta_track ( snap );
3247 *(*ptr)++ = libspectrum_snap_beta_sector( snap );
3248 *(*ptr)++ = libspectrum_snap_beta_data ( snap );
3249 *(*ptr)++ = libspectrum_snap_beta_status( snap );
3250
3251 if( libspectrum_snap_beta_custom_rom( snap ) && rom_data ) {
3252 memcpy( *ptr, rom_data, beta_rom_length ); *ptr += beta_rom_length;
3253 }
3254
3255 if( compressed_rom_data ) libspectrum_free( compressed_rom_data );
3256
3257 return LIBSPECTRUM_ERROR_NONE;
3258 }
3259
3260 static libspectrum_error
write_if1_chunk(libspectrum_byte ** buffer,libspectrum_byte ** ptr,size_t * length,libspectrum_snap * snap,int compress)3261 write_if1_chunk( libspectrum_byte **buffer, libspectrum_byte **ptr,
3262 size_t *length, libspectrum_snap *snap, int compress )
3263 {
3264 #ifdef HAVE_ZLIB_H
3265 libspectrum_error error;
3266 #endif
3267 libspectrum_byte *rom_data = NULL;
3268 libspectrum_byte *compressed_rom_data = NULL;
3269 size_t block_size;
3270 libspectrum_word disk_rom_length = 0;
3271 libspectrum_word uncompressed_rom_length = 0;
3272 libspectrum_word flags = 0;
3273 int use_compression = 0;
3274
3275 if( libspectrum_snap_interface1_custom_rom( snap ) ) {
3276 if( !(libspectrum_snap_interface1_rom_length( snap, 0 ) == 0x2000 ||
3277 libspectrum_snap_interface1_rom_length( snap, 0 ) == 0x4000 )) {
3278 libspectrum_print_error( LIBSPECTRUM_ERROR_LOGIC,
3279 "Interface 1 custom ROM must be 8192 or 16384 "
3280 "bytes, supplied ROM is %lu bytes",
3281 (unsigned long)
3282 libspectrum_snap_interface1_rom_length(
3283 snap, 0 ) );
3284 return LIBSPECTRUM_ERROR_LOGIC;
3285 }
3286 rom_data = libspectrum_snap_interface1_rom( snap, 0 );
3287 uncompressed_rom_length = disk_rom_length =
3288 libspectrum_snap_interface1_rom_length( snap, 0 );
3289 }
3290
3291 compressed_rom_data = NULL;
3292
3293 #ifdef HAVE_ZLIB_H
3294
3295 if( rom_data && compress ) {
3296
3297 size_t compressed_rom_length;
3298
3299 error = libspectrum_zlib_compress( rom_data, disk_rom_length,
3300 &compressed_rom_data, &compressed_rom_length );
3301 if( error ) return error;
3302
3303 if( compress & LIBSPECTRUM_FLAG_SNAPSHOT_ALWAYS_COMPRESS ||
3304 compressed_rom_length < disk_rom_length ) {
3305 use_compression = 1;
3306 rom_data = compressed_rom_data;
3307 disk_rom_length = compressed_rom_length;
3308 }
3309
3310 }
3311
3312 #endif /* #ifdef HAVE_ZLIB_H */
3313
3314 block_size = 40;
3315 if( libspectrum_snap_interface1_custom_rom( snap ) ) {
3316 block_size += disk_rom_length;
3317 }
3318
3319 write_chunk_header( buffer, ptr, length, ZXSTBID_IF1, block_size );
3320
3321 flags |= ZXSTIF1F_ENABLED;
3322 if( libspectrum_snap_interface1_paged( snap ) ) flags |= ZXSTIF1F_PAGED;
3323 if( use_compression ) flags |= ZXSTIF1F_COMPRESSED;
3324 libspectrum_write_word( ptr, flags );
3325
3326 if( libspectrum_snap_interface1_drive_count( snap ) )
3327 *(*ptr)++ = libspectrum_snap_interface1_drive_count( snap );
3328 else
3329 *(*ptr)++ = 8; /* guess 8 drives connected */
3330 *ptr += 3; /* Skip 'reserved' data */
3331 *ptr += sizeof(libspectrum_dword) * 8; /* Skip 'reserved' data */
3332 libspectrum_write_word( ptr, uncompressed_rom_length );
3333
3334 if( libspectrum_snap_interface1_custom_rom( snap ) && disk_rom_length ) {
3335 memcpy( *ptr, rom_data, disk_rom_length ); *ptr += disk_rom_length;
3336 }
3337
3338 if( compressed_rom_data ) libspectrum_free( compressed_rom_data );
3339
3340 return LIBSPECTRUM_ERROR_NONE;
3341 }
3342
3343 static libspectrum_error
write_opus_chunk(libspectrum_byte ** buffer,libspectrum_byte ** ptr,size_t * length,libspectrum_snap * snap,int compress)3344 write_opus_chunk( libspectrum_byte **buffer, libspectrum_byte **ptr,
3345 size_t *length, libspectrum_snap *snap, int compress )
3346 {
3347 #ifdef HAVE_ZLIB_H
3348 libspectrum_error error;
3349 #endif
3350 libspectrum_byte *rom_data, *ram_data;
3351 libspectrum_byte *compressed_rom_data = NULL, *compressed_ram_data = NULL;
3352 size_t disk_rom_length, disk_ram_length, block_size;
3353 libspectrum_dword flags = 0;
3354 int use_compression = 0;
3355
3356 rom_data = libspectrum_snap_opus_rom( snap, 0 );
3357 disk_rom_length = 0x2000;
3358 ram_data = libspectrum_snap_opus_ram( snap, 0 );
3359 disk_ram_length = 0x800;
3360
3361 compressed_ram_data = compressed_rom_data = NULL;
3362
3363 #ifdef HAVE_ZLIB_H
3364
3365 if( compress ) {
3366
3367 size_t compressed_rom_length, compressed_ram_length;
3368
3369 error = libspectrum_zlib_compress( rom_data, disk_rom_length,
3370 &compressed_rom_data, &compressed_rom_length );
3371 if( error ) return error;
3372
3373 error = libspectrum_zlib_compress( ram_data, disk_ram_length,
3374 &compressed_ram_data, &compressed_ram_length );
3375 if( error ) {
3376 if( compressed_rom_data ) libspectrum_free( compressed_rom_data );
3377 return error;
3378 }
3379
3380 if( compress & LIBSPECTRUM_FLAG_SNAPSHOT_ALWAYS_COMPRESS ||
3381 (compressed_rom_length + compressed_ram_length) <
3382 (disk_rom_length + disk_ram_length ) ) {
3383 use_compression = 1;
3384 rom_data = compressed_rom_data;
3385 disk_rom_length = compressed_rom_length;
3386 ram_data = compressed_ram_data;
3387 disk_ram_length = compressed_ram_length;
3388 }
3389
3390 }
3391
3392 #endif /* #ifdef HAVE_ZLIB_H */
3393
3394 block_size = 23 + disk_ram_length;
3395 if( libspectrum_snap_opus_custom_rom( snap ) ) {
3396 block_size += disk_rom_length;
3397 }
3398
3399 write_chunk_header( buffer, ptr, length, ZXSTBID_OPUS, block_size );
3400
3401 if( libspectrum_snap_opus_paged( snap ) ) flags |= ZXSTPLUSDF_PAGED;
3402 if( use_compression ) flags |= ZXSTPLUSDF_COMPRESSED;
3403 if( !libspectrum_snap_opus_direction( snap ) ) flags |= ZXSTPLUSDF_SEEKLOWER;
3404 if( libspectrum_snap_opus_custom_rom( snap ) ) flags |= ZXSTOPUSF_CUSTOMROM;
3405 libspectrum_write_dword( ptr, flags );
3406
3407 libspectrum_write_dword( ptr, disk_ram_length );
3408 if( libspectrum_snap_opus_custom_rom( snap ) ) {
3409 libspectrum_write_dword( ptr, disk_rom_length );
3410 } else {
3411 libspectrum_write_dword( ptr, 0 );
3412 }
3413 *(*ptr)++ = libspectrum_snap_opus_control_a( snap );
3414 *(*ptr)++ = libspectrum_snap_opus_data_reg_a( snap );
3415 *(*ptr)++ = libspectrum_snap_opus_data_dir_a( snap );
3416 *(*ptr)++ = libspectrum_snap_opus_control_b( snap );
3417 *(*ptr)++ = libspectrum_snap_opus_data_reg_b( snap );
3418 *(*ptr)++ = libspectrum_snap_opus_data_dir_b( snap );
3419 *(*ptr)++ = libspectrum_snap_opus_drive_count( snap );
3420 *(*ptr)++ = libspectrum_snap_opus_track ( snap );
3421 *(*ptr)++ = libspectrum_snap_opus_sector ( snap );
3422 *(*ptr)++ = libspectrum_snap_opus_data ( snap );
3423 *(*ptr)++ = libspectrum_snap_opus_status ( snap );
3424
3425 memcpy( *ptr, ram_data, disk_ram_length ); *ptr += disk_ram_length;
3426
3427 if( libspectrum_snap_opus_custom_rom( snap ) ) {
3428 memcpy( *ptr, rom_data, disk_rom_length ); *ptr += disk_rom_length;
3429 }
3430
3431 if( compressed_rom_data ) libspectrum_free( compressed_rom_data );
3432 if( compressed_ram_data ) libspectrum_free( compressed_ram_data );
3433
3434 return LIBSPECTRUM_ERROR_NONE;
3435 }
3436
3437 static libspectrum_error
write_plsd_chunk(libspectrum_byte ** buffer,libspectrum_byte ** ptr,size_t * length,libspectrum_snap * snap,int compress)3438 write_plsd_chunk( libspectrum_byte **buffer, libspectrum_byte **ptr,
3439 size_t *length, libspectrum_snap *snap, int compress )
3440 {
3441 #ifdef HAVE_ZLIB_H
3442 libspectrum_error error;
3443 #endif
3444 libspectrum_byte *rom_data, *ram_data;
3445 libspectrum_byte *compressed_rom_data = NULL, *compressed_ram_data = NULL;
3446 size_t disk_rom_length, disk_ram_length, block_size;
3447 libspectrum_dword flags = 0;
3448 int use_compression = 0;
3449
3450 rom_data = libspectrum_snap_plusd_rom( snap, 0 );
3451 disk_rom_length = 0x2000;
3452 ram_data = libspectrum_snap_plusd_ram( snap, 0 );
3453 disk_ram_length = 0x2000;
3454
3455 compressed_ram_data = compressed_rom_data = NULL;
3456
3457 #ifdef HAVE_ZLIB_H
3458
3459 if( compress ) {
3460
3461 size_t compressed_rom_length, compressed_ram_length;
3462
3463 error = libspectrum_zlib_compress( rom_data, disk_rom_length,
3464 &compressed_rom_data, &compressed_rom_length );
3465 if( error ) return error;
3466
3467 error = libspectrum_zlib_compress( ram_data, disk_ram_length,
3468 &compressed_ram_data, &compressed_ram_length );
3469 if( error ) {
3470 if( compressed_rom_data ) libspectrum_free( compressed_rom_data );
3471 return error;
3472 }
3473
3474 if( compress & LIBSPECTRUM_FLAG_SNAPSHOT_ALWAYS_COMPRESS ||
3475 (compressed_rom_length + compressed_ram_length) <
3476 (disk_rom_length + disk_ram_length ) ) {
3477 use_compression = 1;
3478 rom_data = compressed_rom_data;
3479 disk_rom_length = compressed_rom_length;
3480 ram_data = compressed_ram_data;
3481 disk_ram_length = compressed_ram_length;
3482 }
3483
3484 }
3485
3486 #endif /* #ifdef HAVE_ZLIB_H */
3487
3488 block_size = 19 + disk_ram_length;
3489 if( libspectrum_snap_plusd_custom_rom( snap ) ) {
3490 block_size += disk_rom_length;
3491 }
3492
3493 write_chunk_header( buffer, ptr, length, ZXSTBID_PLUSD, block_size );
3494
3495 if( libspectrum_snap_plusd_paged( snap ) ) flags |= ZXSTPLUSDF_PAGED;
3496 if( use_compression ) flags |= ZXSTPLUSDF_COMPRESSED;
3497 if( !libspectrum_snap_plusd_direction( snap ) ) flags |= ZXSTPLUSDF_SEEKLOWER;
3498 libspectrum_write_dword( ptr, flags );
3499
3500 libspectrum_write_dword( ptr, disk_ram_length );
3501 if( libspectrum_snap_plusd_custom_rom( snap ) ) {
3502 libspectrum_write_dword( ptr, disk_rom_length );
3503 *(*ptr)++ = ZXSTPDRT_CUSTOM;
3504 } else {
3505 libspectrum_write_dword( ptr, 0 );
3506 *(*ptr)++ = ZXSTPDRT_GDOS;
3507 }
3508 *(*ptr)++ = libspectrum_snap_plusd_control( snap );
3509 *(*ptr)++ = libspectrum_snap_plusd_drive_count( snap );
3510 *(*ptr)++ = libspectrum_snap_plusd_track ( snap );
3511 *(*ptr)++ = libspectrum_snap_plusd_sector ( snap );
3512 *(*ptr)++ = libspectrum_snap_plusd_data ( snap );
3513 *(*ptr)++ = libspectrum_snap_plusd_status ( snap );
3514
3515 memcpy( *ptr, ram_data, disk_ram_length ); *ptr += disk_ram_length;
3516
3517 if( libspectrum_snap_plusd_custom_rom( snap ) ) {
3518 memcpy( *ptr, rom_data, disk_rom_length ); *ptr += disk_rom_length;
3519 }
3520
3521 if( compressed_rom_data ) libspectrum_free( compressed_rom_data );
3522 if( compressed_ram_data ) libspectrum_free( compressed_ram_data );
3523
3524 return LIBSPECTRUM_ERROR_NONE;
3525 }
3526
3527 static libspectrum_error
write_zxat_chunk(libspectrum_byte ** buffer,libspectrum_byte ** ptr,size_t * length,libspectrum_snap * snap)3528 write_zxat_chunk( libspectrum_byte **buffer, libspectrum_byte **ptr,
3529 size_t *length, libspectrum_snap *snap )
3530 {
3531 libspectrum_word flags;
3532
3533 write_chunk_header( buffer, ptr, length, ZXSTBID_ZXATASP, 8 );
3534
3535 flags = 0;
3536 if( libspectrum_snap_zxatasp_upload ( snap ) ) flags |= ZXSTZXATF_UPLOAD;
3537 if( libspectrum_snap_zxatasp_writeprotect( snap ) )
3538 flags |= ZXSTZXATF_WRITEPROTECT;
3539 libspectrum_write_word( ptr, flags );
3540
3541 *(*ptr)++ = libspectrum_snap_zxatasp_port_a( snap );
3542 *(*ptr)++ = libspectrum_snap_zxatasp_port_b( snap );
3543 *(*ptr)++ = libspectrum_snap_zxatasp_port_c( snap );
3544 *(*ptr)++ = libspectrum_snap_zxatasp_control( snap );
3545 *(*ptr)++ = libspectrum_snap_zxatasp_pages( snap );
3546 *(*ptr)++ = libspectrum_snap_zxatasp_current_page( snap );
3547
3548 return LIBSPECTRUM_ERROR_NONE;
3549 }
3550
3551 static libspectrum_error
write_atrp_chunk(libspectrum_byte ** buffer,libspectrum_byte ** ptr,size_t * length,libspectrum_snap * snap,int page,int compress)3552 write_atrp_chunk( libspectrum_byte **buffer, libspectrum_byte **ptr,
3553 size_t *length, libspectrum_snap *snap, int page,
3554 int compress )
3555 {
3556 libspectrum_error error;
3557 const libspectrum_byte *data;
3558
3559 data = libspectrum_snap_zxatasp_ram( snap, page );
3560
3561 error = write_ram_page( buffer, ptr, length, ZXSTBID_ZXATASPRAMPAGE, data,
3562 0x4000, page, compress, 0x00 );
3563 if( error ) return error;
3564
3565 return LIBSPECTRUM_ERROR_NONE;
3566 }
3567
3568 static libspectrum_error
write_zxcf_chunk(libspectrum_byte ** buffer,libspectrum_byte ** ptr,size_t * length,libspectrum_snap * snap)3569 write_zxcf_chunk( libspectrum_byte **buffer, libspectrum_byte **ptr,
3570 size_t *length, libspectrum_snap *snap )
3571 {
3572 libspectrum_word flags;
3573
3574 write_chunk_header( buffer, ptr, length, ZXSTBID_ZXCF, 4 );
3575
3576 flags = 0;
3577 if( libspectrum_snap_zxcf_upload( snap ) ) flags |= ZXSTZXCFF_UPLOAD;
3578 libspectrum_write_word( ptr, flags );
3579
3580 *(*ptr)++ = libspectrum_snap_zxcf_memctl( snap );
3581 *(*ptr)++ = libspectrum_snap_zxcf_pages( snap );
3582
3583 return LIBSPECTRUM_ERROR_NONE;
3584 }
3585
3586 static libspectrum_error
write_cfrp_chunk(libspectrum_byte ** buffer,libspectrum_byte ** ptr,size_t * length,libspectrum_snap * snap,int page,int compress)3587 write_cfrp_chunk( libspectrum_byte **buffer, libspectrum_byte **ptr,
3588 size_t *length, libspectrum_snap *snap, int page,
3589 int compress )
3590 {
3591 libspectrum_error error;
3592 const libspectrum_byte *data;
3593
3594 data = libspectrum_snap_zxcf_ram( snap, page );
3595
3596 error = write_ram_page( buffer, ptr, length, ZXSTBID_ZXCFRAMPAGE, data,
3597 0x4000, page, compress, 0x00 );
3598 if( error ) return error;
3599
3600 return LIBSPECTRUM_ERROR_NONE;
3601 }
3602
3603 #ifdef HAVE_ZLIB_H
3604
3605 static libspectrum_error
write_if2r_chunk(libspectrum_byte ** buffer,libspectrum_byte ** ptr,size_t * length,libspectrum_snap * snap)3606 write_if2r_chunk( libspectrum_byte **buffer, libspectrum_byte **ptr,
3607 size_t *length, libspectrum_snap *snap )
3608 {
3609 libspectrum_error error;
3610 libspectrum_byte *block_length, *data, *cart_size, *compressed_data;
3611 size_t data_length, compressed_length;
3612
3613 /* 8 for the chunk header, 4 for the compressed cart size */
3614 libspectrum_make_room( buffer, 8 + 4, ptr, length );
3615
3616 memcpy( *ptr, ZXSTBID_IF2ROM, 4 ); (*ptr) += 4;
3617
3618 /* Store this location for later */
3619 block_length = *ptr; *ptr += 4;
3620
3621 /* And this one */
3622 cart_size = *ptr; *ptr += 4;
3623
3624 data = libspectrum_snap_interface2_rom( snap, 0 ); data_length = 0x4000;
3625 compressed_data = NULL;
3626
3627 error = libspectrum_zlib_compress( data, data_length,
3628 &compressed_data, &compressed_length );
3629 if( error ) return error;
3630
3631 libspectrum_write_dword( &block_length, 4 + compressed_length );
3632 libspectrum_write_dword( &cart_size, compressed_length );
3633
3634 libspectrum_make_room( buffer, compressed_length, ptr, length );
3635
3636 memcpy( *ptr, compressed_data, compressed_length ); *ptr += compressed_length;
3637
3638 if( compressed_data ) libspectrum_free( compressed_data );
3639
3640 return LIBSPECTRUM_ERROR_NONE;
3641 }
3642
3643 #endif /* #ifdef HAVE_ZLIB_H */
3644
3645 static libspectrum_error
write_dock_chunk(libspectrum_byte ** buffer,libspectrum_byte ** ptr,size_t * length,libspectrum_snap * snap,int exrom_dock,const libspectrum_byte * data,int page,int writeable,int compress)3646 write_dock_chunk( libspectrum_byte **buffer, libspectrum_byte **ptr,
3647 size_t *length, libspectrum_snap *snap, int exrom_dock,
3648 const libspectrum_byte *data, int page, int writeable,
3649 int compress )
3650 {
3651 libspectrum_error error;
3652 libspectrum_byte extra_flags;
3653
3654 extra_flags = 0;
3655 if( writeable ) extra_flags |= ZXSTDOCKF_RAM;
3656 if( exrom_dock ) extra_flags |= ZXSTDOCKF_EXROMDOCK;
3657
3658 error = write_ram_page( buffer, ptr, length, ZXSTBID_DOCK, data, 0x2000,
3659 page, compress, extra_flags );
3660 if( error ) return error;
3661
3662 return LIBSPECTRUM_ERROR_NONE;
3663 }
3664
3665 static libspectrum_error
write_side_chunk(libspectrum_byte ** buffer,libspectrum_byte ** ptr,size_t * length,libspectrum_snap * snap)3666 write_side_chunk( libspectrum_byte **buffer, libspectrum_byte **ptr,
3667 size_t *length, libspectrum_snap *snap )
3668 {
3669 write_chunk_header( buffer, ptr, length, ZXSTBID_SIMPLEIDE, 0 );
3670 return LIBSPECTRUM_ERROR_NONE;
3671 }
3672
3673 static libspectrum_error
write_drum_chunk(libspectrum_byte ** buffer,libspectrum_byte ** ptr,size_t * length,libspectrum_snap * snap)3674 write_drum_chunk( libspectrum_byte **buffer, libspectrum_byte **ptr,
3675 size_t *length, libspectrum_snap *snap )
3676 {
3677 write_chunk_header( buffer, ptr, length, ZXSTBID_SPECDRUM, 1 );
3678
3679 *(*ptr)++ = libspectrum_snap_specdrum_dac( snap );
3680
3681 return LIBSPECTRUM_ERROR_NONE;
3682 }
3683
3684 static libspectrum_error
write_dide_chunk(libspectrum_byte ** buffer,libspectrum_byte ** ptr,size_t * length,libspectrum_snap * snap,int compress)3685 write_dide_chunk( libspectrum_byte **buffer, libspectrum_byte **ptr,
3686 size_t *length, libspectrum_snap *snap, int compress )
3687 {
3688 #ifdef HAVE_ZLIB_H
3689 libspectrum_error error;
3690 #endif
3691 libspectrum_byte *eprom_data = NULL;
3692 libspectrum_byte *compressed_eprom_data = NULL;
3693 size_t block_size;
3694 libspectrum_word flags = 0;
3695 libspectrum_word divide_eprom_length = 0;
3696 libspectrum_word uncompressed_eprom_length = 0;
3697 int use_compression = 0;
3698
3699 eprom_data = libspectrum_snap_divide_eprom( snap, 0 );
3700 if( !eprom_data ) {
3701 libspectrum_print_error( LIBSPECTRUM_ERROR_LOGIC,
3702 "DivIDE EPROM data is missing" );
3703 return LIBSPECTRUM_ERROR_LOGIC;
3704 }
3705 uncompressed_eprom_length = divide_eprom_length = 0x2000;
3706
3707 #ifdef HAVE_ZLIB_H
3708
3709 if( eprom_data && compress ) {
3710
3711 size_t compressed_eprom_length;
3712
3713 error = libspectrum_zlib_compress( eprom_data, uncompressed_eprom_length,
3714 &compressed_eprom_data,
3715 &compressed_eprom_length );
3716 if( error ) return error;
3717
3718 if( compress & LIBSPECTRUM_FLAG_SNAPSHOT_ALWAYS_COMPRESS ||
3719 compressed_eprom_length < uncompressed_eprom_length ) {
3720 use_compression = 1;
3721 eprom_data = compressed_eprom_data;
3722 divide_eprom_length = compressed_eprom_length;
3723 }
3724
3725 }
3726
3727 #endif
3728
3729 block_size = 4 + divide_eprom_length;
3730
3731 write_chunk_header( buffer, ptr, length, ZXSTBID_DIVIDE, block_size );
3732
3733 if( libspectrum_snap_divide_eprom_writeprotect( snap ) )
3734 flags |= ZXSTDIVIDE_EPROM_WRITEPROTECT;
3735 if( libspectrum_snap_divide_paged( snap ) ) flags |= ZXSTDIVIDE_PAGED;
3736 if( use_compression ) flags |= ZXSTDIVIDE_COMPRESSED;
3737 libspectrum_write_word( ptr, flags );
3738
3739 *(*ptr)++ = libspectrum_snap_divide_control( snap );
3740 *(*ptr)++ = libspectrum_snap_divide_pages( snap );
3741
3742 memcpy( *ptr, eprom_data, divide_eprom_length ); *ptr += divide_eprom_length;
3743
3744 if( compressed_eprom_data ) libspectrum_free( compressed_eprom_data );
3745
3746 return LIBSPECTRUM_ERROR_NONE;
3747 }
3748
3749 static libspectrum_error
write_dirp_chunk(libspectrum_byte ** buffer,libspectrum_byte ** ptr,size_t * length,libspectrum_snap * snap,int page,int compress)3750 write_dirp_chunk( libspectrum_byte **buffer, libspectrum_byte **ptr,
3751 size_t *length, libspectrum_snap *snap, int page,
3752 int compress )
3753 {
3754 libspectrum_error error;
3755 const libspectrum_byte *data;
3756
3757 data = libspectrum_snap_divide_ram( snap, page );
3758
3759 error = write_ram_page( buffer, ptr, length, ZXSTBID_DIVIDERAMPAGE, data,
3760 0x2000, page, compress, 0x00 );
3761 if( error ) return error;
3762
3763 return LIBSPECTRUM_ERROR_NONE;
3764 }
3765
3766 static libspectrum_error
write_snet_chunk(libspectrum_byte ** buffer,libspectrum_byte ** ptr,size_t * length,libspectrum_snap * snap,int compress)3767 write_snet_chunk( libspectrum_byte **buffer, libspectrum_byte **ptr,
3768 size_t *length, libspectrum_snap *snap, int compress )
3769 {
3770 libspectrum_word flags = 0;
3771
3772 write_chunk_header( buffer, ptr, length, ZXSTBID_SPECTRANET, 54 );
3773
3774 if( libspectrum_snap_spectranet_paged( snap ) )
3775 flags |= ZXSTSNET_PAGED;
3776 if( libspectrum_snap_spectranet_paged_via_io( snap ) )
3777 flags |= ZXSTSNET_PAGED_VIA_IO;
3778 if( libspectrum_snap_spectranet_programmable_trap_active( snap ) )
3779 flags |= ZXSTSNET_PROGRAMMABLE_TRAP_ACTIVE;
3780 if( libspectrum_snap_spectranet_programmable_trap_msb( snap ) )
3781 flags |= ZXSTSNET_PROGRAMMABLE_TRAP_MSB;
3782 if( libspectrum_snap_spectranet_all_traps_disabled( snap ) )
3783 flags |= ZXSTSNET_ALL_DISABLED;
3784 if( libspectrum_snap_spectranet_rst8_trap_disabled( snap ) )
3785 flags |= ZXSTSNET_RST8_DISABLED;
3786 if( libspectrum_snap_spectranet_deny_downstream_a15( snap ) )
3787 flags |= ZXSTSNET_DENY_DOWNSTREAM_A15;
3788 if( libspectrum_snap_spectranet_nmi_flipflop( snap ) )
3789 flags |= ZXSTSNET_NMI_FLIPFLOP;
3790 libspectrum_write_word( ptr, flags );
3791
3792 *(*ptr)++ = libspectrum_snap_spectranet_page_a( snap );
3793 *(*ptr)++ = libspectrum_snap_spectranet_page_b( snap );
3794
3795 libspectrum_write_word( ptr,
3796 libspectrum_snap_spectranet_programmable_trap( snap ) );
3797
3798 memcpy( *ptr, libspectrum_snap_spectranet_w5100( snap, 0 ), 0x30 );
3799 (*ptr) += 0x30;
3800
3801 return LIBSPECTRUM_ERROR_NONE;
3802 }
3803
3804 static libspectrum_error
write_snef_chunk(libspectrum_byte ** buffer,libspectrum_byte ** ptr,size_t * length,libspectrum_snap * snap,int compress)3805 write_snef_chunk( libspectrum_byte **buffer, libspectrum_byte **ptr,
3806 size_t *length, libspectrum_snap *snap, int compress )
3807 {
3808 #ifdef HAVE_ZLIB_H
3809 libspectrum_error error;
3810 #endif
3811
3812 size_t flash_length;
3813 libspectrum_byte *flash_data;
3814 libspectrum_byte *compressed_flash_data = NULL;
3815 int flash_compressed = 0;
3816
3817 size_t block_size;
3818 libspectrum_byte flags = 0;
3819
3820 flash_data = libspectrum_snap_spectranet_flash( snap, 0 );
3821 flash_length = 0x20000;
3822
3823 #ifdef HAVE_ZLIB_H
3824
3825 if( compress ) {
3826 size_t compressed_length;
3827
3828 error = libspectrum_zlib_compress( flash_data, flash_length,
3829 &compressed_flash_data, &compressed_length );
3830 if( error ) return error;
3831
3832 if( compress & LIBSPECTRUM_FLAG_SNAPSHOT_ALWAYS_COMPRESS ||
3833 compressed_length < flash_length ) {
3834 flash_compressed = 1;
3835 flash_data = compressed_flash_data;
3836 flash_length = compressed_length;
3837 }
3838 }
3839
3840 #endif
3841
3842 block_size = 5 + flash_length;
3843
3844 write_chunk_header( buffer, ptr, length, ZXSTBID_SPECTRANETFLASHPAGE,
3845 block_size );
3846
3847 if( flash_compressed )
3848 flags |= ZXSTSNEF_FLASH_COMPRESSED;
3849 *(*ptr)++ = flags;
3850
3851 libspectrum_write_dword( ptr, flash_length );
3852 memcpy( *ptr, flash_data, flash_length ); *ptr += flash_length;
3853
3854 if( flash_compressed )
3855 libspectrum_free( compressed_flash_data );
3856
3857 return LIBSPECTRUM_ERROR_NONE;
3858 }
3859
3860 static libspectrum_error
write_sner_chunk(libspectrum_byte ** buffer,libspectrum_byte ** ptr,size_t * length,libspectrum_snap * snap,int compress)3861 write_sner_chunk( libspectrum_byte **buffer, libspectrum_byte **ptr,
3862 size_t *length, libspectrum_snap *snap, int compress )
3863 {
3864 #ifdef HAVE_ZLIB_H
3865 libspectrum_error error;
3866 #endif
3867
3868 size_t ram_length;
3869 libspectrum_byte *ram_data;
3870 libspectrum_byte *compressed_ram_data = NULL;
3871 int ram_compressed = 0;
3872
3873 size_t block_size;
3874 libspectrum_byte flags = 0;
3875
3876 ram_data = libspectrum_snap_spectranet_ram( snap, 0 );
3877 ram_length = 0x20000;
3878
3879 #ifdef HAVE_ZLIB_H
3880
3881 if( compress ) {
3882 size_t compressed_length;
3883
3884 error = libspectrum_zlib_compress( ram_data, ram_length,
3885 &compressed_ram_data, &compressed_length );
3886 if( error ) return error;
3887
3888 if( compress & LIBSPECTRUM_FLAG_SNAPSHOT_ALWAYS_COMPRESS ||
3889 compressed_length < ram_length ) {
3890 ram_compressed = 1;
3891 ram_data = compressed_ram_data;
3892 ram_length = compressed_length;
3893 }
3894 }
3895
3896 #endif
3897
3898 block_size = 5 + ram_length;
3899
3900 write_chunk_header( buffer, ptr, length, ZXSTBID_SPECTRANETRAMPAGE,
3901 block_size );
3902
3903 if( ram_compressed )
3904 flags |= ZXSTSNER_RAM_COMPRESSED;
3905 *(*ptr)++ = flags;
3906
3907 libspectrum_write_dword( ptr, ram_length );
3908 memcpy( *ptr, ram_data, ram_length ); *ptr += ram_length;
3909
3910 if( ram_compressed )
3911 libspectrum_free( compressed_ram_data );
3912
3913 return LIBSPECTRUM_ERROR_NONE;
3914 }
3915
3916 static void
write_chunk_header(libspectrum_byte ** buffer,libspectrum_byte ** ptr,size_t * length,const char * id,libspectrum_dword block_length)3917 write_chunk_header( libspectrum_byte **buffer, libspectrum_byte **ptr,
3918 size_t *length, const char *id,
3919 libspectrum_dword block_length )
3920 {
3921 libspectrum_make_room( buffer, 8 + block_length, ptr, length );
3922 memcpy( *ptr, id, 4 ); *ptr += 4;
3923 libspectrum_write_dword( ptr, block_length );
3924 }
3925