]> Shamusworld >> Repos - apple2/blob - src/fileio.cpp
Added support for the Apple High Speed SCSI card.
[apple2] / src / fileio.cpp
1 //
2 // fileio.cpp: File handling (mainly disk related)
3 //
4 // by James Hammons
5 // (C) 2019 Underground Software
6 //
7
8 #include "fileio.h"
9
10 #include <stdlib.h>
11 #include <string.h>
12 #include "crc32.h"
13 #include "log.h"
14
15
16 uint8_t woz1Header[8] = { 'W', 'O', 'Z', '1', 0xFF, 0x0A, 0x0D, 0x0A };
17 uint8_t woz2Header[8] = { 'W', 'O', 'Z', '2', 0xFF, 0x0A, 0x0D, 0x0A };
18 uint8_t standardTMAP[160] = {
19         0, 0, 0xFF, 1, 1, 1, 0xFF, 2, 2, 2, 0xFF, 3, 3, 3, 0xFF, 4, 4, 4, 0xFF,
20         5, 5, 5, 0xFF, 6, 6, 6, 0xFF, 7, 7, 7, 0xFF, 8, 8, 8, 0xFF, 9, 9, 9, 0xFF,
21         10, 10, 10, 0xFF, 11, 11, 11, 0xFF, 12, 12, 12, 0xFF, 13, 13, 13, 0xFF,
22         14, 14, 14, 0xFF, 15, 15, 15, 0xFF, 16, 16, 16, 0xFF, 17, 17, 17, 0xFF,
23         18, 18, 18, 0xFF, 19, 19, 19, 0xFF, 20, 20, 20, 0xFF, 21, 21, 21, 0xFF,
24         22, 22, 22, 0xFF, 23, 23, 23, 0xFF, 24, 24, 24, 0xFF, 25, 25, 25, 0xFF,
25         26, 26, 26, 0xFF, 27, 27, 27, 0xFF, 28, 28, 28, 0xFF, 29, 29, 29, 0xFF,
26         30, 30, 30, 0xFF, 31, 31, 31, 0xFF, 32, 32, 32, 0xFF, 33, 33, 33, 0xFF,
27         34, 34, 34, 0xFF, 0xFF, 0xFF,
28         0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
29         0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
30 };
31
32
33 //
34 // Note that size *must* be a valid pointer, otherwise this will go BOOM
35 //
36 uint8_t * ReadFile(const char * filename, uint32_t * size)
37 {
38         FILE * fp = fopen(filename, "rb");
39
40         if (!fp)
41                 return NULL;
42
43         fseek(fp, 0, SEEK_END);
44         *size = ftell(fp);
45         fseek(fp, 0, SEEK_SET);
46
47         uint8_t * buffer = (uint8_t *)malloc(*size);
48         fread(buffer, 1, *size, fp);
49         fclose(fp);
50
51         return buffer;
52 }
53
54
55 //
56 // This initializes the WOZ type 2 headers
57 //
58 void InitWOZ2Headers(WOZ2 & woz)
59 {
60         // Set up header (leave CRC as 0 for now)
61         memcpy(woz.magic, woz2Header, 8);
62         woz.crc32 = 0;
63
64         // INFO header
65         memcpy(woz.infoTag, "INFO", 4);
66         woz.infoSize = Uint32LE(60);
67         woz.infoVersion = 2;
68         woz.diskType = 1;
69         woz.writeProtected = 0;
70         woz.synchronized = 0;
71         woz.cleaned = 1;
72         memset(woz.creator, ' ', 32);
73         memcpy(woz.creator, "Apple2 emulator v1.0.0", 22);
74         woz.diskSides = 1;
75         woz.bootSectorFmt = 1;
76         woz.optimalBitTmg = 32;
77         woz.largestTrack = Uint16LE(13);
78
79         // TMAP header
80         memcpy(woz.tmapTag, "TMAP", 4);
81         woz.tmapSize = Uint32LE(160);
82
83         // TRKS header
84         memcpy(woz.trksTag, "TRKS", 4);
85 }
86
87
88 //
89 // This is used mainly to initialize blank disks and upconvert non-WOZ disks
90 //
91 uint8_t * InitWOZ(uint32_t * pSize/*= NULL*/)
92 {
93         uint32_t size = 1536 + (35 * (13 * 512));
94         uint8_t * data = (uint8_t *)malloc(size);
95         WOZ2 & woz = *((WOZ2 *)data);
96
97         // Zero out WOZ image in memory
98         memset(&woz, 0, size);
99
100         // Set up headers
101         InitWOZ2Headers(woz);
102         memcpy(woz.tmap, standardTMAP, 160);
103         woz.trksSize = Uint32LE(35 * (13 * 512));
104
105         for(int i=0; i<35; i++)
106         {
107                 woz.track[i].startingBlock = Uint16LE(3 + (i * 13));
108                 woz.track[i].blockCount = Uint16LE(13);
109                 woz.track[i].bitCount = Uint32LE(51200);
110         }
111
112         // META header (how to handle? prolly with a separate pointer)
113
114         if (pSize)
115                 *pSize = size;
116
117         return data;
118 }
119
120
121 uint8_t * UpconvertWOZ1ToWOZ2(uint8_t * woz1Data, uint32_t woz1Size, uint32_t * newSize)
122 {
123         WOZ1 & woz1 = *((WOZ1 *)woz1Data);
124
125         // First, figure out how large the new structure will be in comparison to
126         // the old one...
127         uint32_t numTracks = woz1.trksSize / sizeof(WOZ1Track);
128         uint32_t metadataSize = woz1Size - (Uint32LE(woz1.trksSize) + 256);
129
130         // N.B.: # of blocks for each track will *always* be <= 13 for WOZ1
131         *newSize = 0x600 + (numTracks * (13 * 512)) + metadataSize;
132         uint8_t * woz2Data = (uint8_t *)malloc(*newSize);
133         memset(woz2Data, 0, *newSize);
134
135         WOZ2 & woz2 = *((WOZ2 *)woz2Data);
136         InitWOZ2Headers(woz2);
137
138         // Copy parts of INFO & TMAP chunks over
139         memcpy(&woz2.diskType, &woz1.diskType, 36);
140         memcpy(woz2.tmap, woz1.tmap, 160);
141 //note: should check the CRC32 integrity 1st before attempting to recreate it here...  (the CRC is written out when it's saved anyway, so no need to fuck with this right now)
142         woz2.crc32 = 0;
143         woz2.trksSize = Uint32LE(numTracks * (13 * 512));
144
145         // Finally, copy over the tracks
146         for(uint32_t i=0; i<numTracks; i++)
147         {
148                 woz2.track[i].startingBlock = Uint16LE(3 + (i * 13));
149                 woz2.track[i].blockCount = Uint16LE(13);
150                 woz2.track[i].bitCount = woz1.track[i].bitCount;
151                 memcpy(woz2Data + ((3 + (i * 13)) * 512), woz1.track[i].bits, 6646);
152         }
153
154         // Finally, copy over the metadata
155         memcpy(woz2Data + Uint32LE(woz2.trksSize) + 0x600,
156                 woz1Data + Uint32LE(woz1.trksSize) + 0x100, metadataSize);
157
158         return woz2Data;
159 }
160
161
162 //
163 // Check WOZ type on the passed in contents (file loaded elsewhere).
164 // Returns type of WOZ if successful, 0 if not.
165 //
166 uint8_t CheckWOZType(const uint8_t * wozData, uint32_t wozSize)
167 {
168         // Basic sanity checking
169         if ((wozData == NULL) || (wozSize < 8))
170                 return 0;
171
172         if (memcmp(wozData, woz1Header, 8) == 0)
173                 return 1;
174         else if (memcmp(wozData, woz2Header, 8) == 0)
175                 return 2;
176
177         return 0;
178 }
179
180
181 //
182 // Do basic sanity checks on the passed in contents (file loaded elsewhere).
183 // Returns true if successful, false on failure.
184 //
185 bool CheckWOZIntegrity(const uint8_t * wozData, uint32_t wozSize)
186 {
187         WOZ2 & woz = *((WOZ2 *)wozData);
188         uint32_t crc = CRC32(&wozData[12], wozSize - 12);
189         uint32_t wozCRC = Uint32LE(woz.crc32);
190
191         if ((wozCRC != 0) && (wozCRC != crc))
192         {
193                 WriteLog("FILEIO: Corrupted data found in WOZ. CRC32: %08X, computed: %08X\n", wozCRC, crc);
194                 return false;
195         }
196         else if (wozCRC == 0)
197                 WriteLog("FILEIO: Warning--WOZ file has no CRC...\n");
198
199 #if 0 // Need to fix this so it works with both 1 & 2 (works with only 1 ATM)
200         WriteLog("Track map:\n");
201         WriteLog("                                        1   1   1   1   1   1   1   1\n");
202         WriteLog("0.,.1.,.2.,.3.,.4.,.5.,.6.,.7.,.8.,.9.,.0.,.1.,.2.,.3.,.4.,.5.,.6.,.7.,.\n");
203         WriteLog("------------------------------------------------------------------------\n");
204
205         for(uint8_t j=0; j<2; j++)
206         {
207                 for(uint8_t i=0; i<72; i++)
208                 {
209                         char buf[64] = "..";
210                         buf[0] = buf[1] = '.';
211
212                         if (woz.tmap[i] != 0xFF)
213                                 sprintf(buf, "%02d", woz.tmap[i]);
214
215                         WriteLog("%c", buf[j]);
216                 }
217
218                 WriteLog("\n");
219         }
220
221         WriteLog("\n1   1   2   2   2   2   2   2   2   2   2   2   3   3   3   3   3   3\n");
222         WriteLog("8.,.9.,.0.,.1.,.2.,.3.,.4.,.5.,.6.,.7.,.8.,.9.,.0.,.1.,.2.,.3.,.4.,.5\n");
223         WriteLog("---------------------------------------------------------------------\n");
224
225         for(uint8_t j=0; j<2; j++)
226         {
227                 for(uint8_t i=72; i<141; i++)
228                 {
229                         char buf[64] = "..";
230
231                         if (woz.tmap[i] != 0xFF)
232                                 sprintf(buf, "%02d", woz.tmap[i]);
233
234                         WriteLog("%c", buf[j]);
235                 }
236
237                 WriteLog("\n");
238         }
239
240         WriteLog("\n");
241
242         uint8_t numTracks = woz.trksSize / sizeof(WOZ1Track);
243
244         // N.B.: Need to check the track in tmap[] to have this tell the correct track...  Right now, it doesn't
245         for(uint8_t i=0; i<numTracks; i++)
246         {
247                 WriteLog("WOZ: Stream %u: %d bits (packed into %d bytes)\n", i, woz.track[i].bitCount, (woz.track[i].bitCount + 7) / 8);
248         }
249 #endif
250
251         WriteLog("FILEIO: Well formed WOZ file found\n");
252         return true;
253 }
254
255
256 bool SaveWOZ(const char * filename, WOZ2 * woz, uint32_t size)
257 {
258         // Set up CRC32 before writing
259         woz->crc32 = Uint32LE(CRC32(woz->infoTag, size - 12));
260
261         // META header (skip for now) (actually, should be in the disk[] image already)
262
263         // Finally, write the damn image
264         FILE * file = fopen(filename, "wb");
265
266         if (file == NULL)
267         {
268                 WriteLog("FILEIO: Failed to open image file '%s' for writing...\n", filename);
269                 return false;
270         }
271
272         fwrite((uint8_t *)woz, 1, size, file);
273         fclose(file);
274
275         WriteLog("FILEIO: Successfully wrote image file '%s'...\n", filename);
276
277         return true;
278 }
279