34
34
#include "fsimage-gcr.h"
35
35
#include "fsimage.h"
42
44
static log_t fsimage_gcr_log = LOG_ERR;
43
45
static const BYTE gcr_image_header_expected[] =
44
{ 0x47, 0x43, 0x52, 0x2D, 0x31, 0x35, 0x34, 0x31 };
45
/* Hardcoded/expected values VICE works with:
46
* 0x1EF8 - 7928: Maximum container size for a raw GCR track
47
* 0x54 - 84: Maximum container size for (half) track pointers
48
* 0x00 - 0: GCR image file version number
50
static const DWORD gcr_container_sizes_expected = 0x1EF85400;
46
{ 0x47, 0x43, 0x52, 0x2D, 0x31, 0x35, 0x34, 0x31, 0x00 };
52
48
/*-----------------------------------------------------------------------*/
53
49
/* Intial GCR buffer setup. */
55
int fsimage_read_gcr_image(disk_image_t *image)
51
int fsimage_read_gcr_image(const disk_image_t *image)
57
unsigned int track, num_tracks;
58
DWORD gcr_track_p[MAX_TRACKS_1541 * 2];
59
DWORD gcr_speed_p[MAX_TRACKS_1541 * 2];
60
BYTE gcr_image_header[ sizeof( gcr_image_header_expected ) ];
61
DWORD gcr_container_sizes;
64
fsimage = image->media.fsimage;
66
num_tracks = image->tracks;
68
/* Do G64 image file sanity checks, current VICE implementation
69
* does only support image file version 0 with a fixed track map
70
* container size of 84 and maximum track container size of 7928
72
fseek(fsimage->fd, 0, SEEK_SET);
73
if (fread(gcr_image_header, 1, sizeof( gcr_image_header_expected ), fsimage->fd) < 1) {
74
log_error(fsimage_gcr_log, "Could not read GCR disk image.");
77
if (memcmp( gcr_image_header_expected, gcr_image_header,
78
sizeof( gcr_image_header_expected ) ) != 0) {
79
log_error(fsimage_gcr_log,
80
"Unexpected GCR header found." );
83
if (util_dword_read(fsimage->fd, &gcr_container_sizes, 1) < 0) {
84
log_error(fsimage_gcr_log, "Could not read GCR disk image.");
87
if (gcr_container_sizes != gcr_container_sizes_expected) {
88
log_error(fsimage_gcr_log,
89
"Unexpected GCR image file constants found, VICE is unable to work with." );
93
fseek(fsimage->fd, 12, SEEK_SET);
94
if (util_dword_read(fsimage->fd, gcr_track_p, num_tracks * 2) < 0) {
95
log_error(fsimage_gcr_log, "Could not read GCR disk image.");
99
fseek(fsimage->fd, 12 + num_tracks * 8, SEEK_SET);
100
if (util_dword_read(fsimage->fd, gcr_speed_p, num_tracks * 2) < 0) {
101
log_error(fsimage_gcr_log, "Could not read GCR disk image.");
105
for (track = 0; track < MAX_TRACKS_1541; track++) {
106
BYTE *track_data, *zone_data;
108
track_data = image->gcr->data + track * NUM_MAX_BYTES_TRACK;
109
zone_data = image->gcr->speed_zone + track * NUM_MAX_BYTES_TRACK;
110
memset(track_data, 0xff, NUM_MAX_BYTES_TRACK);
111
memset(zone_data, 0x00, NUM_MAX_BYTES_TRACK / 4);
112
image->gcr->track_size[track] = 6250;
114
if (track <= num_tracks && gcr_track_p[track * 2] != 0) {
118
unsigned int zone_len;
120
offset = gcr_track_p[track * 2];
122
fseek(fsimage->fd, offset, SEEK_SET);
123
if (fread(len, 2, 1, fsimage->fd) < 1) {
124
log_error(fsimage_gcr_log, "Could not read GCR disk image.");
128
track_len = len[0] + len[1] * 256;
130
if (track_len < 5000 || track_len > 7928) {
131
log_error(fsimage_gcr_log,
132
"Track field length %i is not supported.",
137
image->gcr->track_size[track] = (unsigned int)track_len;
139
fseek(fsimage->fd, offset + 2, SEEK_SET);
140
if (fread(track_data, track_len, 1, fsimage->fd) < 1) {
141
log_error(fsimage_gcr_log, "Could not read GCR disk image.");
145
zone_len = (unsigned int)((track_len + 3) / 4);
147
if (gcr_speed_p[track * 2] > 3) {
149
BYTE comp_speed[NUM_MAX_BYTES_TRACK / 4];
151
offset = gcr_speed_p[track * 2];
153
fseek(fsimage->fd, offset, SEEK_SET);
154
if (fread(comp_speed, zone_len, 1, fsimage->fd) < 1) {
155
log_error(fsimage_gcr_log,
156
"Could not read GCR disk image.");
159
for (i = 0; i < zone_len; i++) {
160
zone_data[i * 4 + 3] = comp_speed[i] & 3;
161
zone_data[i * 4 + 2] = (comp_speed[i] >> 2) & 3;
162
zone_data[i * 4 + 1] = (comp_speed[i] >> 4) & 3;
163
zone_data[i * 4 ] = (comp_speed[i] >> 6) & 3;
166
memset(zone_data, gcr_speed_p[track * 2], NUM_MAX_BYTES_TRACK);
53
unsigned int half_track;
55
for (half_track = 0; half_track < MAX_GCR_TRACKS; half_track++) {
56
if (image->gcr->tracks[half_track].data) {
57
lib_free(image->gcr->tracks[half_track].data);
58
image->gcr->tracks[half_track].data = NULL;
59
image->gcr->tracks[half_track].size = 0;
61
if (half_track < image->max_half_tracks) {
62
fsimage_gcr_read_half_track(image, half_track + 2, &image->gcr->tracks[half_track]);
67
/*-----------------------------------------------------------------------*/
68
/* Seek to half track */
70
static long fsimage_gcr_seek_half_track(fsimage_t *fsimage, unsigned int half_track,
71
WORD *max_track_length, BYTE *num_half_tracks)
75
if (fsimage->fd == NULL) {
76
log_error(fsimage_gcr_log, "Attempt to read without disk image.");
79
if (util_fpread(fsimage->fd, buf, 12, 0) < 0) {
80
log_error(fsimage_gcr_log, "Could not read GCR disk image.");
83
if (memcmp(gcr_image_header_expected, buf, sizeof(gcr_image_header_expected)) != 0) {
84
log_error(fsimage_gcr_log, "Unexpected GCR header found." );
88
*num_half_tracks = buf[9];
89
if (*num_half_tracks > MAX_GCR_TRACKS) {
90
log_error(fsimage_gcr_log, "Too many half tracks." );
94
*max_track_length = util_le_buf_to_word(&buf[10]);
95
if (*max_track_length > NUM_MAX_MEM_BYTES_TRACK) {
96
log_error(fsimage_gcr_log, "Too large max track length.");
100
if (util_fpread(fsimage->fd, buf, 4, 12 + (half_track - 2) * 4) < 0) {
101
log_error(fsimage_gcr_log, "Could not read GCR disk image.");
104
return util_le_buf_to_dword(buf);
173
107
/*-----------------------------------------------------------------------*/
174
108
/* Read an entire GCR track from the disk image. */
176
int fsimage_gcr_read_track(disk_image_t *image, unsigned int track,
177
BYTE *gcr_data, int *gcr_track_size)
110
int fsimage_gcr_read_half_track(const disk_image_t *image, unsigned int half_track,
183
116
fsimage_t *fsimage;
117
WORD max_track_length;
118
BYTE num_half_tracks;
185
120
fsimage = image->media.fsimage;
187
if (fsimage->fd == NULL) {
188
log_error(fsimage_gcr_log, "Attempt to read without disk image.");
192
fseek(fsimage->fd, 12 + (track - 1) * 8, SEEK_SET);
193
if (util_dword_read(fsimage->fd, &gcr_track_p, 1) < 0) {
194
log_error(fsimage_gcr_log, "Could not read GCR disk image.");
198
memset(gcr_data, 0xff, NUM_MAX_BYTES_TRACK);
199
*gcr_track_size = 6250;
201
if (gcr_track_p != 0) {
203
offset = gcr_track_p;
205
fseek(fsimage->fd, offset, SEEK_SET);
206
if (fread(len, 2, 1, fsimage->fd) < 1) {
125
offset = fsimage_gcr_seek_half_track(fsimage, half_track, &max_track_length, &num_half_tracks);
132
if (util_fpread(fsimage->fd, buf, 2, offset) < 0) {
207
133
log_error(fsimage_gcr_log, "Could not read GCR disk image.");
211
track_len = len[0] + len[1] * 256;
137
track_len = util_le_buf_to_word(buf);
213
if (track_len < 5000 || track_len > 7928) {
139
if ((track_len < 1) || (track_len > max_track_length)) {
214
140
log_error(fsimage_gcr_log,
215
"Track field length %i is not supported.",
141
"Track field length %u is not supported.",
220
*gcr_track_size = track_len;
146
raw->data = lib_calloc(1, track_len);
147
raw->size = track_len;
222
fseek(fsimage->fd, offset + 2, SEEK_SET);
223
if (fread(gcr_data, track_len, 1, fsimage->fd) < 1) {
149
if (fread(raw->data, track_len, 1, fsimage->fd) < 1) {
224
150
log_error(fsimage_gcr_log, "Could not read GCR disk image.");
154
raw->size = disk_image_raw_track_size(image->type, half_track / 2);
155
raw->data = lib_malloc(raw->size);
156
memset(raw->data, 0x55, raw->size);
161
static int fsimage_gcr_read_track(const disk_image_t *image, unsigned int track,
164
return fsimage_gcr_read_half_track(image, track << 1, raw);
231
167
/*-----------------------------------------------------------------------*/
232
168
/* Write an entire GCR track to the disk image. */
234
int fsimage_gcr_write_track(disk_image_t *image, unsigned int track,
235
int gcr_track_size, BYTE *gcr_speed_zone,
236
BYTE *gcr_track_start_ptr)
170
int fsimage_gcr_write_half_track(disk_image_t *image, unsigned int half_track,
171
const disk_track_t *raw)
239
unsigned int num_tracks;
241
DWORD gcr_track_p[MAX_TRACKS_1541 * 2];
242
DWORD gcr_speed_p[MAX_TRACKS_1541 * 2];
174
WORD max_track_length;
244
177
fsimage_t *fsimage;
178
BYTE num_half_tracks;
246
180
fsimage = image->media.fsimage;
248
if (fsimage->fd == NULL) {
249
log_error(fsimage_gcr_log, "Attempt to write without disk image.");
182
offset = fsimage_gcr_seek_half_track(fsimage, half_track, &max_track_length, &num_half_tracks);
253
186
if (image->read_only != 0) {
254
187
log_error(fsimage_gcr_log,
255
188
"Attempt to write to read-only disk image.");
259
num_tracks = image->tracks;
261
fseek(fsimage->fd, 12, SEEK_SET);
262
if (util_dword_read(fsimage->fd, gcr_track_p, num_tracks * 2) < 0) {
263
log_error(fsimage_gcr_log, "Could not read GCR disk image header.");
267
fseek(fsimage->fd, 12 + num_tracks * 8, SEEK_SET);
268
if (util_dword_read(fsimage->fd, gcr_speed_p, num_tracks * 2) < 0) {
269
log_error(fsimage_gcr_log, "Could not read GCR disk image header.");
273
if (gcr_track_p[(track - 1) * 2] == 0) {
192
if (raw->size > max_track_length) {
193
log_error(fsimage_gcr_log,
194
"Track too long for image.");
274
199
offset = fseek(fsimage->fd, 0, SEEK_END);
201
offset = ftell(fsimage->fd);
275
203
if (offset < 0) {
276
204
log_error(fsimage_gcr_log, "Could not extend GCR disk image.");
279
gcr_track_p[(track - 1) * 2] = offset;
282
offset = gcr_track_p[(track - 1) * 2];
284
len[0] = gcr_track_size % 256;
285
len[1] = gcr_track_size / 256;
287
if (fseek(fsimage->fd, offset, SEEK_SET) < 0
288
|| fwrite(len, 2, 1, fsimage->fd) < 1) {
289
log_error(fsimage_gcr_log, "Could not write GCR disk image.");
293
/* Clear gap between the end of the actual track and the start of
295
gap = NUM_MAX_BYTES_TRACK - gcr_track_size;
297
memset(gcr_track_start_ptr + gcr_track_size, 0, gap);
299
if (fseek(fsimage->fd, offset + 2, SEEK_SET) < 0
300
|| fwrite(gcr_track_start_ptr, NUM_MAX_BYTES_TRACK, 1,
302
log_error(fsimage_gcr_log, "Could not write GCR disk image.");
306
if (gcr_speed_zone != NULL) {
307
for (i = 0; (gcr_speed_zone[(track - 1) * NUM_MAX_BYTES_TRACK]
308
== gcr_speed_zone[(track - 1) * NUM_MAX_BYTES_TRACK + i])
309
&& i < NUM_MAX_BYTES_TRACK; i++);
311
if (i < gcr_track_size) {
312
/* This will change soon. */
313
log_error(fsimage_gcr_log,
314
"Saving different speed zones is not supported yet.");
318
if (gcr_speed_p[(track - 1) * 2] >= 4) {
319
/* This will change soon. */
320
log_error(fsimage_gcr_log,
321
"Adding new speed zones is not supported yet.");
325
offset = 12 + num_tracks * 8 + (track - 1) * 8;
326
if (fseek(fsimage->fd, offset, SEEK_SET) < 0
327
|| util_dword_write(fsimage->fd, &gcr_speed_p[(track - 1) * 2], 1)
329
log_error(fsimage_gcr_log, "Could not write GCR disk image.");
334
#if 0 /* We do not support writing different speeds yet. */
335
for (i = 0; i < (NUM_MAX_BYTES_TRACK / 4); i++)
336
zone_len = (gcr_track_size + 3) / 4;
337
zone_data = gcr_speed_zone + (track - 1) * NUM_MAX_BYTES_TRACK;
340
memset(zone_data + gcr_track_size, 0, gap);
342
for (i = 0; i < (NUM_MAX_BYTES_TRACK / 4); i++)
343
comp_speed[i] = (zone_data[i * 4]
344
| (zone_data[i * 4 + 1] << 2)
345
| (zone_data[i * 4 + 2] << 4)
346
| (zone_data[i * 4 + 3] << 6));
348
if (fseek(fsimage->fd, offset, SEEK_SET) < 0
349
|| fwrite((char *)comp_speed, NUM_MAX_BYTES_TRACK / 4, 1
351
log_error(fsimage_gcr_log, "Could not write GCR disk image");
210
if (raw->data != NULL) {
211
util_word_to_le_buf(buf, raw->size);
213
if (util_fpwrite(fsimage->fd, buf, 2, offset) < 0) {
214
log_error(fsimage_gcr_log, "Could not write GCR disk image.");
218
/* Clear gap between the end of the actual track and the start of
220
if (fwrite(raw->data, raw->size, 1, fsimage->fd) < 1) {
221
log_error(fsimage_gcr_log, "Could not write GCR disk image.");
224
gap = max_track_length - raw->size;
227
BYTE *padding = lib_calloc(1, gap);
228
fwrite(padding, gap, 1, fsimage->fd);
233
util_dword_to_le_buf(buf, offset);
234
if (util_fpwrite(fsimage->fd, buf, 4, 12 + (half_track - 2) * 4) < 0) {
235
log_error(fsimage_gcr_log, "Could not write GCR disk image.");
239
util_dword_to_le_buf(buf, disk_image_speed_map(image->type, half_track / 2));
240
if (util_fpwrite(fsimage->fd, buf, 4, 12 + (half_track - 2 + num_half_tracks) * 4) < 0) {
241
log_error(fsimage_gcr_log, "Could not write GCR disk image.");
356
247
/* Make sure the stream is visible to other readers. */
357
248
fflush(fsimage->fd);
253
static int fsimage_gcr_write_track(disk_image_t *image, unsigned int track,
254
const disk_track_t *raw)
256
return fsimage_gcr_write_half_track(image, track << 1, raw);
362
259
/*-----------------------------------------------------------------------*/
363
260
/* Read a sector from the GCR disk image. */
365
int fsimage_gcr_read_sector(disk_image_t *image, BYTE *buf,
366
unsigned int track, unsigned int sector)
262
int fsimage_gcr_read_sector(const disk_image_t *image, BYTE *buf, const disk_addr_t *dadr)
368
BYTE gcr_data[NUM_MAX_BYTES_TRACK], *gcr_track_start_ptr;
369
int gcr_track_size, gcr_current_track_size;
371
if (track > image->tracks) {
266
if (dadr->track > image->tracks) {
372
267
log_error(fsimage_gcr_log,
373
268
"Track %i out of bounds. Cannot read GCR track.",
377
273
if (image->gcr == NULL) {
378
if (fsimage_gcr_read_track(image, track, gcr_data,
379
&gcr_track_size) < 0) {
380
log_error(fsimage_gcr_log,
381
"Cannot read track %i from GCR image.", track);
275
if (fsimage_gcr_read_track(image, dadr->track, &raw) < 0) {
278
if (raw.data == NULL) {
279
return CBMDOS_IPE_NOT_READY;
384
gcr_track_start_ptr = gcr_data;
385
gcr_current_track_size = gcr_track_size;
281
rf = gcr_read_sector(&raw, buf, dadr->sector);
387
gcr_track_start_ptr = image->gcr->data
388
+ ((track - 1) * NUM_MAX_BYTES_TRACK);
389
gcr_current_track_size = image->gcr->track_size[track - 1];
284
rf = gcr_read_sector(&image->gcr->tracks[(dadr->track * 2) - 2], buf, dadr->sector);
391
if (gcr_read_sector(gcr_track_start_ptr, gcr_current_track_size,
392
buf, track, sector) < 0) {
286
if (rf != CBMDOS_FDC_ERR_OK) {
393
287
log_error(fsimage_gcr_log,
394
288
"Cannot find track: %i sector: %i within GCR image.",
289
dadr->track, dadr->sector);
291
case CBMDOS_FDC_ERR_HEADER:
292
return CBMDOS_IPE_READ_ERROR_BNF; /* 20 */
293
case CBMDOS_FDC_ERR_SYNC:
294
return CBMDOS_IPE_READ_ERROR_SYNC; /* 21 */
295
case CBMDOS_FDC_ERR_NOBLOCK:
296
return CBMDOS_IPE_READ_ERROR_DATA; /* 22 */
297
case CBMDOS_FDC_ERR_DCHECK:
298
return CBMDOS_IPE_READ_ERROR_CHK; /* 23 */
299
case CBMDOS_FDC_ERR_VERIFY:
300
return CBMDOS_IPE_WRITE_ERROR_VER; /* 25 */
301
case CBMDOS_FDC_ERR_WPROT:
302
return CBMDOS_IPE_WRITE_PROTECT_ON; /* 26 */
303
case CBMDOS_FDC_ERR_HCHECK:
304
return CBMDOS_IPE_READ_ERROR_BCHK; /* 27 */
305
case CBMDOS_FDC_ERR_BLENGTH:
306
return CBMDOS_IPE_WRITE_ERROR_BIG; /* 28 */
307
case CBMDOS_FDC_ERR_ID:
308
return CBMDOS_IPE_DISK_ID_MISMATCH; /* 29 */
309
case CBMDOS_FDC_ERR_DRIVE:
310
return CBMDOS_IPE_NOT_READY; /* 74 */
311
case CBMDOS_FDC_ERR_DECODE:
312
return CBMDOS_IPE_READ_ERROR_GCR; /* 24 */
314
return CBMDOS_IPE_NOT_READY;
317
return CBMDOS_IPE_OK;
403
321
/*-----------------------------------------------------------------------*/
404
322
/* Write a sector to the GCR disk image. */
406
int fsimage_gcr_write_sector(disk_image_t *image, BYTE *buf,
407
unsigned int track, unsigned int sector)
324
int fsimage_gcr_write_sector(disk_image_t *image, const BYTE *buf,
325
const disk_addr_t *dadr)
409
BYTE gcr_data[NUM_MAX_BYTES_TRACK];
410
BYTE *gcr_track_start_ptr, *speed_zone;
411
int gcr_track_size, gcr_current_track_size;
413
if (track > image->tracks) {
327
if (dadr->track > image->tracks) {
414
328
log_error(fsimage_gcr_log,
415
329
"Track %i out of bounds. Cannot write GCR sector",
419
334
if (image->gcr == NULL) {
420
if (fsimage_gcr_read_track(image, track, gcr_data,
421
&gcr_track_size) < 0) {
336
if (fsimage_gcr_read_track(image, dadr->track, &raw) < 0
337
|| raw.data == NULL) {
340
if (gcr_write_sector(&raw, buf, dadr->sector) != CBMDOS_FDC_ERR_OK) {
422
341
log_error(fsimage_gcr_log,
423
"Cannot read track %i from GCR image.", track);
426
gcr_track_start_ptr = gcr_data;
427
gcr_current_track_size = gcr_track_size;
342
"Could not find track %i sector %i in disk image",
343
dadr->track, dadr->sector);
347
if (fsimage_gcr_write_track(image, dadr->track, &raw) < 0) {
430
gcr_track_start_ptr = image->gcr->data
431
+ ((track - 1) * NUM_MAX_BYTES_TRACK);
432
gcr_current_track_size = image->gcr->track_size[track - 1];
433
speed_zone = image->gcr->speed_zone;
435
if (gcr_write_sector(gcr_track_start_ptr,
436
gcr_current_track_size, buf, track, sector) < 0) {
437
log_error(fsimage_gcr_log,
438
"Could not find track %i sector %i in disk image",
442
if (disk_image_write_track(image, track, gcr_current_track_size,
443
speed_zone, gcr_track_start_ptr) < 0) {
444
log_error(fsimage_gcr_log,
445
"Failed writing track %i to disk image.", track);
353
if (gcr_write_sector(&image->gcr->tracks[(dadr->track * 2) - 2], buf, dadr->sector) != CBMDOS_FDC_ERR_OK) {
354
log_error(fsimage_gcr_log,
355
"Could not find track %i sector %i in disk image",
356
dadr->track, dadr->sector);
359
if (fsimage_gcr_write_track(image, dadr->track, &image->gcr->tracks[(dadr->track * 2) - 2]) < 0) {
360
log_error(fsimage_gcr_log,
361
"Failed writing track %i to disk image.", dadr->track);