3 * coded by Ketmar // Invisible Vector
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.
13 #include "dskldr_common.h"
14 #include "dskfs_all.h"
17 //==========================================================================
21 // crc32 for UDI, taken from Unreal 0.32.7
23 //==========================================================================
24 static void udiCRC32 (uint32_t *crcp
, const uint8_t *buf
, int len
) {
28 for (int k
= 8; --k
; ) { int temp
= -(crc
&1); crc
>>= 1, crc
^= 0xEDB88320&temp
; }
35 //==========================================================================
39 //==========================================================================
40 static int loadUDITrack (Floppy
*flp
, FILE *fl
, uint8_t tr
, int sd
) {
41 int rt
= (tr
<<1)+(sd
? 1 : 0);
44 uint8_t trkBuf
[FLP_MAX_TRACK_SIZE
];
45 if (fread(&type
, 1, 1, fl
) != 1) {
46 // only MFM disks are allowed
47 libfdcMsg(LIBFDC_MSG_ERROR
, "only MFM UDI disks are allowed");
52 //fprintf(stderr, "UDI: TRK %u: unknown format 0x%02x\n", rt, type);
53 libfdcMsg(LIBFDC_MSG_ERROR
, "UDI track %u unknown format 0x%02x", rt
, type
);
54 if (freaduint(fl
, &len
, 4) < 0 || len
> 0x7fffffffU
) return FLPERR_SHIT
; // field len
55 if (fseek(fl
, len
, SEEK_CUR
) != 0) return FLPERR_SHIT
;
59 if (freaduint(fl
, &len
, 2) < 0) return FLPERR_SHIT
;
60 if (len
> FLP_MAX_TRACK_SIZE
) {
61 //fprintf(stderr, "UDI: TRK %u: too long (%u)\n", rt, len);
62 libfdcMsg(LIBFDC_MSG_ERROR
, "UDI track %u too long (%u/%u)", rt
, len
, (unsigned)FLP_MAX_TRACK_SIZE
);
65 if (fseek(fl
, len
, SEEK_CUR
) != 0) return FLPERR_SHIT
;
67 len
= (len
>>3)+((len
&7) == 0 ? 0 : 1);
68 if (fseek(fl
, len
, SEEK_CUR
) != 0) return FLPERR_SHIT
;
70 memset(trkBuf
, 0, sizeof(trkBuf
));
71 if (fread(trkBuf
, FLP_MAX_TRACK_SIZE
, 1, fl
) != 1) return FLPERR_SHIT
;
72 flpPutTrack(flp
, rt
, trkBuf
, FLP_MAX_TRACK_SIZE
);
73 // skip rest of the track image
74 if (fseek(fl
, len
-FLP_MAX_TRACK_SIZE
, SEEK_CUR
) != 0) return FLPERR_SHIT
;
75 // process bit fields?
76 len
= (len
>>3)+(((len
&7) == 0) ? 0 : 1); // skip bit field
77 if (fseek(fl
, len
, SEEK_CUR
) != 0) return FLPERR_SHIT
;
80 memset(trkBuf
, 0, sizeof(trkBuf
));
81 if (len
> 0 && fread(trkBuf
, len
, 1, fl
) != 1) return FLPERR_SHIT
;
82 flpPutTrack(flp
, rt
, trkBuf
, len
);
83 // process bit fields?
84 len
= (len
>>3)+(((len
&7) == 0) ? 0 : 1); // skip bit field
85 if (fseek(fl
, len
, SEEK_CUR
) != 0) return FLPERR_SHIT
;
92 //==========================================================================
96 //==========================================================================
97 int dskLoadUDI (Floppy
*flp
, FILE *fl
) {
99 if (fl
== NULL
) return FLPERR_SHIT
;
100 if (fread(buf
, 16, 1, fl
) != 1) {
101 libfdcMsg(LIBFDC_MSG_ERROR
, "cannot load UDI header");
104 if (memcmp(buf
, "UDI!", 4) != 0) {
105 libfdcMsg(LIBFDC_MSG_ERROR
, "not an UDI image");
109 libfdcMsg(LIBFDC_MSG_ERROR
, "invalid UDI version (%u)", buf
[8]);
113 libfdcMsg(LIBFDC_MSG_ERROR
, "invalid UDI side count (%u)", buf
[10]+1);
116 if (buf
[12] != 0 || buf
[13] != 0 || buf
[14] != 0 || buf
[15] != 0) {
117 libfdcMsg(LIBFDC_MSG_ERROR
, "found UDI extender header (%u bytes)", (unsigned)(buf
[10]|(buf
[11]<<8)|(buf
[12]<<16)|(buf
[13]<<24)));
120 const int cylCount
= buf
[9]+1; // max track
121 const int sides
= (buf
[10] == 0x01); // true if double side
122 libfdcMsg(LIBFDC_MSG_DEBUG
, "UDI: %d sides, %d cylinders", sides
+1, cylCount
);
123 for (int i
= 0; i
< cylCount
; ++i
) {
124 if (loadUDITrack(flp
, fl
, (uint8_t)i
, 0) < 0) goto error
;
125 if (sides
) { if (loadUDITrack(flp
, fl
, (uint8_t)i
, 1) < 0) goto error
; }
128 flp
->doubleSide
= (sides
? 1 : 0);
129 flp
->trk80
= (cylCount
> 42 ? 1 : 0);
141 //==========================================================================
145 //==========================================================================
146 static void getUDIBitField (Floppy
*flp
, uint8_t tr
, uint8_t *buf
) {
148 uint8_t fieldBuf
[FLP_MAX_TRACK_SIZE
];
149 uint8_t trkBuf
[FLP_MAX_TRACK_SIZE
];
150 flpGetTrack(flp
, tr
, trkBuf
);
151 flpGetTrackFields(flp
, tr
, fieldBuf
);
152 for (int i
= 0; i
< FLP_MAX_TRACK_SIZE
; ++i
) {
157 if (fieldBuf
[i
] == 0 && trkBuf
[i
] == 0xa1) *buf
|= (uint8_t)msk
;
163 //==========================================================================
167 //==========================================================================
168 int dskSaveUDI (Floppy
*flp
, FILE *fl
) {
169 static const char *sign
= "UDI!";
170 uint8_t *img
; // 0x112cf4 for 160 tracks in UDI
171 uint8_t *dptr
, *bptr
;
172 if (fl
== NULL
) return FLPERR_SHIT
;
173 if ((dptr
= img
= calloc(1, 0x112cf4)) == NULL
) return FLPERR_SHIT
;
174 memcpy(dptr
, sign
, 4);
177 *(dptr
++) = 0x00; // version
178 *(dptr
++) = (flp
->trk80
? 79 : 39); // maximun track number
179 *(dptr
++) = (flp
->doubleSide
? 1 : 0); // double side (due to floppy property)
185 for (int i
= 0; i
< (flp
->trk80
? 160 : 80); ++i
) {
186 *(dptr
++) = 0x00; // MFM
187 *(dptr
++) = FLP_MAX_TRACK_SIZE
&0xffU
; // track len
188 *(dptr
++) = (FLP_MAX_TRACK_SIZE
>>8)&0xffU
;
189 flpGetTrack(flp
, i
, dptr
); // track image
190 dptr
+= FLP_MAX_TRACK_SIZE
;
191 getUDIBitField(flp
, i
, dptr
);
192 dptr
+= 782; // 6250/8+1
193 if (!flp
->doubleSide
) ++i
; // if single-side skip
195 int i
= (int)(ptrdiff_t)(dptr
-img
);
197 uint32_t j
= 0xffffffffU
;
198 udiCRC32(&j
, img
, i
);
199 //fprintf(stderr, "UDI: crc = 0x%08x\n", j);
202 if (fwrite(img
, (ptrdiff_t)(dptr
-img
), 1, fl
) != 1) {