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