Annotation of hatari/src/msa.c, revision 1.1

1.1     ! root        1: /*
        !             2:   Hatari
        !             3: 
        !             4:   MSA Disc support
        !             5: */
        !             6: 
        !             7: #include "main.h"
        !             8: #include "file.h"
        !             9: #include "floppy.h"
        !            10: #include "memAlloc.h"
        !            11: #include "misc.h"
        !            12: #include "stMemory.h"
        !            13: 
        !            14: #define SAVE_TO_MSA_IMAGES
        !            15: 
        !            16: /*
        !            17:     .MSA FILE FORMAT
        !            18:   --================------------------------------------------------------------
        !            19: 
        !            20:   For those interested, an MSA file is made up as follows:
        !            21: 
        !            22:   Header:
        !            23: 
        !            24:   Word  ID marker, should be $0E0F
        !            25:   Word  Sectors per track
        !            26:   Word  Sides (0 or 1; add 1 to this to get correct number of sides)
        !            27:   Word  Starting track (0-based)
        !            28:   Word  Ending track (0-based)
        !            29: 
        !            30:   Individual tracks follow the header in alternating side order, e.g. a double
        !            31:   sided disk is stored as:
        !            32: 
        !            33:   TRACK 0, SIDE 0
        !            34:   TRACK 0, SIDE 1
        !            35:   TRACK 1, SIDE 0
        !            36:   TRACK 1, SIDE 1
        !            37:   TRACK 2, SIDE 0
        !            38:   TRACK 2, SIDE 1
        !            39: 
        !            40:   ...and so on. Track blocks are made up as follows:
        !            41: 
        !            42:   Word  Data length
        !            43:   Bytes  Data
        !            44: 
        !            45:   If the data length is equal to 512 x the sectors per track value, it is an
        !            46:   uncompressed track and you can merely copy the data to the appropriate track
        !            47:   of the disk. However, if the data length value is less than 512 x the sectors
        !            48:   per track value it is a compressed track.
        !            49: 
        !            50:   Compressed tracks use simple a Run Length Encoding (RLE) compression method.
        !            51:   You can directly copy any data bytes until you find an $E5 byte. This signals
        !            52:   a compressed run, and is made up as follows:
        !            53: 
        !            54:   Byte  Marker - $E5
        !            55:   Byte  Data byte
        !            56:   Word  Run length
        !            57: 
        !            58:   So, if MSA found six $AA bytes in a row it would encode it as:
        !            59: 
        !            60:   $E5AA0006
        !            61: 
        !            62:   What happens if there's an actual $E5 byte on the disk? Well, logically
        !            63:   enough, it is encoded as:
        !            64: 
        !            65:   $E5E50001
        !            66: 
        !            67:   This is obviously bad news if a disk consists of lots of data like
        !            68:   $E500E500E500E500... but if MSA makes a track bigger when attempting to
        !            69:   compress it, it just stores the uncompressed version instead.
        !            70: 
        !            71:   MSA only compresses runs of at least 4 identical bytes (after all, it would be
        !            72:   wasteful to store 4 bytes for a run of only 3 identical bytes!). There is one
        !            73:   exception to this rule: if a run of 2 or 3 $E5 bytes is found, that is stored
        !            74:   appropriately enough as a run. Again, it would be wasteful to store 4 bytes
        !            75:   for every single $E5 byte.
        !            76: 
        !            77:   The hacked release of MSA that enables the user to turn off compression
        !            78:   completely simply stops MSA from trying this compression and produces MSA
        !            79:   images that are completely uncompressed. This is okay because it is possible
        !            80:   for MSA to produce such an image anyway, and such images are therefore 100%
        !            81:   compatible with normal MSA versions (and MSA-to-ST of course).
        !            82: */
        !            83: 
        !            84: typedef struct {
        !            85:   short int ID;                 /* Word  ID marker, should be $0E0F */
        !            86:   short int SectorsPerTrack;    /* Word  Sectors per track */
        !            87:   short int Sides;              /* Word  Sides (0 or 1; add 1 to this to get correct number of sides) */
        !            88:   short int StartingTrack;      /* Word  Starting track (0-based) */
        !            89:   short int EndingTrack;        /* Word  Ending track (0-based) */
        !            90: } MSAHEADERSTRUCT;
        !            91: 
        !            92: #define MSA_WORKSPACE_SIZE  (1024*1024)  /* Size of workspace to use when saving MSA files */
        !            93: 
        !            94: 
        !            95: //-----------------------------------------------------------------------
        !            96: /*
        !            97:   Uncompress .MSA data into buffer
        !            98: */
        !            99: int MSA_UnCompress(unsigned char *pMSAFile,unsigned char *pBuffer)
        !           100: {
        !           101:   MSAHEADERSTRUCT *pMSAHeader;
        !           102:   unsigned char *pMSAImageBuffer,*pImageBuffer;
        !           103:   unsigned char Byte,Data;
        !           104:   int ImageSize = 0;
        !           105:   int i,Track,Side,DataLength,NumBytesUnCompressed,RunLength;
        !           106: 
        !           107:   // Is an '.msa' file?? Check header
        !           108:   pMSAHeader = (MSAHEADERSTRUCT *)pMSAFile;
        !           109:   if (pMSAHeader->ID==STMemory_Swap68000Int(0x0E0F)) {
        !           110:     // First swap 'header' words around to PC format - easier later on
        !           111:     pMSAHeader->SectorsPerTrack = STMemory_Swap68000Int(pMSAHeader->SectorsPerTrack);
        !           112:     pMSAHeader->Sides = STMemory_Swap68000Int(pMSAHeader->Sides);
        !           113:     pMSAHeader->StartingTrack = STMemory_Swap68000Int(pMSAHeader->StartingTrack);
        !           114:     pMSAHeader->EndingTrack = STMemory_Swap68000Int(pMSAHeader->EndingTrack);
        !           115: 
        !           116:     // Set pointers
        !           117:     pImageBuffer = (unsigned char *)pBuffer;
        !           118:     pMSAImageBuffer = (unsigned char *)((unsigned long)pMSAFile+sizeof(MSAHEADERSTRUCT));
        !           119: 
        !           120:     // Uncompress to memory as '.ST' disc image - NOTE assumes 512 bytes per sector(use NUMBYTESPERSECTOR define)!!!
        !           121:     for(Track=pMSAHeader->StartingTrack; Track<(pMSAHeader->EndingTrack+1); Track++) {
        !           122:       for(Side=0; Side<(pMSAHeader->Sides+1); Side++) {
        !           123:         // Uncompress MSA Track, first check if is not compressed
        !           124:         DataLength = STMemory_Swap68000Int(*(short int *)pMSAImageBuffer);
        !           125:         pMSAImageBuffer += sizeof(short int);
        !           126:         if (DataLength==(NUMBYTESPERSECTOR*pMSAHeader->SectorsPerTrack)) {
        !           127:           // No compression on track, simply copy and continue
        !           128:           memcpy(pImageBuffer,pMSAImageBuffer,NUMBYTESPERSECTOR*pMSAHeader->SectorsPerTrack);
        !           129:           pImageBuffer += NUMBYTESPERSECTOR*pMSAHeader->SectorsPerTrack;
        !           130:           pMSAImageBuffer += DataLength;
        !           131:         }
        !           132:         else {
        !           133:           // Uncompress track
        !           134:           NumBytesUnCompressed = 0;
        !           135:           while(NumBytesUnCompressed<(NUMBYTESPERSECTOR*pMSAHeader->SectorsPerTrack)) {
        !           136:             Byte = *pMSAImageBuffer++;
        !           137:             if (Byte!=0xE5) {                           // Compressed header??
        !           138:               *pImageBuffer++ = Byte;                   // No, just copy byte
        !           139:               NumBytesUnCompressed++;
        !           140:             }
        !           141:             else {
        !           142:               Data = *pMSAImageBuffer++;                // Byte to copy
        !           143:               RunLength = STMemory_Swap68000Int(*(short int *)pMSAImageBuffer);  // For length
        !           144:               // Limit length to size of track, incorrect images may overflow
        !           145:               if ( (RunLength+NumBytesUnCompressed)>(NUMBYTESPERSECTOR*pMSAHeader->SectorsPerTrack) )
        !           146:                 RunLength = (NUMBYTESPERSECTOR*pMSAHeader->SectorsPerTrack)-NumBytesUnCompressed;
        !           147:               pMSAImageBuffer += sizeof(short int);
        !           148:               for(i=0; i<RunLength; i++)
        !           149:                 *pImageBuffer++ = Data;                 // Copy byte
        !           150:               NumBytesUnCompressed += RunLength;
        !           151:             }
        !           152:           }
        !           153:         }          
        !           154:       }
        !           155:     }
        !           156: 
        !           157:     // Set size of loaded image
        !           158:     ImageSize = (unsigned long)pImageBuffer-(unsigned long)pBuffer;
        !           159:   }
        !           160: 
        !           161:   // Return number of bytes loaded, '0' if failed
        !           162:   return(ImageSize);
        !           163: }
        !           164: 
        !           165: //-----------------------------------------------------------------------
        !           166: /*
        !           167:   Uncompress .MSA file into memory, return number of bytes loaded
        !           168: */
        !           169: int MSA_ReadDisc(char *pszFileName,unsigned char *pBuffer)
        !           170: {
        !           171:   unsigned char *pMSAFile;
        !           172:   int ImageSize = 0;
        !           173: 
        !           174:   // Read in file
        !           175:   pMSAFile = (unsigned char *)File_Read(pszFileName,NULL,NULL,NULL);
        !           176:   if (pMSAFile) {
        !           177:     // Uncompress into disc buffer
        !           178:     ImageSize = MSA_UnCompress(pMSAFile,pBuffer);
        !           179: 
        !           180:     // Free MSA file we loaded
        !           181:     Memory_Free(pMSAFile);
        !           182:   }
        !           183: 
        !           184:   // Return number of bytes loaded, '0' if failed
        !           185:   return(ImageSize);
        !           186: }
        !           187: 
        !           188: //-----------------------------------------------------------------------
        !           189: /*
        !           190:   Return number of bytes of the same byte in the passed buffer
        !           191:   If we return '0' this means no run(or end of buffer)
        !           192: */
        !           193: int MSA_FindRunOfBytes(unsigned char *pBuffer,int nBytesInBuffer)
        !           194: {
        !           195:   unsigned char ScannedByte;
        !           196:   int nTotalRun;
        !           197:   int i;
        !           198: 
        !           199:   // Do we enough for a run?
        !           200:   if (nBytesInBuffer<2)
        !           201:     return(0);
        !           202: 
        !           203:   // OK, scan for run
        !           204:   nTotalRun = 1;
        !           205:   ScannedByte = *pBuffer++;
        !           206:   // Is this the marker? If so, this is a run of one
        !           207:   if (ScannedByte!=0xE5) {
        !           208:     for(i=1; i<nBytesInBuffer; i++) {
        !           209:       if (*pBuffer++==ScannedByte)
        !           210:         nTotalRun++;
        !           211:       else
        !           212:         break;
        !           213:     }
        !           214:     // Was this enough of a run to make a difference?
        !           215:     if (nTotalRun<4)
        !           216:       nTotalRun = 0;    // Just store a bytes
        !           217:   }
        !           218: 
        !           219:   return(nTotalRun);
        !           220: }
        !           221: 
        !           222: //-----------------------------------------------------------------------
        !           223: /*
        !           224:   Save compressed .MSA file from memory buffer. Returns TRUE is all OK
        !           225: */
        !           226: BOOL MSA_WriteDisc(char *pszFileName,unsigned char *pBuffer,int ImageSize)
        !           227: {
        !           228: #ifdef SAVE_TO_MSA_IMAGES
        !           229: 
        !           230:   MSAHEADERSTRUCT *pMSAHeader;
        !           231:   unsigned short int *pMSADataLength;
        !           232:   unsigned char *pMSAImageBuffer, *pMSABuffer, *pImageBuffer;
        !           233:   unsigned short int nSectorsPerTrack, nSides, nCompressedBytes, nBytesPerTrack;
        !           234:   BOOL nRet;
        !           235:   int nTracks,nBytesToGo,nBytesRun;
        !           236:   int Track,Side;
        !           237: 
        !           238:   // Allocate workspace for compressed image
        !           239:   pMSAImageBuffer = (unsigned char *)Memory_Alloc(MSA_WORKSPACE_SIZE);
        !           240: 
        !           241:   // Store header
        !           242:   pMSAHeader = (MSAHEADERSTRUCT *)pMSAImageBuffer;
        !           243:   pMSAHeader->ID = STMemory_Swap68000Int(0x0E0F);
        !           244:   Floppy_FindDiscDetails(pBuffer,ImageSize,&nSectorsPerTrack,&nSides);
        !           245:   pMSAHeader->SectorsPerTrack = STMemory_Swap68000Int(nSectorsPerTrack);
        !           246:   pMSAHeader->Sides = STMemory_Swap68000Int(nSides-1);
        !           247:   pMSAHeader->StartingTrack = STMemory_Swap68000Int(0);
        !           248:   nTracks = ((ImageSize / NUMBYTESPERSECTOR) / nSectorsPerTrack) / nSides;
        !           249:   pMSAHeader->EndingTrack = STMemory_Swap68000Int(nTracks-1);
        !           250: 
        !           251:   // Compress image
        !           252:   pMSABuffer = pMSAImageBuffer + sizeof(MSAHEADERSTRUCT);
        !           253:   for(Track=0; Track<nTracks; Track++) {
        !           254:     for(Side=0; Side<nSides; Side++) {
        !           255:       // Get track data pointer
        !           256:       nBytesPerTrack = NUMBYTESPERSECTOR*nSectorsPerTrack;
        !           257:       pImageBuffer = pBuffer + (nBytesPerTrack*Side) + ((nBytesPerTrack*nSides)*Track);
        !           258: 
        !           259:       // Skip data length(fill in later)
        !           260:       pMSADataLength = (unsigned short int *)pMSABuffer;
        !           261:       pMSABuffer += sizeof(short int);
        !           262:       
        !           263:       // Compress track
        !           264:       nBytesToGo = NUMBYTESPERSECTOR * nSectorsPerTrack;
        !           265:       nCompressedBytes = 0;
        !           266:       while(nBytesToGo>0) {
        !           267:         nBytesRun = MSA_FindRunOfBytes(pImageBuffer,nBytesToGo);
        !           268:         if (nBytesRun==0) {
        !           269:           // Just copy byte
        !           270:           *pMSABuffer++ = *pImageBuffer++;
        !           271:           nCompressedBytes++;
        !           272:           nBytesRun = 1;
        !           273:         }
        !           274:         else {
        !           275:           // Store run!
        !           276:           *pMSABuffer++ = 0xE5;               // Marker
        !           277:           *pMSABuffer++ = *pImageBuffer;      // Byte, and follow with 16-bit length
        !           278:           *(short int *)pMSABuffer = STMemory_Swap68000Int(nBytesRun);
        !           279:           pMSABuffer += sizeof(short int);
        !           280:           pImageBuffer += nBytesRun;
        !           281:           nCompressedBytes += 4;
        !           282:         }
        !           283:         nBytesToGo -= nBytesRun;
        !           284:       }
        !           285: 
        !           286:       // Is compressed track smaller than the original?
        !           287:       if (nCompressedBytes<(NUMBYTESPERSECTOR*nSectorsPerTrack)) {
        !           288:         // Yes, store size
        !           289:         *pMSADataLength = STMemory_Swap68000Int(nCompressedBytes);
        !           290:       }
        !           291:       else {
        !           292:         // No, just store uncompressed track
        !           293:         *pMSADataLength++ = STMemory_Swap68000Int(NUMBYTESPERSECTOR*nSectorsPerTrack);
        !           294:         pMSABuffer = (unsigned char *)pMSADataLength;
        !           295:         pImageBuffer = pBuffer + (nBytesPerTrack*Side) + ((nBytesPerTrack*nSides)*Track);
        !           296:         memcpy(pMSABuffer,pImageBuffer,(NUMBYTESPERSECTOR*nSectorsPerTrack));
        !           297:         pMSABuffer += (NUMBYTESPERSECTOR*nSectorsPerTrack);
        !           298:       }
        !           299:     }
        !           300:   }
        !           301: 
        !           302:   // And save to file!
        !           303:   nRet = File_Save(/*hWnd,*/pszFileName,pMSAImageBuffer,pMSABuffer-pMSAImageBuffer,FALSE);
        !           304: 
        !           305:   // Free workspace
        !           306:   Memory_Free(pMSAImageBuffer);
        !           307: 
        !           308:   return(nRet);
        !           309: 
        !           310: #else  //SAVE_TO_MSA_IMAGES
        !           311: 
        !           312:   // Oops, cannot save
        !           313:   return(FALSE);
        !           314: 
        !           315: #endif  //SAVE_TO_MSA_IMAGES
        !           316: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.