Apple-II: add disk format converter, some cleanup.

This commit is contained in:
sorgelig
2019-10-04 16:40:02 +08:00
parent 560f19dc6b
commit 4726048389
3 changed files with 403 additions and 188 deletions

View File

@@ -7,7 +7,6 @@
#include <ctype.h>
#include "DiskImage.h"
#include "file_io.h"
#define ERR_OPEN "Error: can't open source file"
#define ERR_GETLEN "Error: can't get file length!"
@@ -27,6 +26,186 @@
char errsect[] = "ERROR: THIS SECTOR NOT FOUND OR IN NON TR-DOS FORMAT!";
enum TDiskImageType { DIT_UNK, DIT_SCL, DIT_FDI, DIT_TD0, DIT_UDI, DIT_HOB, DIT_FDD };
struct VGFIND_TRACK
{
unsigned char *TrackPointer;
unsigned char *ClkPointer;
unsigned int TrackLength;
bool FoundTrack;
};
struct VGFIND_ADM
{
unsigned char* TrackPointer;
unsigned char* ClkPointer;
unsigned int TrackLength;
unsigned char *ADMPointer;
unsigned int ADMLength;
unsigned int MarkedOffsetADM;
unsigned int OffsetADM;
unsigned int OffsetEndADM;
bool FoundADM;
bool CRCOK;
};
struct VGFIND_SECTOR
{
VGFIND_ADM vgfa;
unsigned char *SectorPointer;
unsigned int SectorLength;
unsigned int MarkedOffsetSector;
unsigned int OffsetSector;
unsigned int OffsetEndSector;
bool FoundDATA;
bool CRCOK;
unsigned char DataMarker;
};
class TDiskImage
{
unsigned int FTrackLength[256][256];
unsigned char* FTracksPtr[256][256][2];
TDiskImageType FType;
unsigned short MakeVGCRC(unsigned char *data, unsigned long length);
public:
bool Changed;
bool ReadOnly;
bool DiskPresent;
unsigned char MaxTrack;
unsigned char MaxSide;
TDiskImage();
~TDiskImage();
bool FindTrack(unsigned char CYL, unsigned char SIDE, VGFIND_TRACK *vgft);
bool FindADMark(unsigned char CYL, unsigned char SIDE,
unsigned int FromOffset,
VGFIND_ADM *vgfa);
bool FindSector(unsigned char CYL, unsigned char SIDE,
unsigned char SECT,
VGFIND_SECTOR *vgfs, unsigned int FromOffset = 0);
void ApplySectorCRC(VGFIND_SECTOR vgfs);
void Open(const char *filename, bool ReadOnly);
void writeTRD(fileTYPE *hfile);
void readSCL(int hfile, bool readonly);
void readFDI(int hfile, bool readonly);
void readUDI(int hfile, bool readonly);
void readTD0(int hfile, bool readonly);
void readFDD(int hfile, bool readonly);
void readHOB(int hfile);
void formatTRDOS(unsigned int tracks, unsigned int sides);
void ShowError(const char *str);
};
#pragma pack(1)
struct UDI_HEADER // 16 bytes
{
unsigned char ID[4];
unsigned long UnpackedLength;
unsigned char Version;
unsigned char MaxCylinder;
unsigned char MaxSide;
unsigned char _zero;
unsigned long ExtHdrLength;
};
struct TD0_MAIN_HEADER // 12 bytes
{
char ID[2]; // +0: "TD" - 'Normal'; "td" - packed LZH ('New Advanced data compression')
unsigned char __t; // +2: = 0x00
unsigned char __1; // +3: ???
unsigned char Ver; // +4: Source version (1.0 -> 10, ..., 2.1 -> 21)
unsigned char __2; // +5: ???
unsigned char DiskType; // +6: Source disk type
unsigned char Info; // +7: D7-­ «¨ç¨¥ image info
unsigned char DataDOS; // +8: if(=0)'All sectors were copied', else'DOS Allocated sectors were copied'
unsigned char ChkdSides; // +9: if(=1)'One side was checked', else'Both sides were checked'
unsigned short CRC; // +A: CRC 娤¥à  TD0_MAIN_HEADER (ªà®¬¥ ¡ ©â á CRC)
};
struct TD0_INFO_DATA // 10 ¡ ©â ¡¥§ áâப¨ ª®¬¥­â à¨ï...
{
unsigned short CRC; // +0: CRC ¤«ï áâàãªâãàë COMMENT_DATA (¡¥§ ¡ ©â®¢ CRC)
unsigned short strLen; // +2: „«¨­  áâப¨ ª®¬¥­â à¨ï
unsigned char Year; // +4: „ â  á®§¤ ­¨ï - £®¤ (1900 + X)
unsigned char Month; // +5: „ â  á®§¤ ­¨ï - ¬¥áïæ (Ÿ­¢ àì=0, ”¥¢à «ì=1,...)
unsigned char Day; // +6: „ â  á®§¤ ­¨ï - ç¨á«®
unsigned char Hours; // +7: ‚६ï á®§¤ ­¨ï - ç áë
unsigned char Minutes; // +8: ‚६ï á®§¤ ­¨ï - ¬¨­ãâë
unsigned char Seconds; // +9: ‚६ï á®§¤ ­¨ï - ᥪ㭤ë
};
struct TD0_TRACK_HEADER // 4 bytes
{
unsigned char SectorCount;
unsigned char Track;
unsigned char Side;
unsigned char CRCL;
};
struct TD0_SECT_HEADER // 8 bytes
{
unsigned char ADRM[6];
unsigned short DataLength;
};
struct FDD_MAIN_HEADER
{
char ID[30]; /* ᨣ­ âãà  */
unsigned char MaxTracks; /* ç¨á«® â४®¢ (樫¨­¤à®¢) */
unsigned char MaxHeads; /* ç¨á«® £®«®¢®ª (1 ¨«¨ 2) */
long diskIndex; /* unused */
long DataOffset[512 * 2]; /* ᬥ饭¨¥ ¢ ä ©«¥ ª áâàãªâãà ¬ § £®«®¢ª®¢ */
/* â४®¢ */
};
struct FDD_TRACK_HEADER
{
unsigned char trkType; /* unused */
unsigned char SectNum; /* ç¨á«® ᥪâ®à®¢ ­  â४¥ */
struct
{
/* § £®«®¢®ª ᥪâ®à  */
unsigned char trk; /* ­®¬¥à â४  */
unsigned char side; /* ­®¬¥à áâ®à®­ë */
/* 7 ¡¨â í⮣® ¡ ©â  㪠§ë¢ ¥â ¡¨â a */
unsigned char sect; /* ­®¬¥à ᥪâ®à  */
unsigned char size; /* à §¬¥à ᥪâ®à  (ª®¤) */
long SectPos; /* ᬥ饭¨¥ ¢ ä ©«¥ ª ¤ ­­ë¬ ᥪâ®à  */
} sect[256];
};
struct TRDOS_DIR_ELEMENT // 16 bytes
{
char FileName[8];
char Type;
unsigned short Start;
unsigned short Length;
unsigned char SecLen;
unsigned char FirstSec;
unsigned char FirstTrk;
};
#pragma pack()
static const unsigned char sbootimage[] = {
0x00, 0x01, 0x1a, 0x00, 0xf9, 0xc0, 0xb0, 0x22, 0x31, 0x35, 0x36, 0x31, 0x39, 0x22, 0x3a, 0xea,
0x3a, 0xf7, 0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x20, 0x0d, 0x00, 0x02,
@@ -3000,6 +3179,214 @@ unsigned unpack_lzh(unsigned char *src, unsigned size, unsigned char *buf)
}
return count;
}
//--------------------------------------------------------------------------
#define VOLUME_NUMBER 254
#define TRACKS 35
#define SECTORS 16
#define SECTOR_SIZE 256
#define DOS_TRACK_uint8_tS (SECTORS * SECTOR_SIZE)
#define RAW_TRACK_uint8_tS 0x1A00
static uint8_t *target; /* Where to write in the raw_track buffer */
#define write_byte(x) (*target++ = (x))
static uint8_t GCR_encoding_table[64] = {
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 };
int Swap_Bit[4] = { 0, 2, 1, 3 }; /* swap lower 2 bits */
static uint8_t GCR_buffer[256];
static uint8_t GCR_buffer2[86];
/* physical sector no. to DOS 3.3 logical sector no. table */
static int Logical_Sector[16] = {
0x0, 0x7, 0xE, 0x6, 0xD, 0x5, 0xC, 0x4,
0xB, 0x3, 0xA, 0x2, 0x9, 0x1, 0x8, 0xF };
static int Logical_Sector_po[16] = {
0x0, 0xE, 0xD, 0xC, 0xB, 0xA, 0x9, 0x8,
0x7, 0x6, 0x5, 0x4, 0x3, 0x2, 0x1, 0xF };
/*
* write an FM encoded value, used in writing address fields
*/
static void FM_encode(uint8_t data)
{
write_byte((data >> 1) | 0xAA);
write_byte(data | 0xAA);
}
/*
* Write 0xFF sync bytes
*/
static void write_sync(int length)
{
while (length--) write_byte(0xFF);
}
static void write_address_field(int volume, int track, int sector)
{
/*
* write address mark
*/
write_byte(0xD5);
write_byte(0xAA);
write_byte(0x96);
/*
* write Volume, Track, Sector & Check-sum
*/
FM_encode(volume);
FM_encode(track);
FM_encode(sector);
FM_encode(volume ^ track ^ sector);
/*
* write epilogue
*/
write_byte(0xDE);
write_byte(0xAA);
write_byte(0xEB);
}
/*
* 6-and-2 group encoding: the heart of the "nibblization" procedure
*/
static void encode62(uint8_t *page)
{
int i, j;
/* 86 * 3 = 258, so the first two byte are encoded twice */
GCR_buffer2[0] = Swap_Bit[page[1] & 0x03];
GCR_buffer2[1] = Swap_Bit[page[0] & 0x03];
/* save higher 6 bits in GCR_buffer and lower 2 bits in GCR_buffer2 */
for (i = 255, j = 2; i >= 0; i--, j = j == 85 ? 0 : j + 1) {
GCR_buffer2[j] = (GCR_buffer2[j] << 2) | Swap_Bit[page[i] & 0x03];
GCR_buffer[i] = page[i] >> 2;
}
/* clear off higher 2 bits of GCR_buffer2 set in the last call */
for (i = 0; i < 86; i++)
GCR_buffer2[i] &= 0x3f;
}
static void write_data_field(uint8_t *page)
{
int i;
uint8_t last, checksum;
encode62(page);
/* write prologue */
write_byte(0xD5);
write_byte(0xAA);
write_byte(0xAD);
/* write GCR encoded data */
for (i = 0x55, last = 0; i >= 0; --i) {
checksum = last ^ GCR_buffer2[i];
write_byte(GCR_encoding_table[checksum]);
last = GCR_buffer2[i];
}
for (i = 0; i < 256; ++i) {
checksum = last ^ GCR_buffer[i];
write_byte(GCR_encoding_table[checksum]);
last = GCR_buffer[i];
}
/* write checksum and epilogue */
write_byte(GCR_encoding_table[last]);
write_byte(0xDE);
write_byte(0xAA);
write_byte(0xEB);
}
int dsk2nib(const char *name, fileTYPE *f)
{
int len = strlen(name);
int po = 0;
if (len > 3 && !strcasecmp(name + len - 3, ".po"))
{
po = 1;
}
else if (!(len > 4 && !strcasecmp(name + len - 4, ".dsk")) && !(len > 3 && !strcasecmp(name + len - 3, ".do")))
{
return 0;
}
static uint8_t dos_track[SECTORS * SECTOR_SIZE]; // , pro_track[SECTORS * SECTOR_SIZE];
static uint8_t raw_track[RAW_TRACK_uint8_tS];
fileTYPE disk_file = {};
if (!FileOpen(&disk_file, name))
{
printf("Unable to mount disk file \"%s\"\n", name);
return 0;
}
if (!FileOpenEx(f, "vtrd", -1))
{
FileClose(&disk_file);
printf("ERROR: fail to create /vtrd\n");
return 0;
}
/* Read, convert, and write each track */
for (int track = 0; track < TRACKS; ++track)
{
if (FileReadAdv(&disk_file, dos_track, DOS_TRACK_uint8_tS) != DOS_TRACK_uint8_tS)
{
printf("Unexpected end of disk data\n");
FileClose(&disk_file);
FileClose(f);
return 0;
}
target = raw_track;
for (int sector = 0; sector < SECTORS; sector++)
{
int sec = po ? Logical_Sector_po[sector] : sector;
write_sync(38); /* Inter-sector gap */
write_address_field(VOLUME_NUMBER, track, sector);
write_sync(8);
write_data_field(dos_track + Logical_Sector[sec] * SECTOR_SIZE);
}
/* Pad rest of buffer with sync bytes */
while (target != &raw_track[RAW_TRACK_uint8_tS]) write_byte(0xff);
if (FileWriteAdv(f, raw_track, RAW_TRACK_uint8_tS) != RAW_TRACK_uint8_tS)
{
printf("Error writing to /vtrd file\n");
FileClose(&disk_file);
FileClose(f);
return 0;
}
}
FileClose(&disk_file);
f->size = FileGetSize(f);
FileSeekLBA(f, 0);
printf("dsk2nib: vtrd size=%llu.\n", f->size);
return 1;
}
//--------------------------------------------------------------------------
int x2trd(const char *name, fileTYPE *f)

