289 lines
7.3 KiB
C++
289 lines
7.3 KiB
C++
//
|
|
// fileio.cpp: File handling (mainly disk related)
|
|
//
|
|
// by James Hammons
|
|
// (C) 2019 Underground Software
|
|
//
|
|
|
|
#include "fileio.h"
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include "crc32.h"
|
|
#include "log.h"
|
|
|
|
|
|
uint8_t woz1Header[8] = { 'W', 'O', 'Z', '1', 0xFF, 0x0A, 0x0D, 0x0A };
|
|
uint8_t woz2Header[8] = { 'W', 'O', 'Z', '2', 0xFF, 0x0A, 0x0D, 0x0A };
|
|
uint8_t standardTMAP[160] = {
|
|
0, 0, 0xFF, 1, 1, 1, 0xFF, 2, 2, 2, 0xFF, 3, 3, 3, 0xFF, 4, 4, 4, 0xFF,
|
|
5, 5, 5, 0xFF, 6, 6, 6, 0xFF, 7, 7, 7, 0xFF, 8, 8, 8, 0xFF, 9, 9, 9, 0xFF,
|
|
10, 10, 10, 0xFF, 11, 11, 11, 0xFF, 12, 12, 12, 0xFF, 13, 13, 13, 0xFF,
|
|
14, 14, 14, 0xFF, 15, 15, 15, 0xFF, 16, 16, 16, 0xFF, 17, 17, 17, 0xFF,
|
|
18, 18, 18, 0xFF, 19, 19, 19, 0xFF, 20, 20, 20, 0xFF, 21, 21, 21, 0xFF,
|
|
22, 22, 22, 0xFF, 23, 23, 23, 0xFF, 24, 24, 24, 0xFF, 25, 25, 25, 0xFF,
|
|
26, 26, 26, 0xFF, 27, 27, 27, 0xFF, 28, 28, 28, 0xFF, 29, 29, 29, 0xFF,
|
|
30, 30, 30, 0xFF, 31, 31, 31, 0xFF, 32, 32, 32, 0xFF, 33, 33, 33, 0xFF,
|
|
34, 34, 34, 0xFF, 0xFF, 0xFF,
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
|
|
};
|
|
|
|
|
|
//
|
|
// sizePtr is optional
|
|
//
|
|
uint8_t * ReadFile(const char * filename, uint32_t * sizePtr/*= NULL*/, uint32_t skip/*= 0*/)
|
|
{
|
|
FILE * fp = fopen(filename, "rb");
|
|
|
|
if (!fp)
|
|
return NULL;
|
|
|
|
fseek(fp, 0, SEEK_END);
|
|
uint32_t size = ftell(fp);
|
|
fseek(fp, 0, SEEK_SET);
|
|
|
|
if (skip > 0)
|
|
{
|
|
fseek(fp, skip, SEEK_CUR);
|
|
size -= skip;
|
|
}
|
|
|
|
uint8_t * buffer = (uint8_t *)malloc(size);
|
|
fread(buffer, 1, size, fp);
|
|
fclose(fp);
|
|
|
|
if (sizePtr != NULL)
|
|
*sizePtr = size;
|
|
|
|
return buffer;
|
|
}
|
|
|
|
|
|
//
|
|
// This initializes the WOZ type 2 headers
|
|
//
|
|
void InitWOZ2Headers(WOZ2 & woz)
|
|
{
|
|
// Set up header (leave CRC as 0 for now)
|
|
memcpy(woz.magic, woz2Header, 8);
|
|
woz.crc32 = 0;
|
|
|
|
// INFO header
|
|
memcpy(woz.infoTag, "INFO", 4);
|
|
woz.infoSize = Uint32LE(60);
|
|
woz.infoVersion = 2;
|
|
woz.diskType = 1;
|
|
woz.writeProtected = 0;
|
|
woz.synchronized = 0;
|
|
woz.cleaned = 1;
|
|
memset(woz.creator, ' ', 32);
|
|
memcpy(woz.creator, "Apple2 emulator v1.0.0", 22);
|
|
woz.diskSides = 1;
|
|
woz.bootSectorFmt = 1;
|
|
woz.optimalBitTmg = 32;
|
|
woz.largestTrack = Uint16LE(13);
|
|
|
|
// TMAP header
|
|
memcpy(woz.tmapTag, "TMAP", 4);
|
|
woz.tmapSize = Uint32LE(160);
|
|
|
|
// TRKS header
|
|
memcpy(woz.trksTag, "TRKS", 4);
|
|
}
|
|
|
|
|
|
//
|
|
// This is used mainly to initialize blank disks and upconvert non-WOZ disks
|
|
//
|
|
uint8_t * InitWOZ(uint32_t * pSize/*= NULL*/)
|
|
{
|
|
uint32_t size = 1536 + (35 * (13 * 512));
|
|
uint8_t * data = (uint8_t *)malloc(size);
|
|
WOZ2 & woz = *((WOZ2 *)data);
|
|
|
|
// Zero out WOZ image in memory
|
|
memset(&woz, 0, size);
|
|
|
|
// Set up headers
|
|
InitWOZ2Headers(woz);
|
|
memcpy(woz.tmap, standardTMAP, 160);
|
|
woz.trksSize = Uint32LE(35 * (13 * 512));
|
|
|
|
for(int i=0; i<35; i++)
|
|
{
|
|
woz.track[i].startingBlock = Uint16LE(3 + (i * 13));
|
|
woz.track[i].blockCount = Uint16LE(13);
|
|
woz.track[i].bitCount = Uint32LE(51200);
|
|
}
|
|
|
|
// META header (how to handle? prolly with a separate pointer)
|
|
|
|
if (pSize)
|
|
*pSize = size;
|
|
|
|
return data;
|
|
}
|
|
|
|
|
|
uint8_t * UpconvertWOZ1ToWOZ2(uint8_t * woz1Data, uint32_t woz1Size, uint32_t * newSize)
|
|
{
|
|
WOZ1 & woz1 = *((WOZ1 *)woz1Data);
|
|
|
|
// First, figure out how large the new structure will be in comparison to
|
|
// the old one...
|
|
uint32_t numTracks = woz1.trksSize / sizeof(WOZ1Track);
|
|
uint32_t metadataSize = woz1Size - (Uint32LE(woz1.trksSize) + 256);
|
|
|
|
// N.B.: # of blocks for each track will *always* be <= 13 for WOZ1
|
|
*newSize = 0x600 + (numTracks * (13 * 512)) + metadataSize;
|
|
uint8_t * woz2Data = (uint8_t *)malloc(*newSize);
|
|
memset(woz2Data, 0, *newSize);
|
|
|
|
WOZ2 & woz2 = *((WOZ2 *)woz2Data);
|
|
InitWOZ2Headers(woz2);
|
|
|
|
// Copy parts of INFO & TMAP chunks over
|
|
memcpy(&woz2.diskType, &woz1.diskType, 36);
|
|
memcpy(woz2.tmap, woz1.tmap, 160);
|
|
//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)
|
|
woz2.crc32 = 0;
|
|
woz2.trksSize = Uint32LE(numTracks * (13 * 512));
|
|
|
|
// Finally, copy over the tracks
|
|
for(uint32_t i=0; i<numTracks; i++)
|
|
{
|
|
woz2.track[i].startingBlock = Uint16LE(3 + (i * 13));
|
|
woz2.track[i].blockCount = Uint16LE(13);
|
|
woz2.track[i].bitCount = woz1.track[i].bitCount;
|
|
memcpy(woz2Data + ((3 + (i * 13)) * 512), woz1.track[i].bits, 6646);
|
|
}
|
|
|
|
// Finally, copy over the metadata
|
|
memcpy(woz2Data + Uint32LE(woz2.trksSize) + 0x600,
|
|
woz1Data + Uint32LE(woz1.trksSize) + 0x100, metadataSize);
|
|
|
|
return woz2Data;
|
|
}
|
|
|
|
|
|
//
|
|
// Check WOZ type on the passed in contents (file loaded elsewhere).
|
|
// Returns type of WOZ if successful, 0 if not.
|
|
//
|
|
uint8_t CheckWOZType(const uint8_t * wozData, uint32_t wozSize)
|
|
{
|
|
// Basic sanity checking
|
|
if ((wozData == NULL) || (wozSize < 8))
|
|
return 0;
|
|
|
|
if (memcmp(wozData, woz1Header, 8) == 0)
|
|
return 1;
|
|
else if (memcmp(wozData, woz2Header, 8) == 0)
|
|
return 2;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
//
|
|
// Do basic sanity checks on the passed in contents (file loaded elsewhere).
|
|
// Returns true if successful, false on failure.
|
|
//
|
|
bool CheckWOZIntegrity(const uint8_t * wozData, uint32_t wozSize)
|
|
{
|
|
WOZ2 & woz = *((WOZ2 *)wozData);
|
|
uint32_t crc = CRC32(&wozData[12], wozSize - 12);
|
|
uint32_t wozCRC = Uint32LE(woz.crc32);
|
|
|
|
if ((wozCRC != 0) && (wozCRC != crc))
|
|
{
|
|
WriteLog("FILEIO: Corrupted data found in WOZ. CRC32: %08X, computed: %08X\n", wozCRC, crc);
|
|
return false;
|
|
}
|
|
else if (wozCRC == 0)
|
|
WriteLog("FILEIO: Warning--WOZ file has no CRC...\n");
|
|
|
|
#if 0 // Need to fix this so it works with both 1 & 2 (works with only 1 ATM)
|
|
WriteLog("Track map:\n");
|
|
WriteLog(" 1 1 1 1 1 1 1 1\n");
|
|
WriteLog("0.,.1.,.2.,.3.,.4.,.5.,.6.,.7.,.8.,.9.,.0.,.1.,.2.,.3.,.4.,.5.,.6.,.7.,.\n");
|
|
WriteLog("------------------------------------------------------------------------\n");
|
|
|
|
for(uint8_t j=0; j<2; j++)
|
|
{
|
|
for(uint8_t i=0; i<72; i++)
|
|
{
|
|
char buf[64] = "..";
|
|
buf[0] = buf[1] = '.';
|
|
|
|
if (woz.tmap[i] != 0xFF)
|
|
sprintf(buf, "%02d", woz.tmap[i]);
|
|
|
|
WriteLog("%c", buf[j]);
|
|
}
|
|
|
|
WriteLog("\n");
|
|
}
|
|
|
|
WriteLog("\n1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3\n");
|
|
WriteLog("8.,.9.,.0.,.1.,.2.,.3.,.4.,.5.,.6.,.7.,.8.,.9.,.0.,.1.,.2.,.3.,.4.,.5\n");
|
|
WriteLog("---------------------------------------------------------------------\n");
|
|
|
|
for(uint8_t j=0; j<2; j++)
|
|
{
|
|
for(uint8_t i=72; i<141; i++)
|
|
{
|
|
char buf[64] = "..";
|
|
|
|
if (woz.tmap[i] != 0xFF)
|
|
sprintf(buf, "%02d", woz.tmap[i]);
|
|
|
|
WriteLog("%c", buf[j]);
|
|
}
|
|
|
|
WriteLog("\n");
|
|
}
|
|
|
|
WriteLog("\n");
|
|
|
|
uint8_t numTracks = woz.trksSize / sizeof(WOZ1Track);
|
|
|
|
// N.B.: Need to check the track in tmap[] to have this tell the correct track... Right now, it doesn't
|
|
for(uint8_t i=0; i<numTracks; i++)
|
|
{
|
|
WriteLog("WOZ: Stream %u: %d bits (packed into %d bytes)\n", i, woz.track[i].bitCount, (woz.track[i].bitCount + 7) / 8);
|
|
}
|
|
#endif
|
|
|
|
WriteLog("FILEIO: Well formed WOZ file found\n");
|
|
return true;
|
|
}
|
|
|
|
|
|
bool SaveWOZ(const char * filename, WOZ2 * woz, uint32_t size)
|
|
{
|
|
// Set up CRC32 before writing
|
|
woz->crc32 = Uint32LE(CRC32(woz->infoTag, size - 12));
|
|
|
|
// META header (skip for now) (actually, should be in the disk[] image already)
|
|
|
|
// Finally, write the damn image
|
|
FILE * file = fopen(filename, "wb");
|
|
|
|
if (file == NULL)
|
|
{
|
|
WriteLog("FILEIO: Failed to open image file '%s' for writing...\n", filename);
|
|
return false;
|
|
}
|
|
|
|
fwrite((uint8_t *)woz, 1, size, file);
|
|
fclose(file);
|
|
|
|
WriteLog("FILEIO: Successfully wrote image file '%s'...\n", filename);
|
|
|
|
return true;
|
|
}
|
|
|