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