View File

@@ -1,190 +1,9 @@
#ifndef __DISKIMAGE_H
#define __DISKIMAGE_H
//-----------------------------------------------------------------------------
#include "file_io.h"
enum TDiskImageType { DIT_UNK, DIT_SCL, DIT_FDI, DIT_TD0, DIT_UDI, DIT_HOB, DIT_FDD };
struct VGFIND_TRACK
{
unsigned char *TrackPointer;
unsigned char *ClkPointer;
unsigned int TrackLength;
bool FoundTrack;
};
struct VGFIND_ADM
{
unsigned char* TrackPointer;
unsigned char* ClkPointer;
unsigned int TrackLength;
unsigned char *ADMPointer;
unsigned int ADMLength;
unsigned int MarkedOffsetADM;
unsigned int OffsetADM;
unsigned int OffsetEndADM;
bool FoundADM;
bool CRCOK;
};
struct VGFIND_SECTOR
{
VGFIND_ADM vgfa;
unsigned char *SectorPointer;
unsigned int SectorLength;
unsigned int MarkedOffsetSector;
unsigned int OffsetSector;
unsigned int OffsetEndSector;
bool FoundDATA;
bool CRCOK;
unsigned char DataMarker;
};
class TDiskImage
{
unsigned int FTrackLength[256][256];
unsigned char* FTracksPtr[256][256][2];
TDiskImageType FType;
unsigned short MakeVGCRC(unsigned char *data, unsigned long length);
public:
bool Changed;
bool ReadOnly;
bool DiskPresent;
unsigned char MaxTrack;
unsigned char MaxSide;
TDiskImage();
~TDiskImage();
bool FindTrack(unsigned char CYL, unsigned char SIDE, VGFIND_TRACK *vgft);
bool FindADMark(unsigned char CYL, unsigned char SIDE,
unsigned int FromOffset,
VGFIND_ADM *vgfa);
bool FindSector(unsigned char CYL, unsigned char SIDE,
unsigned char SECT,
VGFIND_SECTOR *vgfs, unsigned int FromOffset=0);
void ApplySectorCRC(VGFIND_SECTOR vgfs);
void Open(const char *filename, bool ReadOnly);
void writeTRD(fileTYPE *hfile);
void readSCL(int hfile, bool readonly);
void readFDI(int hfile, bool readonly);
void readUDI(int hfile, bool readonly);
void readTD0(int hfile, bool readonly);
void readFDD(int hfile, bool readonly);
void readHOB(int hfile);
void formatTRDOS(unsigned int tracks, unsigned int sides);
void ShowError(const char *str);
};
#pragma pack(1)
struct UDI_HEADER // 16 bytes
{
unsigned char ID[4];
unsigned long UnpackedLength;
unsigned char Version;
unsigned char MaxCylinder;
unsigned char MaxSide;
unsigned char _zero;
unsigned long ExtHdrLength;
};
struct TD0_MAIN_HEADER // 12 bytes
{
char ID[2]; // +0: "TD" - 'Normal'; "td" - packed LZH ('New Advanced data compression')
unsigned char __t; // +2: = 0x00
unsigned char __1; // +3: ???
unsigned char Ver; // +4: Source version (1.0 -> 10, ..., 2.1 -> 21)
unsigned char __2; // +5: ???
unsigned char DiskType; // +6: Source disk type
unsigned char Info; // +7: D7-­ «¨ç¨¥ image info
unsigned char DataDOS; // +8: if(=0)'All sectors were copied', else'DOS Allocated sectors were copied'
unsigned char ChkdSides; // +9: if(=1)'One side was checked', else'Both sides were checked'
unsigned short CRC; // +A: CRC 娤¥à  TD0_MAIN_HEADER (ªà®¬¥ ¡ ©â á CRC)
};
struct TD0_INFO_DATA // 10 ¡ ©â ¡¥§ áâப¨ ª®¬¥­â à¨ï...
{
unsigned short CRC; // +0: CRC ¤«ï áâàãªâãàë COMMENT_DATA (¡¥§ ¡ ©â®¢ CRC)
unsigned short strLen; // +2: „«¨­  áâப¨ ª®¬¥­â à¨ï
unsigned char Year; // +4: „ â  á®§¤ ­¨ï - £®¤ (1900 + X)
unsigned char Month; // +5: „ â  á®§¤ ­¨ï - ¬¥áïæ (Ÿ­¢ àì=0, ”¥¢à «ì=1,...)
unsigned char Day; // +6: „ â  á®§¤ ­¨ï - ç¨á«®
unsigned char Hours; // +7: ‚६ï á®§¤ ­¨ï - ç áë
unsigned char Minutes; // +8: ‚६ï á®§¤ ­¨ï - ¬¨­ãâë
unsigned char Seconds; // +9: ‚६ï á®§¤ ­¨ï - ᥪ㭤ë
};
struct TD0_TRACK_HEADER // 4 bytes
{
unsigned char SectorCount;
unsigned char Track;
unsigned char Side;
unsigned char CRCL;
};
struct TD0_SECT_HEADER // 8 bytes
{
unsigned char ADRM[6];
unsigned short DataLength;
};
struct FDD_MAIN_HEADER
{
char ID[30]; /* ᨣ­ âãà  */
unsigned char MaxTracks; /* ç¨á«® â४®¢ (樫¨­¤à®¢) */
unsigned char MaxHeads; /* ç¨á«® £®«®¢®ª (1 ¨«¨ 2) */
long diskIndex; /* unused */
long DataOffset[512*2]; /* ᬥ饭¨¥ ¢ ä ©«¥ ª áâàãªâãà ¬ § £®«®¢ª®¢ */
/* â४®¢ */
};
struct FDD_TRACK_HEADER
{
unsigned char trkType; /* unused */
unsigned char SectNum; /* ç¨á«® ᥪâ®à®¢ ­  â४¥ */
struct
{
/* § £®«®¢®ª ᥪâ®à  */
unsigned char trk; /* ­®¬¥à â४  */
unsigned char side; /* ­®¬¥à áâ®à®­ë */
/* 7 ¡¨â í⮣® ¡ ©â  㪠§ë¢ ¥â ¡¨â a */
unsigned char sect; /* ­®¬¥à ᥪâ®à  */
unsigned char size; /* à §¬¥à ᥪâ®à  (ª®¤) */
long SectPos; /* ᬥ饭¨¥ ¢ ä ©«¥ ª ¤ ­­ë¬ ᥪâ®à  */
} sect[256];
};
struct TRDOS_DIR_ELEMENT // 16 bytes
{
char FileName[8];
char Type;
unsigned short Start;
unsigned short Length;
unsigned char SecLen;
unsigned char FirstSec;
unsigned char FirstTrk;
};
#pragma pack()
int dsk2nib(const char *name, fileTYPE *f);
int x2trd(const char *name, fileTYPE *f);
int x2trd_ext_supp(const char *name);

View File

@@ -1155,14 +1155,23 @@ int user_io_file_mount(char *name, unsigned char index, char pre)
{
int writable = 0;
int ret = 0;
if (x2trd_ext_supp(name))
if (!strcasecmp(user_io_get_core_name_ex(), "apple-ii"))
{
ret = x2trd(name, sd_image+ index);
ret = dsk2nib(name, sd_image + index);
}
else
if (!ret)
{
writable = FileCanWrite(name);
ret = FileOpenEx(&sd_image[index], name, writable ? (O_RDWR | O_SYNC) : O_RDONLY);
if (x2trd_ext_supp(name))
{
ret = x2trd(name, sd_image + index);
}
else
{
writable = FileCanWrite(name);
ret = FileOpenEx(&sd_image[index], name, writable ? (O_RDWR | O_SYNC) : O_RDONLY);
}
}
buffer_lba[index] = ULLONG_MAX;