/* AppleWin : An Apple //e emulator for Windows Copyright (C) 1994-1996, Michael O'Brien Copyright (C) 1999-2001, Oliver Schmidt Copyright (C) 2002-2005, Tom Charlesworth Copyright (C) 2006-2007, Tom Charlesworth, Michael Pohoreski AppleWin is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. AppleWin is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with AppleWin; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* Description: Disk Image * * Author: Various */ /* Adaptation for SDL and POSIX (l) by beom beotiger, Nov-Dec 2007 */ #include "stdafx.h" #include "wwrapper.h" //#pragma hdrstop /* DO logical order 0 1 2 3 4 5 6 7 8 9 A B C D E F */ /* physical order 0 D B 9 7 5 3 1 E C A 8 6 4 2 F */ /* PO logical order 0 E D C B A 9 8 7 6 5 4 3 2 1 F */ /* physical order 0 2 4 6 8 A C E 1 3 5 7 9 B D F */ typedef struct _imageinforec { TCHAR filename[MAX_PATH]; DWORD format; HANDLE file; DWORD offset; BOOL writeprotected; DWORD headersize; LPBYTE header; BOOL validtrack[TRACKS]; } imageinforec, *imageinfoptr; typedef BOOL (*boottype )(imageinfoptr); typedef DWORD (*detecttype)(LPBYTE,DWORD); typedef void (*readtype )(imageinfoptr,int,int,LPBYTE,int *); typedef void (*writetype )(imageinfoptr,int,int,LPBYTE,int); BOOL AplBoot (imageinfoptr ptr); DWORD AplDetect (LPBYTE imageptr, DWORD imagesize); DWORD DoDetect (LPBYTE imageptr, DWORD imagesize); void DoRead (imageinfoptr ptr, int track, int quartertrack, LPBYTE trackimagebuffer, int *nibbles); void DoWrite (imageinfoptr ptr, int track, int quartertrack, LPBYTE trackimage, int nibbles); DWORD IieDetect (LPBYTE imageptr, DWORD imagesize); void IieRead (imageinfoptr ptr, int track, int quartertrack, LPBYTE trackimagebuffer, int *nibbles); void IieWrite (imageinfoptr ptr, int track, int quartertrack, LPBYTE trackimage, int nibbles); DWORD Nib1Detect (LPBYTE imageptr, DWORD imagesize); void Nib1Read (imageinfoptr ptr, int track, int quartertrack, LPBYTE trackimagebuffer, int *nibbles); void Nib1Write (imageinfoptr ptr, int track, int quartertrack, LPBYTE trackimage, int nibbles); DWORD Nib2Detect (LPBYTE imageptr, DWORD imagesize); void Nib2Read (imageinfoptr ptr, int track, int quartertrack, LPBYTE trackimagebuffer, int *nibbles); void Nib2Write (imageinfoptr ptr, int track, int quartertrack, LPBYTE trackimage, int nibbles); DWORD PoDetect (LPBYTE imageptr, DWORD imagesize); void PoRead (imageinfoptr ptr, int track, int quartertrack, LPBYTE trackimagebuffer, int *nibbles); void PoWrite (imageinfoptr ptr, int track, int quartertrack, LPBYTE trackimage, int nibbles); BOOL PrgBoot (imageinfoptr ptr); DWORD PrgDetect (LPBYTE imageptr, DWORD imagesize); typedef struct _imagetyperec { LPCTSTR createexts; LPCTSTR rejectexts; detecttype detect; boottype boot; readtype read; writetype write; } imagetyperec, *imagetypeptr; static imagetyperec imagetype[IMAGETYPES] = {{TEXT(".prg"), TEXT(".do;.dsk;.iie;.nib;.po"), PrgDetect, PrgBoot, NULL, NULL}, {TEXT(".do;.dsk"), TEXT(".nib;.iie;.po;.prg"), DoDetect, NULL, DoRead, DoWrite}, {TEXT(".po"), TEXT(".do;.iie;.nib;.prg"), PoDetect, NULL, PoRead, PoWrite}, {TEXT(".apl"), TEXT(".do;.dsk;.iie;.nib;.po"), AplDetect, AplBoot, NULL, NULL}, {TEXT(".nib"), TEXT(".do;.iie;.po;.prg"), Nib1Detect, NULL, Nib1Read, Nib1Write}, {TEXT(".nb2"), TEXT(".do;.iie;.po;.prg"), Nib2Detect, NULL, Nib2Read, Nib2Write}, {TEXT(".iie"), TEXT(".do.;.nib;.po;.prg"), IieDetect, NULL, IieRead, IieWrite}}; static BYTE diskbyte[0x40] = {0x96,0x97,0x9A,0x9B,0x9D,0x9E,0x9F,0xA6, 0xA7,0xAB,0xAC,0xAD,0xAE,0xAF,0xB2,0xB3, 0xB4,0xB5,0xB6,0xB7,0xB9,0xBA,0xBB,0xBC, 0xBD,0xBE,0xBF,0xCB,0xCD,0xCE,0xCF,0xD3, 0xD6,0xD7,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE, 0xDF,0xE5,0xE6,0xE7,0xE9,0xEA,0xEB,0xEC, 0xED,0xEE,0xEF,0xF2,0xF3,0xF4,0xF5,0xF6, 0xF7,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}; static BYTE sectornumber[3][0x10] = {{0x00,0x08,0x01,0x09,0x02,0x0A,0x03,0x0B, 0x04,0x0C,0x05,0x0D,0x06,0x0E,0x07,0x0F}, {0x00,0x07,0x0E,0x06,0x0D,0x05,0x0C,0x04, 0x0B,0x03,0x0A,0x02,0x09,0x01,0x08,0x0F}, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}}; static LPBYTE workbuffer = NULL; /**************************************************************************** * * NIBBLIZATION FUNCTIONS * ***/ //=========================================================================== LPBYTE Code62 (int sector) { // CONVERT THE 256 8-BIT BYTES INTO 342 6-BIT BYTES, WHICH WE STORE // STARTING AT 4K INTO THE WORK BUFFER. { LPBYTE sectorbase = workbuffer+(sector << 8); LPBYTE resultptr = workbuffer+0x1000; BYTE offset = 0xAC; while (offset != 0x02) { BYTE value = 0; #define ADDVALUE(a) value = (value << 2) | \ (((a) & 0x01) << 1) | \ (((a) & 0x02) >> 1) ADDVALUE(*(sectorbase+offset)); offset -= 0x56; ADDVALUE(*(sectorbase+offset)); offset -= 0x56; ADDVALUE(*(sectorbase+offset)); offset -= 0x53; #undef ADDVALUE *(resultptr++) = value << 2; } *(resultptr-2) &= 0x3F; *(resultptr-1) &= 0x3F; int loop = 0; while (loop < 0x100) *(resultptr++) = *(sectorbase+(loop++)); } // EXCLUSIVE-OR THE ENTIRE DATA BLOCK WITH ITSELF OFFSET BY ONE BYTE, // CREATING A 343RD BYTE WHICH IS USED AS A CHECKSUM. STORE THE NEW // BLOCK OF 343 BYTES STARTING AT 5K INTO THE WORK BUFFER. { BYTE savedval = 0; LPBYTE sourceptr = workbuffer+0x1000; LPBYTE resultptr = workbuffer+0x1400; int loop = 342; while (loop--) { *(resultptr++) = savedval ^ *sourceptr; savedval = *(sourceptr++); } *resultptr = savedval; } // USING A LOOKUP TABLE, CONVERT THE 6-BIT BYTES INTO DISK BYTES. A VALID // DISK BYTE IS A BYTE THAT HAS THE HIGH BIT SET, AT LEAST TWO ADJACENT // BITS SET (EXCLUDING THE HIGH BIT), AND AT MOST ONE PAIR OF CONSECUTIVE // ZERO BITS. THE CONVERTED BLOCK OF 343 BYTES IS STORED STARTING AT 4K // INTO THE WORK BUFFER. { LPBYTE sourceptr = workbuffer+0x1400; LPBYTE resultptr = workbuffer+0x1000; int loop = 343; while (loop--) *(resultptr++) = diskbyte[(*(sourceptr++)) >> 2]; } return workbuffer+0x1000; } //=========================================================================== void Decode62 (LPBYTE imageptr) { // IF WE HAVEN'T ALREADY DONE SO, GENERATE A TABLE FOR CONVERTING // DISK BYTES BACK INTO 6-BIT BYTES static BOOL tablegenerated = 0; static BYTE sixbitbyte[0x80]; if (!tablegenerated) { ZeroMemory(sixbitbyte,0x80); int loop = 0; while (loop < 0x40) { sixbitbyte[diskbyte[loop]-0x80] = loop << 2; loop++; } tablegenerated = 1; } // USING OUR TABLE, CONVERT THE DISK BYTES BACK INTO 6-BIT BYTES { LPBYTE sourceptr = workbuffer+0x1000; LPBYTE resultptr = workbuffer+0x1400; int loop = 343; while (loop--) *(resultptr++) = sixbitbyte[*(sourceptr++) & 0x7F]; } // EXCLUSIVE-OR THE ENTIRE DATA BLOCK WITH ITSELF OFFSET BY ONE BYTE // TO UNDO THE EFFECTS OF THE CHECKSUMMING PROCESS { BYTE savedval = 0; LPBYTE sourceptr = workbuffer+0x1400; LPBYTE resultptr = workbuffer+0x1000; int loop = 342; while (loop--) { *resultptr = savedval ^ *(sourceptr++); savedval = *(resultptr++); } } // CONVERT THE 342 6-BIT BYTES INTO 256 8-BIT BYTES { LPBYTE lowbitsptr = workbuffer+0x1000; LPBYTE sectorbase = workbuffer+0x1056; BYTE offset = 0xAC; while (offset != 0x02) { if (offset >= 0xAC) *(imageptr+offset) = (*(sectorbase+offset) & 0xFC) | (((*lowbitsptr) & 0x80) >> 7) | (((*lowbitsptr) & 0x40) >> 5); offset -= 0x56; *(imageptr+offset) = (*(sectorbase+offset) & 0xFC) | (((*lowbitsptr) & 0x20) >> 5) | (((*lowbitsptr) & 0x10) >> 3); offset -= 0x56; *(imageptr+offset) = (*(sectorbase+offset) & 0xFC) | (((*lowbitsptr) & 0x08) >> 3) | (((*lowbitsptr) & 0x04) >> 1); offset -= 0x53; lowbitsptr++; } } } //=========================================================================== void DenibblizeTrack (LPBYTE trackimage, BOOL dosorder, int nibbles) { ZeroMemory(workbuffer,0x1000); // SEARCH THROUGH THE TRACK IMAGE FOR EACH SECTOR. FOR EVERY SECTOR // WE FIND, COPY THE NIBBLIZED DATA FOR THAT SECTOR INTO THE WORK // BUFFER AT OFFSET 4K. THEN CALL DECODE62() TO DENIBBLIZE THE DATA // IN THE BUFFER AND WRITE IT INTO THE FIRST PART OF THE WORK BUFFER // OFFSET BY THE SECTOR NUMBER. { int offset = 0; int partsleft = 33; int sector = 0; while (partsleft--) { BYTE byteval[3] = {0,0,0}; int bytenum = 0; int loop = nibbles; while ((loop--) && (bytenum < 3)) { if (bytenum) byteval[bytenum++] = *(trackimage+offset++); else if (*(trackimage+offset++) == 0xD5) bytenum = 1; if (offset >= nibbles) offset = 0; } if ((bytenum == 3) && (byteval[1] = 0xAA)) { int loop = 0; int tempoffset = offset; while (loop < 384) { *(workbuffer+0x1000+loop++) = *(trackimage+tempoffset++); if (tempoffset >= nibbles) tempoffset = 0; } if (byteval[2] == 0x96) sector = ((*(workbuffer+0x1004) & 0x55) << 1) | (*(workbuffer+0x1005) & 0x55); else if (byteval[2] == 0xAD) { Decode62(workbuffer+(sectornumber[dosorder][sector] << 8)); sector = 0; } } } } } //=========================================================================== DWORD NibblizeTrack (LPBYTE trackimagebuffer, BOOL dosorder, int track) { ZeroMemory(workbuffer+4096,4096); LPBYTE imageptr = trackimagebuffer; BYTE sector = 0; // WRITE GAP ONE, WHICH CONTAINS 48 SELF-SYNC BYTES int loop; for (loop = 0; loop < 48; loop++) *(imageptr++) = 0xFF; while (sector < 16) { // WRITE THE ADDRESS FIELD, WHICH CONTAINS: // - PROLOGUE (D5AA96) // - VOLUME NUMBER ("4 AND 4" ENCODED) // - TRACK NUMBER ("4 AND 4" ENCODED) // - SECTOR NUMBER ("4 AND 4" ENCODED) // - CHECKSUM ("4 AND 4" ENCODED) // - EPILOGUE (DEAAEB) *(imageptr++) = 0xD5; *(imageptr++) = 0xAA; *(imageptr++) = 0x96; #define VOLUME 0xFE #define CODE44A(a) ((((a) >> 1) & 0x55) | 0xAA) #define CODE44B(a) (((a) & 0x55) | 0xAA) *(imageptr++) = CODE44A(VOLUME); *(imageptr++) = CODE44B(VOLUME); *(imageptr++) = CODE44A((BYTE)track); *(imageptr++) = CODE44B((BYTE)track); *(imageptr++) = CODE44A(sector); *(imageptr++) = CODE44B(sector); *(imageptr++) = CODE44A(VOLUME ^ ((BYTE)track) ^ sector); *(imageptr++) = CODE44B(VOLUME ^ ((BYTE)track) ^ sector); #undef CODE44A #undef CODE44B *(imageptr++) = 0xDE; *(imageptr++) = 0xAA; *(imageptr++) = 0xEB; // WRITE GAP TWO, WHICH CONTAINS SIX SELF-SYNC BYTES for (loop = 0; loop < 6; loop++) *(imageptr++) = 0xFF; // WRITE THE DATA FIELD, WHICH CONTAINS: // - PROLOGUE (D5AAAD) // - 343 6-BIT BYTES OF NIBBLIZED DATA, INCLUDING A 6-BIT CHECKSUM // - EPILOGUE (DEAAEB) *(imageptr++) = 0xD5; *(imageptr++) = 0xAA; *(imageptr++) = 0xAD; CopyMemory(imageptr,Code62(sectornumber[dosorder][sector]),343); imageptr += 343; *(imageptr++) = 0xDE; *(imageptr++) = 0xAA; *(imageptr++) = 0xEB; // WRITE GAP THREE, WHICH CONTAINS 27 SELF-SYNC BYTES for (loop = 0; loop < 27; loop++) *(imageptr++) = 0xFF; sector++; } return imageptr-trackimagebuffer; } //=========================================================================== void SkewTrack (int track, int nibbles, LPBYTE trackimagebuffer) { int skewbytes = (track*768) % nibbles; CopyMemory(workbuffer,trackimagebuffer,nibbles); CopyMemory(trackimagebuffer,workbuffer+skewbytes,nibbles-skewbytes); CopyMemory(trackimagebuffer+nibbles-skewbytes,workbuffer,skewbytes); } /**************************************************************************** * * RAW PROGRAM IMAGE (APL) FORMAT IMPLEMENTATION * ***/ //=========================================================================== BOOL AplBoot (imageinfoptr ptr) { SetFilePointer(ptr->file,0,NULL,FILE_BEGIN); WORD address = 0; WORD length = 0; DWORD bytesread; ReadFile(ptr->file,&address,sizeof(WORD),&bytesread,NULL); ReadFile(ptr->file,&length ,sizeof(WORD),&bytesread,NULL); if ((((WORD)(address+length)) <= address) || (address >= 0xC000) || (address+length-1 >= 0xC000)) return 0; ReadFile(ptr->file,mem+address,length,&bytesread,NULL); int loop = 192; while (loop--) *(memdirty+loop) = 0xFF; regs.pc = address; return 1; } //=========================================================================== DWORD AplDetect (LPBYTE imageptr, DWORD imagesize) { DWORD length = *(LPWORD)(imageptr+2); return (((length+4) == imagesize) || ((length+4+((256-((length+4) & 255)) & 255)) == imagesize)); } /**************************************************************************** * * DOS ORDER (DO) FORMAT IMPLEMENTATION * ***/ //=========================================================================== DWORD DoDetect (LPBYTE imageptr, DWORD imagesize) { if (((imagesize < 143105) || (imagesize > 143364)) && (imagesize != 143403) && (imagesize != 143488)) return 0; // CHECK FOR A DOS ORDER IMAGE OF A DOS DISKETTE { int loop = 0; BOOL mismatch = 0; while ((loop++ < 15) && !mismatch) if (*(imageptr+0x11002+(loop << 8)) != loop-1) mismatch = 1; if (!mismatch) return 2; } // CHECK FOR A DOS ORDER IMAGE OF A PRODOS DISKETTE { int loop = 1; BOOL mismatch = 0; while ((loop++ < 5) && !mismatch) if ((*(LPWORD)(imageptr+(loop << 9)+0x100) != ((loop == 5) ? 0 : 6-loop)) || (*(LPWORD)(imageptr+(loop << 9)+0x102) != ((loop == 2) ? 0 : 8-loop))) mismatch = 1; if (!mismatch) return 2; } return 1; } //=========================================================================== void DoRead (imageinfoptr ptr, int track, int quartertrack, LPBYTE trackimagebuffer, int *nibbles) { SetFilePointer(ptr->file,ptr->offset+(track << 12),NULL,FILE_BEGIN); ZeroMemory(workbuffer,4096); DWORD bytesread; ReadFile(ptr->file,workbuffer,4096,&bytesread,NULL); *nibbles = NibblizeTrack(trackimagebuffer,1,track); if (!enhancedisk) SkewTrack(track,*nibbles,trackimagebuffer); } //=========================================================================== void DoWrite (imageinfoptr ptr, int track, int quartertrack, LPBYTE trackimage, int nibbles) { ZeroMemory(workbuffer,4096); DenibblizeTrack(trackimage,1,nibbles); SetFilePointer(ptr->file,ptr->offset+(track << 12),NULL,FILE_BEGIN); DWORD byteswritten; WriteFile(ptr->file,workbuffer,4096,&byteswritten,NULL); } /**************************************************************************** * * SIMSYSTEM IIE (IIE) FORMAT IMPLEMENTATION * ***/ //=========================================================================== void IieConvertSectorOrder (LPBYTE sourceorder) { int loop = 16; while (loop--) { BYTE found = 0xFF; int loop2 = 16; while (loop2-- && (found == 0xFF)) if (*(sourceorder+loop2) == loop) found = loop2; if (found == 0xFF) found = 0; sectornumber[2][loop] = found; } } //=========================================================================== DWORD IieDetect (LPBYTE imageptr, DWORD imagesize) { if (strncmp((const char *)imageptr,"SIMSYSTEM_IIE",13) || (*(imageptr+13) > 3)) return 0; return 2; } //=========================================================================== void IieRead (imageinfoptr ptr, int track, int quartertrack, LPBYTE trackimagebuffer, int *nibbles) { // IF WE HAVEN'T ALREADY DONE SO, READ THE IMAGE FILE HEADER if (!ptr->header) { ptr->header = (LPBYTE)VirtualAlloc(NULL, 88, 0x1000, 0); if (!ptr->header) { *nibbles = 0; return; } ZeroMemory(ptr->header,88); DWORD bytesread; SetFilePointer(ptr->file,0,NULL,FILE_BEGIN); ReadFile(ptr->file,ptr->header,88,&bytesread,NULL); } // IF THIS IMAGE CONTAINS USER DATA, READ THE TRACK AND NIBBLIZE IT if (*(ptr->header+13) <= 2) { IieConvertSectorOrder(ptr->header+14); SetFilePointer(ptr->file,(track << 12)+30,NULL,FILE_BEGIN); ZeroMemory(workbuffer,4096); DWORD bytesread; ReadFile(ptr->file,workbuffer,4096,&bytesread,NULL); *nibbles = NibblizeTrack(trackimagebuffer,2,track); } // OTHERWISE, IF THIS IMAGE CONTAINS NIBBLE INFORMATION, READ IT // DIRECTLY INTO THE TRACK BUFFER else { *nibbles = *(LPWORD)(ptr->header+(track << 1)+14); DWORD offset = 88; while (track--) offset += *(LPWORD)(ptr->header+(track << 1)+14); SetFilePointer(ptr->file,offset,NULL,FILE_BEGIN); ZeroMemory(trackimagebuffer,*nibbles); DWORD bytesread; ReadFile(ptr->file,trackimagebuffer,*nibbles,&bytesread,NULL); } } //=========================================================================== void IieWrite (imageinfoptr ptr, int track, int quartertrack, LPBYTE trackimage, int nibbles) { // note: unimplemented } /**************************************************************************** * * NIBBLIZED 6656-NIBBLE (NIB) FORMAT IMPLEMENTATION * ***/ //=========================================================================== DWORD Nib1Detect (LPBYTE imageptr, DWORD imagesize) { return (imagesize == 232960) ? 2 : 0; } //=========================================================================== void Nib1Read (imageinfoptr ptr, int track, int quartertrack, LPBYTE trackimagebuffer, int *nibbles) { SetFilePointer(ptr->file,ptr->offset+track*NIBBLES,NULL,FILE_BEGIN); ReadFile(ptr->file,trackimagebuffer,NIBBLES,(DWORD *)nibbles,NULL); } //=========================================================================== void Nib1Write (imageinfoptr ptr, int track, int quartertrack, LPBYTE trackimage, int nibbles) { SetFilePointer(ptr->file,ptr->offset+track*NIBBLES,NULL,FILE_BEGIN); DWORD byteswritten; WriteFile(ptr->file,trackimage,nibbles,&byteswritten,NULL); } /**************************************************************************** * * NIBBLIZED 6384-NIBBLE (NB2) FORMAT IMPLEMENTATION * ***/ //=========================================================================== DWORD Nib2Detect (LPBYTE imageptr, DWORD imagesize) { return (imagesize == 223440) ? 2 : 0; } //=========================================================================== void Nib2Read (imageinfoptr ptr, int track, int quartertrack, LPBYTE trackimagebuffer, int *nibbles) { SetFilePointer(ptr->file,ptr->offset+track*6384,NULL,FILE_BEGIN); ReadFile(ptr->file,trackimagebuffer,6384,(DWORD *)nibbles,NULL); } //=========================================================================== void Nib2Write (imageinfoptr ptr, int track, int quartertrack, LPBYTE trackimage, int nibbles) { SetFilePointer(ptr->file,ptr->offset+track*6384,NULL,FILE_BEGIN); DWORD byteswritten; WriteFile(ptr->file,trackimage,nibbles,&byteswritten,NULL); } /**************************************************************************** * * PRODOS ORDER (PO) FORMAT IMPLEMENTATION * ***/ //=========================================================================== DWORD PoDetect (LPBYTE imageptr, DWORD imagesize) { if (((imagesize < 143105) || (imagesize > 143364)) && (imagesize != 143488)) return 0; // CHECK FOR A PRODOS ORDER IMAGE OF A DOS DISKETTE { int loop = 4; BOOL mismatch = 0; while ((loop++ < 13) && !mismatch) if (*(imageptr+0x11002+(loop << 8)) != 14-loop) mismatch = 1; if (!mismatch) return 2; } // CHECK FOR A PRODOS ORDER IMAGE OF A PRODOS DISKETTE { int loop = 1; BOOL mismatch = 0; while ((loop++ < 5) && !mismatch) if ((*(LPWORD)(imageptr+(loop << 9) ) != ((loop == 2) ? 0 : loop-1)) || (*(LPWORD)(imageptr+(loop << 9)+2) != ((loop == 5) ? 0 : loop+1))) mismatch = 1; if (!mismatch) return 2; } return 1; } //=========================================================================== void PoRead (imageinfoptr ptr, int track, int quartertrack, LPBYTE trackimagebuffer, int *nibbles) { SetFilePointer(ptr->file,ptr->offset+(track << 12),NULL,FILE_BEGIN); ZeroMemory(workbuffer,4096); DWORD bytesread; ReadFile(ptr->file,workbuffer,4096,&bytesread,NULL); *nibbles = NibblizeTrack(trackimagebuffer,0,track); if (!enhancedisk) SkewTrack(track,*nibbles,trackimagebuffer); } //=========================================================================== void PoWrite (imageinfoptr ptr, int track, int quartertrack, LPBYTE trackimage, int nibbles) { ZeroMemory(workbuffer,4096); DenibblizeTrack(trackimage,0,nibbles); SetFilePointer(ptr->file,ptr->offset+(track << 12),NULL,FILE_BEGIN); DWORD byteswritten; WriteFile(ptr->file,workbuffer,4096,&byteswritten,NULL); } /**************************************************************************** * * PRODOS PROGRAM IMAGE (PRG) FORMAT IMPLEMENTATION * ***/ //=========================================================================== BOOL PrgBoot (imageinfoptr ptr) { SetFilePointer(ptr->file,5,NULL,FILE_BEGIN); WORD address = 0; WORD length = 0; DWORD bytesread; ReadFile(ptr->file,&address,sizeof(WORD),&bytesread,NULL); ReadFile(ptr->file,&length ,sizeof(WORD),&bytesread,NULL); length <<= 1; if ((((WORD)(address+length)) <= address) || (address >= 0xC000) || (address+length-1 >= 0xC000)) return 0; SetFilePointer(ptr->file,128,NULL,FILE_BEGIN); ReadFile(ptr->file,mem+address,length,&bytesread,NULL); int loop = 192; while (loop--) *(memdirty+loop) = 0xFF; regs.pc = address; return 1; } //=========================================================================== DWORD PrgDetect (LPBYTE imageptr, DWORD imagesize) { return (*(LPDWORD)imageptr == 0x214C470A) ? 2 : 0; } // // ----- ALL GLOBALLY ACCESSIBLE FUNCTIONS ARE BELOW THIS LINE ----- // //=========================================================================== BOOL ImageBoot (HIMAGE imagehandle) { imageinfoptr ptr = (imageinfoptr)imagehandle; BOOL result = 0; if (imagetype[ptr->format].boot) result = imagetype[ptr->format].boot(ptr); if (result) ptr->writeprotected = 1; return result; } //=========================================================================== void ImageClose (HIMAGE imagehandle) { imageinfoptr ptr = (imageinfoptr)imagehandle; if (ptr->file != INVALID_HANDLE_VALUE) CloseHandle(ptr->file); for (int track = 0; track < TRACKS; track++) if (!ptr->validtrack[track]) { DeleteFile(ptr->filename); break; } if (ptr->header) VirtualFree(ptr->header,0,/*MEM_RELEASE*/0); VirtualFree(ptr,0,/*MEM_RELEASE*/0); } //=========================================================================== void ImageDestroy () { VirtualFree(workbuffer,0,/*MEM_RELEASE*/0); workbuffer = NULL; } //=========================================================================== void ImageInitialize () { workbuffer = (LPBYTE)VirtualAlloc(NULL,0x2000,0x1000,/*PAGE_READWRITE*/0); } //=========================================================================== int ImageOpen (LPCTSTR imagefilename, HIMAGE *hDiskImage_, BOOL *pWriteProtected_, BOOL bCreateIfNecessary) { if (! (imagefilename && hDiskImage_ && pWriteProtected_ && workbuffer)) return IMAGE_ERROR_BAD_POINTER; // HACK: MAGIC # -1 // TRY TO OPEN THE IMAGE FILE HANDLE file = INVALID_HANDLE_VALUE; if (! *pWriteProtected_) // file = CreateFile(imagefilename, // GENERIC_READ | GENERIC_WRITE, // FILE_SHARE_READ | FILE_SHARE_WRITE, // (LPSECURITY_ATTRIBUTES)NULL, // OPEN_EXISTING, // FILE_ATTRIBUTE_NORMAL, // NULL); file = fopen(imagefilename, "r+b"); // open file in r/w mode // File may have read-only attribute set, so try to open as read-only. if (file == INVALID_HANDLE_VALUE) { // file = CreateFile( // imagefilename, // GENERIC_READ, // FILE_SHARE_READ, // (LPSECURITY_ATTRIBUTES)NULL, // OPEN_EXISTING, // FILE_ATTRIBUTE_NORMAL, // NULL ); file = fopen(imagefilename, "rb"); // open file just for reading if (file != INVALID_HANDLE_VALUE) *pWriteProtected_ = 1; } if ((file == INVALID_HANDLE_VALUE) && bCreateIfNecessary) // file = CreateFile( // imagefilename, // GENERIC_READ | GENERIC_WRITE, // FILE_SHARE_READ | FILE_SHARE_WRITE, // (LPSECURITY_ATTRIBUTES)NULL, // CREATE_NEW, // FILE_ATTRIBUTE_NORMAL, // NULL ); file = fopen(imagefilename, "a+b"); // create file // IF WE AREN'T ABLE TO OPEN THE FILE, RETURN if (file == INVALID_HANDLE_VALUE) return IMAGE_ERROR_UNABLE_TO_OPEN; // HACK: MAGIC # 1 // DETERMINE THE FILE'S EXTENSION AND CONVERT IT TO LOWERCASE LPCTSTR imagefileext = imagefilename; if (_tcsrchr(imagefileext,FILE_SEPARATOR)) imagefileext = _tcsrchr(imagefileext,FILE_SEPARATOR)+1; if (_tcsrchr(imagefileext,TEXT('.'))) imagefileext = _tcsrchr(imagefileext,TEXT('.')); #define _MAX_EXT 5 TCHAR ext[_MAX_EXT]; _tcsncpy(ext,imagefileext,_MAX_EXT); CharLowerBuff(ext,_tcslen(ext)); DWORD size = GetFileSize(file,NULL); LPBYTE view = NULL; LPBYTE pImage = NULL; const DWORD UNKNOWN_FORMAT = 0xFFFFFFFF; DWORD format = UNKNOWN_FORMAT; if (size > 0) { // MAP THE FILE INTO MEMORY FOR USE BY THE DETECTION FUNCTIONS /* HANDLE mapping = CreateFileMapping( file, (LPSECURITY_ATTRIBUTES)NULL, PAGE_READONLY, 0,0,NULL ); view = (LPBYTE)MapViewOfFile(mapping,FILE_MAP_READ,0,0,0);*/ view = (LPBYTE)malloc(size); fread(view, 1, size, (FILE*)file); fseek((FILE*)file, 0, FILE_BEGIN); // I just got accustomed to mrsftish FILE_BEGIN, FILE_END, etc. Hmm. ^_^ pImage = view; if (pImage) { // DETERMINE WHETHER THE FILE HAS A 128-BYTE MACBINARY HEADER if ((size > 128) && (!*pImage) && (*(pImage+1) < 120) && (!*(pImage+*(pImage+1)+2)) && (*(pImage+0x7A) == 0x81) && (*(pImage+0x7B) == 0x81)) { pImage += 128; size -= 128; } // CALL THE DETECTION FUNCTIONS IN ORDER, LOOKING FOR A MATCH DWORD possibleformat = UNKNOWN_FORMAT; // 0xFFFFFFFF; int loop = 0; while ((loop < IMAGETYPES) && (format == UNKNOWN_FORMAT)) // 0xFFFFFFFF)) { { if (*ext && _tcsstr(imagetype[loop].rejectexts,ext)) ++loop; else { DWORD result = imagetype[loop].detect(pImage,size); if (result == 2) format = loop; else if ((result == 1) && (possibleformat == UNKNOWN_FORMAT)) // 0xFFFFFFFF)) possibleformat = loop++; else ++loop; } } if (format == UNKNOWN_FORMAT) // 0xFFFFFFFF) format = possibleformat; // CLOSE THE MEMORY MAPPING // UnmapViewOfFile(view); free(view); // free memory block, allocated before } //CloseHandle(mapping); } else { // WE CREATE ONLY DOS ORDER (DO) OR 6656-NIBBLE (NIB) FORMAT FILES for (int loop = 1; loop <= 4; loop += 3) { if (*ext && _tcsstr(imagetype[loop].createexts,ext)) { format = loop; break; } } } // IF THE FILE DOES MATCH A KNOWN FORMAT... if (format != UNKNOWN_FORMAT) { // CREATE A RECORD FOR THE FILE, AND RETURN AN IMAGE HANDLE *hDiskImage_ = (HIMAGE)VirtualAlloc(NULL,sizeof(imageinforec),0x1000,0); if (*hDiskImage_) { ZeroMemory(*hDiskImage_,sizeof(imageinforec)); // do this in DiskInsert vv _tcsncpy(((imageinfoptr)*hDiskImage_)->filename,imagefilename,MAX_PATH); ((imageinfoptr)*hDiskImage_)->format = format; ((imageinfoptr)*hDiskImage_)->file = file; ((imageinfoptr)*hDiskImage_)->offset = pImage-view; ((imageinfoptr)*hDiskImage_)->writeprotected = *pWriteProtected_; for (int track = 0; track < TRACKS; track++) ((imageinfoptr)*hDiskImage_)->validtrack[track] = (size > 0); return IMAGE_ERROR_NONE; // HACK: MAGIC # 0 } } CloseHandle(file); if (!(size > 0)) DeleteFile(imagefilename); return IMAGE_ERROR_BAD_SIZE; // HACK: MAGIC # 2 } //=========================================================================== void ImageReadTrack (HIMAGE imagehandle, int track, int quartertrack, LPBYTE trackimagebuffer, int *nibbles) { imageinfoptr ptr = (imageinfoptr)imagehandle; if (imagetype[ptr->format].read && ptr->validtrack[track]) imagetype[ptr->format].read(ptr,track,quartertrack,trackimagebuffer,nibbles); else for (*nibbles = 0; *nibbles < NIBBLES; (*nibbles)++) trackimagebuffer[*nibbles] = (BYTE)(rand() & 0xFF); } //=========================================================================== void ImageWriteTrack (HIMAGE imagehandle, int track, int quartertrack, LPBYTE trackimage, int nibbles) { imageinfoptr ptr = (imageinfoptr)imagehandle; if (imagetype[ptr->format].write && !ptr->writeprotected) { imagetype[ptr->format].write(ptr,track,quartertrack,trackimage,nibbles); ptr->validtrack[track] = 1; } }