3 * based on the code by SAM style
4 * Understanding is not required. Only obedience.
6 * This program is free software. It comes without any warranty, to
7 * the extent permitted by applicable law. You can redistribute it
8 * and/or modify it under the terms of the Do What The Fuck You Want
9 * To Public License, Version 2, as published by Sam Hocevar. See
10 * http://sam.zoy.org/wtfpl/COPYING for more details.
14 //#include "filetypes.h"
16 // +0x00 signature (23)
18 // +0x22 disk info block
20 typedef struct LIBFDC_PACKED
{
21 uint8_t byte0d0f
[4]; // unused
24 uint8_t dataRate
; // unknown, SD, HD, ED
25 uint8_t recMode
; // unknown, FM, MFM
30 uint8_t sectorInfo
[0x100-0x18]; // max 29 (x 8 bytes)
34 typedef struct LIBFDC_PACKED
{
43 } SectorInfBlock
; // 8 bytes
46 static const char edsksgn
[8] = "EXTENDED";
47 static const char dsksgn
[8] = "MV - CPC";
50 int dskLoadDSK (Floppy
*flp
, FILE *fl
) {
51 //fprintf(stderr, "*** loading DSK (000) (fpl=%p; ins=%d) ***\n", flp, (flp ? flp->insert : -1));
52 if (!flp
) return FLPERR_SHIT
;
53 if (fl
== NULL
) return FLPERR_SHIT
;
58 //fprintf(stderr, "*** loading DSK ***\n");
60 if (fread(sigBuf
, 256, 1, fl
) != 1) {
61 libfdcMsg(LIBFDC_MSG_ERROR
, "cannot load DSK header");
67 if (!strncmp(sigBuf
, edsksgn
, 8)) {
70 } else if (!strncmp(sigBuf
, dsksgn
, 8)) {
75 libfdcMsg(LIBFDC_MSG_ERROR
, "invalid DSK signature");
80 for (int i
= 0; i
< 168; ++i
) {
81 memset(flp
->data
[i
].byte
, 0, FLP_MAX_TRACK_SIZE
);
82 flpFillFields(flp
, i
, 0);
85 int trkcnt
= sigBuf
[0x30]&0xff;
86 int sidcnt
= sigBuf
[0x31]&0xff;
88 if (sidcnt
== 0 || sidcnt
> 2) {
89 libfdcMsg(LIBFDC_MSG_ERROR
, "invalid number of DSK sides (%d)", sidcnt
);
94 libfdcMsg(LIBFDC_MSG_ERROR
, "DSK contains no tracks");
99 libfdcMsg(LIBFDC_MSG_WARNING
, "too many cylinders in DSK (%d), truncated to %d", trkcnt
, 86);
103 libfdcMsg(LIBFDC_MSG_DEBUG
, "DSK: %d head%s, %d cylinders", sidcnt
, (sidcnt
== 2 ? "s" :""), trkcnt
);
104 int tlen
= (sigBuf
[0x32]&0xff)|((sigBuf
[0x33]&0xff)<<8);
106 int pos
= 0x100; // 1st track allways @ 0x100
108 for (int i
= 0; i
< trkcnt
*sidcnt
&& !err
; ++i
) {
109 int rtlen
= (ext
? sigBuf
[0x34+i
]<<8 : tlen
);
111 // move to track info block
112 if (fseek(fl
, pos
, SEEK_SET
) < 0) {
113 libfdcMsg(LIBFDC_MSG_ERROR
, "cannot seek to DSK track info block for track %d", i
);
116 if (fread(sigBuf
, 12, 1, fl
) != 1) {
117 libfdcMsg(LIBFDC_MSG_ERROR
, "cannot read DSK track info block for track %d", i
);
121 if (strncmp(sigBuf
, "Track-Info\r\n", 12) == 0) {
123 if (fread((char *)&tib
, sizeof(TrackInfBlock
), 1, fl
) != 1) return FLPERR_SHIT
;
124 SectorInfBlock
*sib
= (SectorInfBlock
*)&tib
.sectorInfo
;
125 for (int sc
= 0; sc
< tib
.secCount
; ++sc
) {
128 if (sib
[sc
].size
> 5) {
131 slen
= (0x80<<sib
[sc
].size
)&0xffff;
134 slen
= sib
[sc
].bslo
|(sib
[sc
].bshi
<<8);
136 secs
[sc
].trk
= sib
[sc
].track
;
137 secs
[sc
].head
= sib
[sc
].side
;
138 secs
[sc
].sec
= sib
[sc
].sector
;
139 secs
[sc
].sz
= sib
[sc
].size
;
140 secs
[sc
].type
= 0xfb;
141 //fprintf(stderr, " sector(tr=%d;sc=%d): C=%d; H=%d; R=%d; N=%d; slen=%d\n", tr, sc, sib[sc].track, sib[sc].side, sib[sc].sector, sib[sc].size, slen);
142 if (fread((char *)secs
[sc
].data
, slen
, 1, fl
) != 1) return FLPERR_SHIT
;
144 // calculate good CRCs
145 flpFormatTracks(flp
, tr
, secs
, tib
.secCount
, FLP_FORMAT_TRACK_CALC_CRC
);
147 if (sidcnt
== 1) ++tr
;
150 libfdcMsg(LIBFDC_MSG_ERROR
, "invalid DSK track info block signature for track %d", i
);
151 err
= 1; //ERR_DSK_SIGN;
154 //flpFormatTracks(flp, tr, secs, tib.secCount, FLP_FORMAT_TRACK_CALC_CRC);
155 // flp_format_trk(flp, tr, 10, 512, NULL);
157 if (sidcnt
== 1) ++tr
;
161 flp
->doubleSide
= (sidcnt
> 1 ? 1 : 0);
162 flp
->trk80
= (trkcnt
> 42 ? 1 : 0);
165 return (err
? FLPERR_SHIT
: FLPERR_OK
);
169 static long saveTrackDSK (Floppy
*flp
, int trk
, int side
, FILE *fl
) {
172 long fpos
= ftell(fl
);
173 if (fpos
< 0) return -1;
178 int rtrk
= (trk
<<1)|side
;
180 memset(&tinf
, 0, sizeof(TrackInfBlock
));
181 // scan track & collect sectors info & data
182 for (pos
= 0; pos
< FLP_MAX_TRACK_SIZE
&& sec
< 29; ++pos
) {
183 if (flp
->data
[rtrk
].field
[pos
] == 1) {
185 sdata
[sec
].trk
= flp
->data
[rtrk
].byte
[pos
++]; // C
186 sdata
[sec
].head
= flp
->data
[rtrk
].byte
[pos
++];// H
187 sdata
[sec
].sec
= flp
->data
[rtrk
].byte
[pos
++]; // R
188 sdata
[sec
].sz
= flp
->data
[rtrk
].byte
[pos
++]&7;// N
189 pos
+= 2; // skip crc
190 if (sdata
[sec
].sz
> mdsz
) mdsz
= sdata
[sec
].sz
; // max N
191 dsz
= 128<<sdata
[sec
].sz
; // sector data size
192 if (dsz
> 0x1800) dsz
= 0x1800;
193 dps
= flp
->data
[rtrk
].map
[sdata
[sec
].sec
]; // position of sector data
194 if (dps
> 0) sdata
[sec
].type
= flp
->data
[rtrk
].byte
[dps
-1]; // sector data type (FB | F8)
195 memcpy(sdata
[sec
].data
, flp
->data
[rtrk
].byte
+dps
, dsz
); // copy sector data
199 if (sec
< 1) return 0; // no sectors found, no data written, size = 0
201 tinf
.track
= trk
&0xff;
203 tinf
.secSize
= mdsz
&7; // 0 @ extend dsk ?
204 tinf
.secCount
= sec
&0xff;
205 tinf
.gap3Size
= 0x1a;
208 for (int i
= 0; i
< sec
; ++i
) {
209 tinf
.sectorInfo
[pos
] = sdata
[i
].trk
;
210 tinf
.sectorInfo
[pos
+1] = sdata
[i
].head
;
211 tinf
.sectorInfo
[pos
+2] = sdata
[i
].sec
;
212 tinf
.sectorInfo
[pos
+3] = sdata
[i
].sz
;
213 dsz
= 128<<sdata
[i
].sz
;
214 if (i
== sec
-1) tinf
.sectorInfo
[pos
+4] = 0x80; // end of cylinder
215 tinf
.sectorInfo
[pos
+6] = dsz
&0xff;
216 tinf
.sectorInfo
[pos
+7] = (dsz
>>8)&0xff;
219 // save track info block
220 if (fwrite("Track-Info\r\n", 12, 1, fl
) != 1) return -1;
221 if (fwrite(&tinf
, sizeof(TrackInfBlock
), 1, fl
) != 1) return -1;
223 for (int i
= 0; i
< sec
; ++i
) {
224 dsz
= 128<<sdata
[i
].sz
;
225 if (dsz
> 0x1800) dsz
= 0x1800;
226 if (fwrite(sdata
[i
].data
, dsz
, 1, fl
) != 1) return -1;
228 long epos
= ftell(fl
);
229 if (epos
< 0) return -1;
234 static const char *sign
= "EXTENDED CPC DSK File\r\nDisk-Info\r\nZXEmuT ";
236 int dskSaveDSK (Floppy
*flp
, FILE *fl
) {
237 if (!flp
|| fl
== NULL
|| !flp
->insert
) return FLPERR_SHIT
;
239 memset(buf
, 0, 0x100);
240 memcpy(buf
, sign
, 0x22+0x0e);
241 // 30 = track count, will be updated later
243 // 32,33 = 0 @ extend format
244 // 34+N = size of track N (from Track-Info to Track-Info)
245 // fwrite(buf, 256, 1, fl); // signature + disk info : buf will be saved later
246 if (fseek(fl
, 256, SEEK_SET
) < 0) return FLPERR_SHIT
;
251 for (int i
= 0; i
< 86; ++i
) {
252 isize
= saveTrackDSK(flp
, i
, 0, fl
);
253 buf
[cpos
] = (isize
>>8)&0xff;
255 if (isize
> 0) tcount
= i
+1;
256 if (flp
->doubleSide
) {
257 isize
= saveTrackDSK(flp
, i
, 1, fl
);
258 if (isize
< 0) return FLPERR_SHIT
;
259 if (isize
> 0) ds
= 1;
260 buf
[cpos
] = (isize
>>8)&0xff;
262 if (isize
> 0) tcount
= i
+1;
265 buf
[0x30] = (tcount
< 43 ? 42 : 84); // = tcount & 0xff;
266 buf
[0x31] = (ds
? 2 : 1);
268 cpos
= 0x36; // 0x34 doesn't changed
271 buf
[tcount
] = buf
[cpos
];
277 // save disk info block
278 if (fseek(fl
, 0, SEEK_SET
) < 0) return FLPERR_SHIT
;
279 if (fwrite(buf
, 256, 1, fl
) != 1) return FLPERR_SHIT
;