]> Shamusworld >> Repos - wozmaker/blobdiff - src/fileio.cpp
Move saving code to fileio, add WOZ2 support, misc. DSP tweaks.
[wozmaker] / src / fileio.cpp
index a70b4ca6ef8ede21b2737484534f3246b69b88d1..c3718c367bc886149dc01aea3510885c54c993cb 100644 (file)
@@ -10,6 +10,8 @@
 #include "fileio.h"
 #include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
+#include "global.h"
 
 
 static uint32_t crcTable[256] =
@@ -78,3 +80,212 @@ uint8_t * ReadFile(const char * filename, uint32_t * size)
        return buffer;
 }
 
+
+bool LoadA2R(const char * filename)
+{
+/*
+Really, this crap should go into fileio.cpp.  !!! FIX !!!
+*/
+       static uint8_t a2rHdr[8] = { 0x41, 0x32, 0x52, 0x32, 0xFF, 0x0A, 0x0D, 0x0A };
+       static uint8_t a2rHdr1[8] = { 0x41, 0x32, 0x52, 0x31, 0xFF, 0x0A, 0x0D, 0x0A };
+
+       if (Global::a2r != NULL)
+               free(Global::a2r);
+
+       Global::a2r = (A2R *)ReadFile(filename, &Global::a2rSize);
+
+       if (Global::a2r == NULL)
+               return false;
+
+       // Sanity check, to see if what we asked for is what we got
+       if (memcmp(Global::a2r->magic1, a2rHdr, 8) != 0)
+       {
+               // It's not a v2 A2R file, maybe it's v1?
+               if (memcmp(Global::a2r->magic1, a2rHdr1, 8) == 0)
+               {
+                       // Bytes 8-F are usually: 01 00 8D 00 A5 01 00 00
+                       // First, allocate mem to copy the old version to the new:
+                       uint8_t * oldfile = (uint8_t *)Global::a2r;
+                       uint8_t * newfile = (uint8_t *)malloc(Global::a2rSize + 36);
+                       memcpy(newfile + 52, oldfile + 16, Global::a2rSize - 16);
+
+                       // Make sure creator is set correctly (v1 doesn't have it)
+                       memset(Global::a2r->creator, 0x20, 32);
+
+                       // Swap in the new file, free the old one
+                       free(Global::a2r);
+                       Global::a2r = (A2R *)newfile;
+                       Global::a2rSize += 36;  // Add in the size of the INFO chunk
+
+                       // Fix up stuff that's different between v1 and v2
+//printf("A2R Size: %08X\n", Global::a2rSize);
+//printf("A2R Stream Size: %08X (preswap)\n", Global::a2r->strmSize);
+                       SwapBytes32((uint8_t *)&Global::a2r->strmSize);
+//printf("A2R Stream Size: %08X (postswap)\n", Global::a2r->strmSize);
+                       uint32_t dataSize = Uint32LE(Global::a2r->strmSize);
+                       uint32_t pos = 0;
+
+                       while (pos < dataSize)
+                       {
+                               A2RStream * stream = (A2RStream *)(&Global::a2r->data[pos]);
+
+                               if (stream->location == 0xFF)
+                                       break;
+
+                               SwapBytes32(stream->dataLength);
+                               SwapBytes32(stream->estLoopPoint);
+                               pos += 10 + Uint32LE(stream->dataLength);
+                       }
+
+                       // Change INFO to META & fix size (if any, dunno if it's optional)
+                       if (Global::a2rSize > (60 + dataSize))
+                       {
+                               memcpy(&Global::a2r->data[dataSize], "META", 4);
+                               SwapBytes32(&Global::a2r->data[dataSize + 4]);
+                       }
+               }
+               else
+               {
+                       free(Global::a2r);
+                       Global::a2r = NULL;
+
+//                     QMessageBox::critical(this, "Bad A2R file", "It may have an .a2r extension, but it isn't a valid A2R file.");
+
+                       return false;
+               }
+       }
+
+       // Setup individual stream pointers
+       Global::numStreams = 0;
+       uint8_t * streamPtr = Global::a2r->data;
+
+       while ((*streamPtr != 0xFF) && (Global::numStreams < 800))
+       {
+               Global::stream[Global::numStreams] = (A2RStream *)streamPtr;
+               streamPtr += 10 + Uint32LE(Global::stream[Global::numStreams]->dataLength);
+               Global::numStreams++;
+       }
+
+       // Metadata check
+       Global::metadata = NULL;
+
+       if (Global::a2rSize > (60 + Uint32LE(Global::a2r->strmSize)))
+       {
+               Global::metadata = (A2RMetadata *)((uint8_t *)Global::a2r + (60 + Uint32LE(Global::a2r->strmSize)));
+
+               // Make sure it's plausible metadata
+               if (memcmp(Global::metadata->metaTag, "META", 4) != 0)
+                       Global::metadata = NULL;
+       }
+
+       // Unpack TMNG & XTMG streams to simplify analysis
+       for(uint32_t i=0; i<Global::numStreams; i++)
+       {
+               Global::waveLen[i] = 0;
+
+               // Don't bother with BITS captures
+               if (Global::stream[i]->captureType == 2)
+                       continue;
+
+               // We skip the first timing byte because it can't tell you what the actual time was when the pulse was seen--it's the time between when the *capture* started and the pulse was seen, not the time between the previous pulse and this one!  So that first one is discarded since it's worse than useless; it's misleading.
+               for(uint32_t j=1; j<Uint32LE(Global::stream[i]->dataLength); j++)
+               {
+                       uint32_t a = Global::stream[i]->data[j];
+
+                       while ((Global::stream[i]->data[j] == 0xFF) || (a < 24))
+                       {
+                               j++;
+                               a += Global::stream[i]->data[j];
+                       }
+
+                       Global::wave[i][Global::waveLen[i]] = a;
+                       Global::waveLen[i]++;
+               }
+       }
+
+//ISO-8061 date format
+#if 0
+       char buf[200];
+       time_t t = time(NULL);
+       tm * tmp = gmtime(&t);
+       strftime(buf, sizeof(buf), "%FT%TZ", tmp);
+       printf("Time is: %s\n", buf);
+#endif
+
+       return true;
+}
+
+
+bool WriteWOZFile(const char * filename)
+{
+       // See if we can actually write a file; if not, there's no need to check
+       // anything else
+       FILE * file = fopen(filename, "wb");
+
+       if (!file)
+               return false;
+
+       // Need to come up with proper numbers here...
+       uint32_t numTrackBlocks = 0;
+
+       for(uint32_t i=0; i<141; i++)
+               numTrackBlocks += (Global::bStreamLen[i] + 511) / 512;
+
+       uint32_t wozSize = sizeof(WOZ2) + (numTrackBlocks * 512) + (Global::metadata != NULL ? Global::metadata->metaSize + 8 : 0);
+
+       WOZ2 * woz = (WOZ2 *)malloc(wozSize);
+
+       memcpy(woz->magic1, "WOZ2\xFF\x0A\x0D\x0A", 8);
+
+       memcpy(woz->infoTag, "INFO", 4);
+       woz->infoSize = Uint32LE(60);
+       woz->infoVersion = 1;
+       woz->diskType = 1;
+       woz->writeProtected = 1;
+       woz->synchronized = 1;
+       woz->cleaned = 1;
+       memcpy(woz->creator, "WOZ Maker v1.0.0                ", 32);
+       woz->diskSides = 1;
+       woz->bootSectorFmt = 1;
+       woz->optimalBitTmg = 32;
+       woz->compatibleHW = Uint16LE(0);
+       woz->requiredRAM = Uint16LE(0);
+
+       memcpy(woz->tmapTag, "TMAP", 4);
+       woz->tmapSize = Uint32LE(160);
+
+       for(uint32_t i=0; i<141; i++)
+               woz->tmap[i] = (Global::bStreamLen[i] == 0 ? 0xFF : i);
+
+       memcpy(woz->trksTag, "TRKS", 4);
+       woz->trksSize = Uint32LE(1280 + (numTrackBlocks * 512));
+       uint16_t startBlock = 0, largestBlock = 0;
+
+       for(uint32_t i=0; i<141; i++)
+       {
+               uint16_t blockLen = (Global::bStreamLen[i] + 511) / 512;
+               memset(&woz->data[startBlock * 512], 0, blockLen * 512);
+               memcpy(&woz->data[startBlock * 512], Global::bStream[i], Global::bStreamLen[i]);
+               woz->track[i].startingBlock = Uint16LE(startBlock + 3);
+               woz->track[i].blockCount = Uint16LE(blockLen);
+               woz->track[i].bitCount = Uint16LE(Global::bStreamLenBits[i]);
+               startBlock += blockLen;
+
+               if (blockCount > largestBlock)
+                       largestBlock = blockCount;
+       }
+
+       woz->largestTrack = Uint16LE(largestBlock);
+
+       if (Global::metadata != NULL)
+               memcpy(&woz->data[startBlock * 512], Global::metadata, Uint32LE(Global::metadata->metaSize) + 8);
+
+       woz->crc32 = Uint32LE(CRC32(&woz->infoTag[0], wozSize - 12));
+       fwrite(woz, 1, wozSize, file);
+       fclose(file);
+
+       free(woz);
+
+       return true;
+}
+