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