]> Shamusworld >> Repos - apple2/blob - src/fileio.cpp
cc2ef48bc7e88ad4d2fd80b56fbf26b3b4dfb9dd
[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 0 // Need to fix this so it works with both 1 & 2 (works with only 1 ATM)
209         WriteLog("Track map:\n");
210         WriteLog("                                        1   1   1   1   1   1   1   1\n");
211         WriteLog("0.,.1.,.2.,.3.,.4.,.5.,.6.,.7.,.8.,.9.,.0.,.1.,.2.,.3.,.4.,.5.,.6.,.7.,.\n");
212         WriteLog("------------------------------------------------------------------------\n");
213
214         for(uint8_t j=0; j<2; j++)
215         {
216                 for(uint8_t i=0; i<72; i++)
217                 {
218                         char buf[64] = "..";
219                         buf[0] = buf[1] = '.';
220
221                         if (woz.tmap[i] != 0xFF)
222                                 sprintf(buf, "%02d", woz.tmap[i]);
223
224                         WriteLog("%c", buf[j]);
225                 }
226
227                 WriteLog("\n");
228         }
229
230         WriteLog("\n1   1   2   2   2   2   2   2   2   2   2   2   3   3   3   3   3   3\n");
231         WriteLog("8.,.9.,.0.,.1.,.2.,.3.,.4.,.5.,.6.,.7.,.8.,.9.,.0.,.1.,.2.,.3.,.4.,.5\n");
232         WriteLog("---------------------------------------------------------------------\n");
233
234         for(uint8_t j=0; j<2; j++)
235         {
236                 for(uint8_t i=72; i<141; i++)
237                 {
238                         char buf[64] = "..";
239
240                         if (woz.tmap[i] != 0xFF)
241                                 sprintf(buf, "%02d", woz.tmap[i]);
242
243                         WriteLog("%c", buf[j]);
244                 }
245
246                 WriteLog("\n");
247         }
248
249         WriteLog("\n");
250
251         uint8_t numTracks = woz.trksSize / sizeof(WOZ1Track);
252
253         // N.B.: Need to check the track in tmap[] to have this tell the correct track...  Right now, it doesn't
254         for(uint8_t i=0; i<numTracks; i++)
255         {
256                 WriteLog("WOZ: Stream %u: %d bits (packed into %d bytes)\n", i, woz.track[i].bitCount, (woz.track[i].bitCount + 7) / 8);
257         }
258 #endif
259
260         WriteLog("FILEIO: Well formed WOZ file found\n");
261         return true;
262 }
263
264
265 bool SaveWOZ(const char * filename, WOZ2 * woz, uint32_t size)
266 {
267         // Set up CRC32 before writing
268         woz->crc32 = Uint32LE(CRC32(woz->infoTag, size - 12));
269
270         // META header (skip for now) (actually, should be in the disk[] image already)
271
272         // Finally, write the damn image
273         FILE * file = fopen(filename, "wb");
274
275         if (file == NULL)
276         {
277                 WriteLog("FILEIO: Failed to open image file '%s' for writing...\n", filename);
278                 return false;
279         }
280
281         fwrite((uint8_t *)woz, 1, size, file);
282         fclose(file);
283
284         WriteLog("FILEIO: Successfully wrote image file '%s'...\n", filename);
285
286         return true;
287 }
288