UrForth: "STRLITERAL" now respects the optimiser
[urasm.git] / src / libfdc / dskldr_udi.c
blob536751647a450ebd58d364aa88bad5bceec3539c
1 /*
2 * disk images I/O
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.
12 #include "dskldr.h"
13 #include "dskldr_common.h"
14 #include "dskfs_all.h"
17 //==========================================================================
19 // udiCRC32
21 // crc32 for UDI, taken from Unreal 0.32.7
23 //==========================================================================
24 static void udiCRC32 (uint32_t *crcp, const uint8_t *buf, int len) {
25 uint32_t crc = *crcp;
26 while (len--) {
27 crc ^= -1^*buf++;
28 for (int k = 8; --k; ) { int temp = -(crc&1); crc >>= 1, crc ^= 0xEDB88320&temp; }
29 crc ^= FLPERR_SHIT;
31 *crcp = crc;
35 //==========================================================================
37 // loadUDITrack
39 //==========================================================================
40 static int loadUDITrack (Floppy *flp, FILE *fl, uint8_t tr, int sd) {
41 int rt = (tr<<1)+(sd ? 1 : 0);
42 uint8_t type;
43 uint32_t len;
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");
48 return FLPERR_SHIT;
50 if (type != 0x00) {
51 // skip unknown field
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;
56 } else {
57 // MFM
58 // track size
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);
63 #if 0
64 // skip track image
65 if (fseek(fl, len, SEEK_CUR) != 0) return FLPERR_SHIT;
66 // and bit field
67 len = (len>>3)+((len&7) == 0 ? 0 : 1);
68 if (fseek(fl, len, SEEK_CUR) != 0) return FLPERR_SHIT;
69 #else
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;
78 #endif
79 } else {
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;
88 return FLPERR_OK;
92 //==========================================================================
94 // dskLoadUDI
96 //==========================================================================
97 int dskLoadUDI (Floppy *flp, FILE *fl) {
98 uint8_t buf[16];
99 if (fl == NULL) return FLPERR_SHIT;
100 if (fread(buf, 16, 1, fl) != 1) {
101 libfdcMsg(LIBFDC_MSG_ERROR, "cannot load UDI header");
102 return FLPERR_SHIT;
104 if (memcmp(buf, "UDI!", 4) != 0) {
105 libfdcMsg(LIBFDC_MSG_ERROR, "not an UDI image");
106 return FLPERR_SHIT;
108 if (buf[8] != 0) {
109 libfdcMsg(LIBFDC_MSG_ERROR, "invalid UDI version (%u)", buf[8]);
110 return FLPERR_SHIT;
112 if (buf[10] > 1) {
113 libfdcMsg(LIBFDC_MSG_ERROR, "invalid UDI side count (%u)", buf[10]+1);
114 return FLPERR_SHIT;
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)));
118 return FLPERR_SHIT;
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; }
127 flp->protect = 0;
128 flp->doubleSide = (sides ? 1 : 0);
129 flp->trk80 = (cylCount > 42 ? 1 : 0);
130 flp->insert = 1;
131 flp->changed = 0;
132 return FLPERR_OK;
133 error:
134 flp->insert = 0;
135 flp->changed = 0;
136 flpFormatTRD(flp);
137 return FLPERR_SHIT;
141 //==========================================================================
143 // getUDIBitField
145 //==========================================================================
146 static void getUDIBitField (Floppy *flp, uint8_t tr, uint8_t *buf) {
147 unsigned msk = 0x01;
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) {
153 if (msk == 0x100) {
154 msk = 0x01;
155 *(++buf) = 0x00;
157 if (fieldBuf[i] == 0 && trkBuf[i] == 0xa1) *buf |= (uint8_t)msk;
158 msk <<= 1;
163 //==========================================================================
165 // dskSaveUDI
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);
175 bptr = img+4;
176 dptr += 8;
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)
180 *(dptr++) = 0x00;
181 *(dptr++) = 0x00;
182 *(dptr++) = 0x00;
183 *(dptr++) = 0x00;
184 *(dptr++) = 0x00;
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);
196 writeui32(bptr, i);
197 uint32_t j = 0xffffffffU;
198 udiCRC32(&j, img, i);
199 //fprintf(stderr, "UDI: crc = 0x%08x\n", j);
200 writeui32(dptr, j);
201 dptr += 4;
202 if (fwrite(img, (ptrdiff_t)(dptr-img), 1, fl) != 1) {
203 free(img);
204 return FLPERR_SHIT;
206 free(img);
207 flp->changed = 0;
208 return FLPERR_OK;