It was thus said that the Great Tony Duell once stated:
There are now presumably a number of disks archived in Imagedisk format
that cannot (legally) be read. Great!. This is no better than teledisk.
It has convinced me even more that the only tools I will use to archive
disks are open-source ones, because that's the only way I can be sure
that the author won't throw a hissy fit for whatever reason and make the
archives useless.
Here you go Tony, and any other person that bitched about the Imagedisk
format being undocumented. If Dave allows, I can include the actual format
from his documentation (he wrote the documentation, but
said the format is
open---I suppose someone can write up the format, but I've
already more time
on this than I cared to).
-spc (Now maybe this will shut up the people that claim the format
isn't documented ... )
/*********************************************************************
*
* Copyright 2001 by Sean Conner. All Rights Reserved.
*
* This program 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.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* Comments, questions and criticisms can be sent to: sean at
conman.org
*
*********************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
/***********************************************************************/
typedef unsigned char t_byte;
enum
{
TH_MODE,
TH_CYLINDER,
TH_HEAD,
TH_SECTORS,
TH_SECTORSIZE,
TH_SIZE
};
typedef t_byte t_trackheader[5];
struct track
{
int mode;
int cylinder;
int head;
int sectors;
int sectorsize;
t_byte *sectormap;
t_byte *cylindermap;
t_byte *headmap;
int *validsector;
t_byte **data;
};
/**********************************************************************/
static void *my_malloc (size_t);
static void *my_realloc (void *,size_t);
static void my_fread (void *,size_t,FILE *,int);
static int my_feof (FILE *);
static void imd_track_header_check (t_trackheader,int,long);
char *imd_header (FILE *);
struct track *imd_track (FILE *,int);
void imd_track_free (struct track *);
/**************************************************************************/
int main(int argc,char *argv[])
{
int i;
int j;
FILE *fpin;
char *header;
struct track *track;
static char *modes[] =
{
"500 kbps FM",
"300 kbps FM",
"250 kbps FM",
"500 kbps MFM",
"300 kbps MFM",
"250 kbps MFM"
};
if (argc == 1)
{
fprintf(stderr,"usage: %s <imd files>\n",argv[0]);
exit(EXIT_FAILURE);
}
for (i = 1 ; i < argc ; i++)
{
fpin = fopen(argv[i],"rb");
if (fpin == NULL)
{
perror(argv[i]);
continue;
}
header = imd_header(fpin);
printf("HEADER:\n%s\n",header);
free(header);
for (j = 0 ; !my_feof(fpin) ; j++)
{
track = imd_track(fpin,j);
printf(
"Track: %d\n"
"\tMode: %s\n"
"\tCylinder: %d\n"
"\tHead: %d\n"
"\tSectors: %d\n"
"\tSector Size: %d\n"
"\tCylinder Map: %s\n"
"\tHead Map: %s\n",
j,
modes[track->mode],
track->cylinder,
track->head,
track->sectors,
track->sectorsize,
(track->cylindermap == NULL) ? "no" : "yes",
(track->headmap == NULL) ? "no" : "yes"
);
imd_track_free(track);
}
fclose(fpin);
}
return(EXIT_SUCCESS);
}
/*************************************************************************/
static void *my_malloc(size_t size)
{
void *mem;
assert(size > 0);
mem = malloc(size);
if (mem == NULL)
{
perror("out of memory");
exit(EXIT_FAILURE);
}
return(mem);
}
/*************************************************************************/
static void *my_realloc(void *ptr,size_t size)
{
void *mem;
mem = realloc(ptr,size);
if (mem == NULL)
{
perror("out of memory");
exit(EXIT_FAILURE);
}
return(mem);
}
/************************************************************************/
static void my_fread(void *ptr,size_t size,FILE *fpin,int track)
{
size_t r;
r = fread(ptr,1,size,fpin);
if (r != size)
{
fprintf(stderr,"corrupt track %04d - reading error\n",track);
exit(EXIT_FAILURE);
}
}
/***************************************************************************/
static int my_feof(FILE *fp)
{
int c;
c = fgetc(fp);
if (c == EOF) return(1);
ungetc(c,fp);
return(0);
}
/***************************************************************************/
char *imd_header(FILE *fpin)
{
char *text = NULL;
size_t size = 0;
size_t i = 0;
int c;
assert(fpin != NULL);
while(!feof(fpin))
{
c = fgetc(fpin);
if (c == 0x1A) break;
if (c == EOF)
{
fprintf(stderr,"unexpected end of input in header\n");
exit(EXIT_FAILURE);
}
if (i == size)
{
size += 1024;
text = my_realloc(text,size);
}
text[i++] = c;
}
if (text) text[i] = '\0';
return(text);
}
/************************************************************************/
static void imd_track_header_check(t_trackheader th,int track,long pos)
{
if (th[TH_MODE] > 5)
{
fprintf(
stderr,
"corrupt track %04d - non-supported mode %d @ %08lX\n",
track,
th[TH_MODE],
pos
);
exit(EXIT_FAILURE);
}
if ((th[TH_HEAD] & 0x3F) > 1)
{
fprintf(
stderr,
"corrupt track %04d - non-supported # heads %d @ %08lX\n",
track,
th[TH_HEAD],
pos
);
exit(EXIT_FAILURE);
}
if (th[TH_SECTORSIZE] > 6)
{
fprintf(
stderr,
"corrupt track %04d - non-supported sector size %d @ %08lX\n",
track,
th[TH_SECTORSIZE],
pos
);
exit(EXIT_FAILURE);
}
}
/*************************************************************************/
struct track *imd_track(FILE *fpin,int tr)
{
struct track *track;
t_trackheader thead;
int i;
t_byte sectype;
t_byte fill;
assert(fpin != NULL);
assert(tr > -1);
track = my_malloc(sizeof(struct track));
memset(track,0,sizeof(struct track));
my_fread(&thead,sizeof(t_trackheader),fpin,tr);
imd_track_header_check(thead,tr,ftell(fpin));
track->mode = thead[TH_MODE];
track->cylinder = thead[TH_CYLINDER];
track->head = thead[TH_HEAD] & 0x3F;
track->sectors = thead[TH_SECTORS];
track->sectorsize = 128 << (thead[TH_SECTORSIZE]);
assert(
(track->sectorsize == 128)
|| (track->sectorsize == 256)
|| (track->sectorsize == 512)
|| (track->sectorsize == 1024)
|| (track->sectorsize == 2048)
|| (track->sectorsize == 4096)
|| (track->sectorsize == 8192)
);
track->sectormap = my_malloc(track->sectors);
my_fread(track->sectormap,track->sectors,fpin,tr);
if (thead[TH_HEAD] & 0x80)
{
track->cylindermap = my_malloc(track->sectors);
my_fread(track->cylindermap,track->sectors,fpin,tr);
}
if (thead[TH_HEAD] & 0x40)
{
track->headmap = my_malloc(track->sectors);
my_fread(track->headmap,track->sectors,fpin,tr);
}
track->validsector = my_malloc(track->sectors * sizeof(int));
track->data = my_malloc(track->sectors * sizeof(t_byte *));
for (i = 0 ; i < track->sectors ; i++)
{
track->data[i] = my_malloc(track->sectorsize);
my_fread(§ype,1,fpin,tr);
if (sectype == 0)
{
track->validsector[i] = 0;
memset(track->data[i],0,track->sectorsize);
}
else if (sectype == 1)
{
track->validsector[i] = 1;
my_fread(track->data[i],track->sectorsize,fpin,tr);
}
else if (sectype == 2)
{
my_fread(&fill,1,fpin,tr);
memset(track->data[i],fill,track->sectorsize);
}
}
return(track);
}
/************************************************************************/
void imd_track_free(struct track *track)
{
int i;
assert(track != NULL);
assert(track->sectormap != NULL);
assert(track->data != NULL);
for (i = 0 ; i < track->sectors ; i++)
{
assert(track->data[i] != NULL);
free(track->data[i]);
}
free(track->data);
if (track->headmap) free(track->headmap);
if (track->cylindermap) free(track->cylindermap);
free(track->validsector);
free(track->sectormap);
free(track);
}
/**************************************************************************/