#include #include #include #include "osdepend.h" #include "imgtoolx.h" #ifdef LSB_FIRST typedef UINT16 littleuword; typedef UINT32 littleulong; #define GET_UWORD(a) a #define GET_ULONG(a) a #define SET_UWORD(a,v) a=v #define SET_ULONG(a,v) a=v #else typedef struct { unsigned char low, high; } littleuword; typedef struct { unsigned char low, mid, high, highest; } littleulong; #define GET_UWORD(a) (a.low|(a.high<<8)) #define GET_ULONG(a) (a.low|(a.mid<<8)|(a.high<<16)|(a.highest<<24)) #define SET_UWORD(a,v) a.low=(v)&0xff;a.high=((v)>>8)&0xff #define SET_ULONG(a,v) a.low=(v)&0xff;a.mid=((v)>>8)&0xff;a.high=((v)>>16)&0xff;a.highest=((v)>>24)&0xff #endif /* T64 File Structure was developed by Miha Peternel for use in C64S. It is easy to use and allows future extensions. ______________________ T64 file structure Offset, size, description 0, 64 tape record 64, 32*n file records for n directory entries 64+32*n, ??? binary contents of the files _______________ Tape Record Offset, size, description 0, 32 DOS tape description + EOF (for type) 32, 2 tape version ($0101) 34, 2 number of directory entries 36, 2 number of used entries (can be 0 in my loader) 38, 2 free 40, 24 user description as displayed in tape menu _______________ File Record Offset, size, description 0, 1 entry type 0 = free entry 1 = normal tape file 3 = memory snapshot v0.9, uncompressed 2..255 reserved (for memory snapshots...) 1, 1 C64 file type 2, 2 start address 4, 2 end address 6, 2 free 8, 4 offset of file contents start within T64 file 12, 4 free 16, 16 C64 file name */ typedef struct{ char dostext[0x20]; // dos text littleuword version; // packed bcd littleuword max_entries; littleuword used_entries; littleuword reserved; char description[24]; } t64_header; typedef struct { unsigned char type; unsigned char file_type; littleuword start_address; littleuword end_address; littleuword reserved; littleulong offset; littleulong reserved2; char name[0x10]; } t64_entry; typedef struct { imgtool_image base; imgtool_stream *file_handle; int size; int modified; unsigned char *data; } t64_image; #define HEADER(image) ((t64_header*)image->data) #define ENTRY(image, index) ((t64_entry*)(image->data+sizeof(t64_header))+index) typedef struct { imgtool_directory base; t64_image *image; int index; } t64_iterator; static int t64_image_init(const imgtool_module *mod, imgtool_stream *f, imgtool_image **outimg); static void t64_image_exit(imgtool_image *img); static void t64_image_info(imgtool_image *img, char *string, const int len); static int t64_image_beginenum(imgtool_image *img, imgtool_directory **outenum); static int t64_image_nextenum(imgtool_directory *enumeration, imgtool_dirent *ent); static void t64_image_closeenum(imgtool_directory *enumeration); //static size_t t64_image_freespace(imgtool_image *img); static int t64_image_readfile(imgtool_image *img, const char *fname, imgtool_stream *destf); static int t64_image_writefile(imgtool_image *img, const char *fname, imgtool_stream *sourcef, const ResolvedOption *_options); static int t64_image_deletefile(imgtool_image *img, const char *fname); static int t64_image_create(const imgtool_module *mod, imgtool_stream *f, const ResolvedOption *_options); static struct OptionTemplate t64_createopts[] = { { "entries", NULL, IMGOPTION_FLAG_TYPE_INTEGER, 0, 3, NULL }, /* [0] */ { "label", NULL, IMGOPTION_FLAG_TYPE_STRING | IMGOPTION_FLAG_HASDEFAULT, 0, 0, NULL }, /* [1] */ { NULL, NULL, 0, 0, 0, 0 } }; #define T64_OPTION_ENTRIES 0 #define T64_OPTION_LABEL 1 IMAGEMODULE( t64, "Commodore 64 Archive for Tapes", /* human readable name */ "t64", /* file extension */ NULL, /* crcfile */ NULL, /* crc system name */ EOLN_CR, /* eoln */ 0, /* flags */ t64_image_init, /* init function */ t64_image_exit, /* exit function */ t64_image_info, /* info function */ t64_image_beginenum, /* begin enumeration */ t64_image_nextenum, /* enumerate next */ t64_image_closeenum, /* close enumeration */ NULL, //t64_image_freespace, /* free space on image */ t64_image_readfile, /* read file */ t64_image_writefile, /* write file */ t64_image_deletefile, /* delete file */ t64_image_create, /* create image */ NULL, /* read sector */ NULL, /* write sector */ NULL, /* file _options */ t64_createopts /* create options */ ) static int t64_image_init(const imgtool_module *mod, imgtool_stream *f, imgtool_image **outimg) { t64_image *image; image=*(t64_image**)outimg=(t64_image *) malloc(sizeof(t64_image)); if (!image) return IMGTOOLERR_OUTOFMEMORY; memset(image, 0, sizeof(t64_image)); image->base.module = mod; image->size=stream_size(f); image->file_handle=f; image->data = (unsigned char *) malloc(image->size); if ( (!image->data) ||(stream_read(f, image->data, image->size)!=image->size) ) { free(image); *outimg=NULL; return IMGTOOLERR_OUTOFMEMORY; } return 0; } static void t64_image_exit(imgtool_image *img) { t64_image *image=(t64_image*)img; if (image->modified) { stream_clear(image->file_handle); stream_write(image->file_handle, image->data, image->size); } stream_close(image->file_handle); free(image->data); free(image); } static void t64_image_info(imgtool_image *img, char *string, const int len) { t64_image *image=(t64_image*)img; char dostext_with_null[33]= { 0 }; char name_with_null[25]={ 0 }; strncpy(dostext_with_null, HEADER(image)->dostext, 32); strncpy(name_with_null, HEADER(image)->description, 24); sprintf(string,"%s\n%s\nversion:%.4x max entries:%d", dostext_with_null, name_with_null, GET_UWORD(HEADER(image)->version), HEADER(image)->max_entries); } static int t64_image_beginenum(imgtool_image *img, imgtool_directory **outenum) { t64_image *image=(t64_image*)img; t64_iterator *iter; iter=*(t64_iterator**)outenum = (t64_iterator *) malloc(sizeof(t64_iterator)); if (!iter) return IMGTOOLERR_OUTOFMEMORY; iter->base.module = img->module; iter->image=image; iter->index = 0; return 0; } static int t64_image_nextenum(imgtool_directory *enumeration, imgtool_dirent *ent) { t64_iterator *iter=(t64_iterator*)enumeration; ent->corrupt=0; for (;!(ent->eof=(iter->index>=GET_UWORD(HEADER(iter->image)->max_entries)));iter->index++ ){ if (ENTRY(iter->image, iter->index)->type==0) continue; memset(ent->fname,0,17); strncpy(ent->fname, ENTRY(iter->image, iter->index)->name, 16); if (ent->attr) sprintf(ent->attr,"start:%.4x end:%.4x type:%d file:%d", GET_UWORD( ENTRY(iter->image,iter->index)->start_address), GET_UWORD( ENTRY(iter->image,iter->index)->end_address), ENTRY(iter->image,iter->index)->type, ENTRY(iter->image,iter->index)->file_type ); ent->filesize=GET_UWORD( ENTRY(iter->image, iter->index)->end_address ) -GET_UWORD( ENTRY(iter->image, iter->index)->start_address ); iter->index++; break; } return 0; } static void t64_image_closeenum(imgtool_directory *enumeration) { free(enumeration); } #if 0 static size_t t64_image_freespace(imgtool_image *img) { int i; rsdos_diskimage *rsimg = (rsdos_diskimage *) img; size_t s = 0; for (i = 0; i < GRANULE_COUNT; i++) if (rsimg->granulemap[i] == 0xff) s += (9 * 256); return s; } #endif static int t64_image_findfile(t64_image *image, const char *fname) { int i=0; for (i=0; imax_entries); i++) { if (ENTRY(image, i)->type==0) continue; if (!strnicmp(fname, ENTRY(image,i)->name, strlen(fname)) ) return i; } return -1; } static int t64_image_readfile(imgtool_image *img, const char *fname, imgtool_stream *destf) { t64_image *image=(t64_image*)img; int size; int ind; if ((ind=t64_image_findfile(image, fname))==-1 ) return IMGTOOLERR_MODULENOTFOUND; size=GET_UWORD( ENTRY(image, ind)->end_address )-GET_UWORD( ENTRY(image, ind)->start_address ); if (stream_write(destf, &ENTRY(image, ind)->start_address, 2)!=2) { return IMGTOOLERR_WRITEERROR; } if (stream_write(destf, image->data+GET_ULONG(ENTRY(image, ind)->offset), size)!=size) { return IMGTOOLERR_WRITEERROR; } return 0; } static int t64_image_writefile(imgtool_image *img, const char *fname, imgtool_stream *sourcef, const ResolvedOption *_options) { t64_image *image=(t64_image*)img; int size, fsize; int ind; int pos, i, t; fsize=stream_size(sourcef); if ((ind=t64_image_findfile(image, fname))==-1 ) { // appending for (ind=0; indmax_entries)&&(ENTRY(image,ind)->type!=0); ind++) ; if (ind>=GET_UWORD(HEADER(image)->max_entries)) return IMGTOOLERR_NOSPACE; pos=image->size; if (!(image->data=realloc(image->data, image->size+fsize-2)) ) return IMGTOOLERR_OUTOFMEMORY; image->size+=fsize-2; #ifdef LSB_FIRST HEADER(image)->used_entries++; #else if (++HEADER(image)->used_entries.low == 0) HEADER(image)->used_entries.high++; #endif } else { pos=GET_ULONG(ENTRY(image,ind)->offset); // find the size of the data in this area for (size=image->size-pos, i=0; imax_entries); i++) { if (ENTRY(image,i)->type==0) continue; if (GET_UWORD(ENTRY(image,i)->offset)offset)-pos>=size) continue; size=GET_ULONG(ENTRY(image, i)->offset)-pos; } if ((size!=0)&&(image->size-pos-size!=0)) memmove(image->data+pos, image->data+pos+size, image->size-pos-size); // correct offset positions in other entries for (i=0;imax_entries); i++) { if (i==ind) continue; if (ENTRY(image,i)->type==0) continue; if (GET_ULONG(ENTRY(image,i)->offset)offset)-size; SET_ULONG( ENTRY(image,i)->offset, t); } // overwritting if (!(image->data=realloc(image->data, image->size+fsize-2-size))) return IMGTOOLERR_OUTOFMEMORY; pos=image->size; image->size=image->size+fsize-2-size; } memset(ENTRY(image,ind), 0, sizeof(t64_entry)); if (stream_read(sourcef, &ENTRY(image,ind)->start_address, 2)!=2) { return IMGTOOLERR_READERROR; } if (stream_read(sourcef, image->data+pos, fsize-2)!=fsize-2) { return IMGTOOLERR_READERROR; } SET_UWORD( ENTRY(image, ind)->end_address, GET_UWORD( ENTRY(image, ind)->start_address)+fsize-2); SET_ULONG( ENTRY(image, ind)->offset, pos); strncpy(ENTRY(image, ind)->name, fname, 16); ENTRY(image,ind)->type=1; // normal file ENTRY(image,ind)->file_type=1; // prg image->modified=1; return 0; } static int t64_image_deletefile(imgtool_image *img, const char *fname) { t64_image *image=(t64_image*)img; int pos, size; int ind, i; if ((ind=t64_image_findfile(image, fname))==-1 ) { return IMGTOOLERR_MODULENOTFOUND; } pos=GET_ULONG(ENTRY(image,ind)->offset); // find the size of the data in this area for (size=image->size-pos, i=0; imax_entries); i++) { if (ENTRY(image,i)->type==0) continue; if (GET_UWORD(ENTRY(image,i)->offset)offset)-pos>=size) continue; size=GET_ULONG(ENTRY(image, i)->offset)-pos; } if ((size!=0)&&(image->size-pos-size!=0)) memmove(image->data+pos, image->data+pos+size, image->size-pos-size); // correct offset positions in other entries for (i=0;imax_entries); i++) { if (i==ind) continue; if (ENTRY(image,i)->type==0) continue; if (GET_ULONG(ENTRY(image,i)->offset)offset, GET_ULONG(ENTRY(image,i)->offset)-size ); } image->size-=size; ENTRY(image,ind)->type=0; // normal file image->modified=1; #ifdef LSB_FIRST HEADER(image)->used_entries--; #else if (HEADER(image)->used_entries.low-- == 0) HEADER(image)->used_entries.high--; #endif return 0; } static int t64_image_create(const imgtool_module *mod, imgtool_stream *f, const ResolvedOption *_options) { int entries; t64_header header={ "T64 Tape archiv created by MESS\x1a" }; t64_entry entry= { 0 }; int i; entries = _options[T64_OPTION_ENTRIES].i; if (entries==0) entries=10; SET_UWORD(header.version, 0x0101); SET_UWORD(header.max_entries, entries); if (_options[T64_OPTION_LABEL].s) strcpy(header.description, _options[T64_OPTION_LABEL].s); if (stream_write(f, &header, sizeof(t64_header)) != sizeof(t64_header)) return IMGTOOLERR_WRITEERROR; for (i=0; i