11/*
22 * IMD -> DSK (pure data) file converter
33 *
4- * Copyright (c) 2024 Tony Lawrence
4+ * Copyright (c) 2024-2025 Tony Lawrence
55 *
66 * Redistribution and use in source and binary forms, with or
77 * without modification, are permitted provided that the
4040
4141#include <assert.h>
4242#include <ctype.h>
43+ #include <errno.h>
4344#include <stdio.h>
4445#include <stdint.h>
4546#include <stdlib.h>
@@ -69,8 +70,8 @@ typedef int32_t int4;
6970/* IMD track header */
7071PACKED (struct S_IMDTrkHdr {
7172 uint1 mode ; /* Track write mode (check only) */
72- uint1 cyl ; /* Cylinder # */
73- uint1 head ; /* Head (side) 0|1 and map flags */
73+ uint1 cyl ; /* Physical cylinder # */
74+ uint1 head ; /* Phys head (side) 0|1 and map flags*/
7475 uint1 nsect ; /* Number of sectors to follow */
7576 uint1 ssize ; /* Sector size or 0xFF for size tbl */
7677});
@@ -189,7 +190,7 @@ static int/*bool*/ x_skip_sector(FILE* fp, uint2 ssize)
189190 return 0 /*false*/ ;
190191 if (ch < 0 || ch > 8 )
191192 return 0 /*false*/ ;
192- if (ch == 0 )
193+ if (! ch )
193194 return 1 /*true*/ ;
194195 return fseek (fp , ch & 1 ? ssize : 1 , SEEK_CUR ) == 0 ? 1 /*T*/ : 0 /*F*/ ;
195196}
@@ -200,8 +201,15 @@ static int cyls = 0;
200201static int heads = 0 ;
201202static int sectors = 0 ;
202203static int sector_size = 0 ;
204+ static uint1 sector_filler = 0 ;
205+ static uint1 sector [SECTOR_SIZE_MAX ];
206+
207+ #define DA (C , H , S ) (((C) * heads + (H)) * sectors + (S) - one_based)
208+ #define DA_OFFSET (da ) ((da) * sector_size)
209+
203210
204211/* Sector numbering */
212+ static int no_maps = 0 ; /* =1 no cyl/head maps; =2 no sector maps, either */
205213static int max_sect = 0 ;
206214static int zero_sect = 0 ;
207215static int one_based = 1 ;
@@ -211,7 +219,6 @@ static int one_based = 1;
211219static int x_scan_tracks (FILE * fp , const char * file )
212220{
213221 const char * problem = 0 ;
214- uint1 smap [256 ];
215222 char buf [80 ];
216223 int track ;
217224
@@ -259,23 +266,29 @@ static int x_scan_tracks(FILE* fp, const char* file)
259266 }
260267 if (heads <= n )
261268 heads ++ ;
269+ if (cyls <= hdr .cyl )
270+ cyls = hdr .cyl + 1 ;
262271 if (!hdr .nsect )
263272 continue ;
264273 if (sectors < hdr .nsect )
265274 sectors = hdr .nsect ;
266- if (fread (smap , hdr .nsect , 1 , fp ) != 1 ) {
267- problem = "Cannot read sector map" ;
268- goto out ;
269- }
270- for (n = 0 ; n < hdr .nsect ; ++ n ) {
271- if (!smap [n ]) {
272- ++ zero_sect ;
273- continue ;
275+ if (no_maps < 2 ) {
276+ uint1 smap [256 ];
277+ if (fread (smap , hdr .nsect , 1 , fp ) != 1 ) {
278+ problem = "Cannot read sector map" ;
279+ goto out ;
274280 }
275- if (max_sect < smap [n ])
276- max_sect = smap [n ];
277- }
278- skip = 0 ;
281+ for (n = 0 ; n < hdr .nsect ; ++ n ) {
282+ if (!smap [n ]) {
283+ ++ zero_sect ;
284+ continue ;
285+ }
286+ if (max_sect < smap [n ])
287+ max_sect = smap [n ];
288+ }
289+ skip = 0 ;
290+ } else
291+ skip = hdr .nsect ;
279292 if (hdr .head & SECTOR_CYL_MAP )
280293 skip += hdr .nsect ;
281294 if (hdr .head & SECTOR_HEAD_MAP )
@@ -349,14 +362,13 @@ static int/*bool*/ x_extract_sector(int C, int H, int S, int track,
349362 FILE * in , const char * infile ,
350363 FILE * out , const char * outfile )
351364{
352- static uint1 sector [SECTOR_SIZE_MAX ];
353365 int /*bool*/ duplicate = 0 /*false*/ ;
354366 const char * problem = 0 ;
355367 const char * file = 0 ;
356368 int ch ;
357369
358370 /* Disk Address */
359- int da = ( C * heads + H ) * sectors + S - one_based ;
371+ long da = DA ( C , H , S ) ;
360372 assert (0 <= da && da < cyls * heads * sectors );
361373
362374 if (map [da >> 3 ] & (1 << (da & 7 ))) {
@@ -377,17 +389,17 @@ static int/*bool*/ x_extract_sector(int C, int H, int S, int track,
377389 case 0 :
378390 problem = "Sector data unavailable" ;
379391 break ;
380- case 1 : case 2 :
392+ case 2 : case 1 :
381393 /* normal sector data */
382394 assert (!problem );
383395 break ;
384- case 3 : case 4 :
396+ case 4 : case 3 :
385397 problem = "Deleted data" ;
386398 break ;
387- case 5 : case 6 :
399+ case 6 : case 5 :
388400 problem = "Sector data with error" ;
389401 break ;
390- case 7 : case 8 :
402+ case 8 : case 7 :
391403 problem = "Deleted data with error" ;
392404 break ;
393405 default :
@@ -412,14 +424,14 @@ static int/*bool*/ x_extract_sector(int C, int H, int S, int track,
412424 file = infile ;
413425 goto out ;
414426 }
415- } /* else: technically it's still a "compressed" sector */
427+ } else /* technically it's still a "compressed" sector */
428+ ch = sector_filler ;
416429 memset (sector , ch , sector_size );
417430 if (!duplicate )
418431 ++ n_compressed ;
419432 }
420433
421- da *= sector_size ;
422- if (fseek (out , da , SEEK_SET ) != 0 ) {
434+ if (fseek (out , DA_OFFSET (da ), SEEK_SET ) != 0 ) {
423435 problem = "File positioning error" ;
424436 file = outfile ;
425437 goto out ;
@@ -442,7 +454,7 @@ static int/*bool*/ x_extract_sector(int C, int H, int S, int track,
442454}
443455
444456
445- static int /*bool*/ x_extract_track (int track , int /*bool*/ no_map ,
457+ static int /*bool*/ x_extract_track (int track ,
446458 FILE * in , const char * infile ,
447459 FILE * out , const char * outfile )
448460{
@@ -466,12 +478,15 @@ static int/*bool*/ x_extract_track(int track, int/*bool*/ no_map,
466478 if (!hdr .nsect )
467479 return 1 /*true*/ ;
468480
469- if (fread (smap , hdr .nsect , 1 , in ) != 1 ) {
470- problem = "Cannot read sector map" ;
471- goto out ;
472- }
473- skip = 0 ;
474- if (no_map ) {
481+ if (no_maps < 2 ) {
482+ if (fread (smap , hdr .nsect , 1 , in ) != 1 ) {
483+ problem = "Cannot read sector map" ;
484+ goto out ;
485+ }
486+ skip = 0 ;
487+ } else
488+ skip = hdr .nsect ;
489+ if (no_maps ) {
475490 if (hdr .head & SECTOR_CYL_MAP )
476491 skip += hdr .nsect ;
477492 if (hdr .head & SECTOR_HEAD_MAP )
@@ -498,8 +513,8 @@ static int/*bool*/ x_extract_track(int track, int/*bool*/ no_map,
498513
499514 for (n = 0 ; n < hdr .nsect ; ++ n ) {
500515 int C = hdr .head & SECTOR_CYL_MAP ? cmap [n ] : hdr .cyl ;
501- int H = hdr .head & SECTOR_HEAD_MAP ? hmap [n ] : hdr .head & 0xF ;
502- int S = smap [n ];
516+ int H = hdr .head & SECTOR_HEAD_MAP ? hmap [n ] : hdr .head & 1 ;
517+ int S = no_maps < 2 ? smap [n ] : n + 1 ;
503518 if (verbose >= VERBOSE_SECTOR )
504519 fprintf (stderr , "Extracting: %d/%d/%d\n" , C , H , S );
505520 if (C < 0 || C >= cyls ) {
@@ -536,8 +551,9 @@ __attribute__((noreturn))
536551#endif
537552static void usage (const char * prog )
538553{
539- fprintf (stderr , "%s [-i] [-v...] infile outfile\n\n" , prog );
540- fprintf (stderr , "-i = Ignore cylinder / head maps\n"
554+ fprintf (stderr , "%s [-i] [-i] [-c val] [-v...] infile outfile\n\n" , prog );
555+ fprintf (stderr , "-i = Ignore cylinder / head maps; second -i: Ignore sector maps, too\n"
556+ "-c = Use 'val' as byte-filler in missing sectors (default: 0)\n"
541557 "-v = Increase verbosity with each occurrence\n" );
542558 exit (2 );
543559}
@@ -554,8 +570,6 @@ static void usage(const char* prog)
554570
555571int main (int argc , char * argv [])
556572{
557- /* whether to ignore cyl / head maps */
558- int /*bool*/ no_map = 0 /*false*/ ;
559573 const char * infile ;
560574 const char * outfile ;
561575 int p , q , tracks ;
@@ -570,11 +584,20 @@ int main(int argc, char* argv[])
570584 ++ verbose ;
571585 continue ;
572586 }
587+ if (strcmp (argv [p ], "-c" ) == 0 ) {
588+ char * end ;
589+ errno = 0 ;
590+ if (sector_filler || !argv [++ p ] ||
591+ !(sector_filler = strtol (argv [p ], & end , 0 )) || errno || * end ) {
592+ usage (argv [0 ]);
593+ }
594+ continue ;
595+ }
573596 if (strcmp (argv [p ], "-i" ) != 0 )
574597 break ;
575- if (no_map )
598+ if (no_maps > 1 )
576599 usage (argv [0 ]);
577- no_map = 1 /*ignore map*/ ;
600+ ++ no_maps ;
578601 } while (argv [++ p ]);
579602 }
580603 if (p < argc && strcmp (argv [p ], "--" ) == 0 )
@@ -602,7 +625,7 @@ int main(int argc, char* argv[])
602625 assert (heads <= 2 && sectors <= 255 && sector_size <= SECTOR_SIZE_MAX );
603626
604627 if (heads <= 0 || sectors <= 0 || sector_size <= 0
605- || ( cyls = (tracks + heads - 1 ) / heads ) <= 0 || 255 < cyls ) {
628+ || cyls < (tracks + heads - 1 ) / heads || 255 < cyls ) {
606629 fprintf (stderr , "%s: Failed to determine disk geometry, sorry\n" , infile );
607630 return EXIT_FAILURE ;
608631 }
@@ -633,10 +656,12 @@ int main(int argc, char* argv[])
633656 }
634657
635658 for (p = 0 ; p < tracks ; ++ p ) {
636- if (!x_extract_track (p , no_map , in , infile , out , outfile ))
659+ if (!x_extract_track (p , in , infile , out , outfile ))
637660 return EXIT_FAILURE ;
638661 }
639662
663+ if (sector_filler )
664+ memset (sector , sector_filler , sector_size );
640665 for (p = 0 ; p < q ; p += 8 ) {
641666 int k , n = p >> 3 ;
642667 if (map [n ] == (1 << 8 ) - 1 )
@@ -651,8 +676,17 @@ int main(int argc, char* argv[])
651676 S %= sectors ;
652677 C = H / heads ;
653678 H %= heads ;
679+ S += one_based ;
654680 fprintf (stderr , "%s: WARNING -- Sector not stored: %d/%d/%d\n" ,
655- outfile , C , H , S + one_based );
681+ outfile , C , H , S );
682+ if (sector_filler ) {
683+ long da = DA (C , H , S );
684+ assert (0 <= da && da < cyls * heads * sectors );
685+ if (fseek (out , DA_OFFSET (da ), SEEK_SET ) != 0
686+ || fwrite (sector , sector_size , 1 , out ) != 1 ) {
687+ fprintf (stderr , "%s: Error writing sector filler\n" , outfile );
688+ }
689+ }
656690 }
657691 }
658692
0 commit comments