commit 2781ab32ce207523441cbe4ecce967f408c86217
parent 03a8240a9cce607b8632178bb243a1d79f80e15e
Author: lostd <lostd@2f30.org>
Date:   Mon, 10 Aug 2015 18:07:46 +0300
Include ISO LBA fixer tool by DeXT
Diffstat:
3 files changed, 351 insertions(+), 1 deletion(-)
diff --git a/selfboot/Makefile b/selfboot/Makefile
@@ -1,6 +1,6 @@
 # dreamcast selfboot tools
 
-BINS = makeip scramble 1strdchk
+BINS = makeip scramble 1strdchk isofix
 
 all: $(BINS)
 
diff --git a/selfboot/isofix.c b/selfboot/isofix.c
@@ -0,0 +1,325 @@
+/******************************************************/
+/*                                                    */
+/*            ISO start LBA fixing utility            */
+/*                                                    */
+/* This tool will take an ISO image with PVD pointing */
+/* to bad DR offset and add padding data so actual DR */
+/* gets located in right absolute address.            */
+/*                                                    */
+/* Original boot area, PVD, SVD and VDT are copied to */
+/* the start of new, fixed ISO image.                 */
+/*                                                    */
+/* Supported input image formats are: 2048, 2336,     */
+/* 2352 and 2056 bytes per sector. All of them are    */
+/* converted to 2048 bytes per sector when writing    */
+/* excluding 2056 format which is needed by Mac users.*/
+/*                                                    */
+/******************************************************/
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "isofix.h"
+
+
+int main( int argc, char **argv )
+{
+	int sector_size = 2048, mode = 1;
+	long image_length, remaining_length, progress, last_pos, start_lba, i;
+	char lba_parameter = 0;
+
+	char destfname[256];
+	char string[256];
+	char buffer[4096];
+
+	struct opts_s opts = { false, false, false, false, false };
+
+	FILE *fsource, *fdest, *fboot, *fheader;
+
+
+printf("ISO LBA fixer 1.3 - (C) 2001 by DeXT\n\n");
+
+// process command line
+
+strcpy(destfname,"fixed.iso");
+
+if (argc < 2)
+   opts.askforimage = true;
+else
+   {
+   for (i = 1; i < argc; i++)
+       {
+       if (atol(argv[i]) <= 0)    // not a number, or negative one
+          {
+          if (!stricmp(argv[i], "/boot"))
+             {
+             opts.extractbootonly = true;
+             if (i == 1) opts.askforimage = true;
+             }
+          else if (!stricmp(argv[i], "/header"))
+             {
+             opts.extractheaderonly = true;
+             if (i == 1) opts.askforimage = true;
+             }
+          else if (!stricmp(argv[i], "/mac"))
+             {
+             opts.macformat = true;
+             if (i == 1) opts.askforimage = true;
+             }
+          else if (!stricmp(argv[i], "/iso"))
+             {
+             opts.isoformat = true;
+             if (i == 1) opts.askforimage = true;
+             }
+          else
+             {
+             if (i == 1) strcpy(string, argv[i]);
+             else strcpy(destfname, argv[i]);
+             }
+          }
+       else lba_parameter = i;
+       }
+   }
+
+if (opts.askforimage == true)
+   {
+   printf("\nPlease enter name of image to fix (Return to exit): ");
+   gets(string);
+   if (strlen(string) == 0) exit(1);
+   }
+
+printf("Processing file: '%s'\n",string);
+
+fsource = fopen(string,"rb");
+
+if (fsource == NULL) { printf("Image not found!"); exit(1); }
+
+fseek(fsource, 0L, SEEK_END);
+image_length = ftell(fsource);
+fseek(fsource, 0L, SEEK_SET);
+
+// detect format
+
+printf("Scanning image...\n");
+
+fread(buffer, 1, 16, fsource);
+if (!memcmp(SYNC_DATA, buffer, 12)) // raw (2352)
+   {
+   sector_size = 2352;
+   switch(buffer[15])
+         {
+         case 2: mode = 2; break;
+         case 1: mode = 1; break;
+         default: { printf("Unsupported track mode (%d)", buffer[15]); exit (1); }
+         }
+   if (seek_pvd(buffer, 2352, mode, fsource) == 0) { printf("Could not find PVD!\n"); exit(1); }
+   }
+else if (seek_pvd(buffer, 2048, 1, fsource))
+   {
+   sector_size = 2048;
+   mode = 1;
+   }
+else if (seek_pvd(buffer, 2336, 2, fsource))
+   {
+   sector_size = 2336;
+   mode = 2;
+   }
+else if (seek_pvd(buffer, 2056, 2, fsource))
+   {
+   sector_size = 2056;
+   mode = 2;
+   opts.macformat = true;
+   }
+else { printf("Could not find PVD!\n"); exit(1); }
+
+if (opts.isoformat == true) opts.macformat = false;
+
+printf("sector size = %d, mode = %d\n", sector_size, mode);
+
+if (opts.extractbootonly == false && opts.extractheaderonly == false)
+   {
+   if (lba_parameter != 0)
+      start_lba = atol(argv[lba_parameter]);
+   else
+      {
+      printf("\nPlease enter starting LBA value: ");
+      gets(string);
+      start_lba = atol(string);
+      if (start_lba <= 0) { printf("Bad LBA value"); exit(1); }
+      }
+
+   printf("Creating destination file '%s'...\n",destfname);
+   fdest = fopen(destfname, "wb");
+   if (fdest == NULL) { printf("Can't open destination file!"); exit(1); }
+   }
+
+if (opts.extractheaderonly == false || (opts.extractheaderonly == true && opts.extractbootonly == true))
+   {
+   printf("Saving boot area to file 'bootfile.bin'...\n");
+   fboot = fopen("bootfile.bin", "wb");
+   }
+if (opts.extractbootonly == false || (opts.extractheaderonly == true && opts.extractbootonly == true))
+   {
+   printf("Saving ISO header to file 'header.iso'...\n");
+   fheader = fopen("header.iso", "wb");
+   }
+
+// save boot area
+
+fseek(fsource, 0L, SEEK_SET);
+for (i = 0; i < 16 ; i++)
+    {
+    sector_read(buffer, sector_size, mode, fsource);
+    if (opts.extractbootonly == false && opts.extractheaderonly == false)
+       {
+       if (opts.macformat == true) fwrite (SUB_HEADER, 8, 1, fdest);
+       fwrite(buffer, 2048, 1, fdest);
+       }
+    if (opts.extractheaderonly == false || (opts.extractheaderonly == true && opts.extractbootonly == true))
+       {
+       if (opts.macformat == true) fwrite (SUB_HEADER, 8, 1, fboot);
+       fwrite(buffer, 2048, 1, fboot);
+       }
+    if (opts.extractbootonly == false || (opts.extractheaderonly == true && opts.extractbootonly == true))
+       {
+       if (opts.macformat == true) fwrite (SUB_HEADER, 8, 1, fheader);
+       fwrite(buffer, 2048, 1, fheader);
+       }
+    }
+
+if (opts.extractheaderonly == false || (opts.extractheaderonly == true && opts.extractbootonly == true))
+   fclose(fboot);
+if (opts.extractbootonly == true && opts.extractheaderonly == false) exit(0); // boot saved, exit
+
+// seek & copy pvd etc.
+
+last_pos = ftell(fsource); // start of pvd
+
+do {
+   sector_read(buffer, sector_size, mode, fsource);
+
+   if      (!memcmp(PVD_STRING, buffer, 8)) { printf("Found PVD at sector %ld\n", last_pos/sector_size); }
+   else if (!memcmp(SVD_STRING, buffer, 8)) { printf("Found SVD at sector %ld\n", last_pos/sector_size); }
+   else if (!memcmp(VDT_STRING, buffer, 8)) { printf("Found VDT at sector %ld\n", last_pos/sector_size); opts.last_vd = true; }
+   else    { printf("Error: Found unknown Volume Descriptor"); exit(1); }
+
+   if (opts.extractbootonly == false && opts.extractheaderonly == false)
+      {
+      if (opts.macformat == true) fwrite (SUB_HEADER, 8, 1, fdest);
+      fwrite(buffer, 2048, 1, fdest);
+      }
+   if (opts.macformat == true) fwrite (SUB_HEADER, 8, 1, fheader);
+   fwrite(buffer, 2048, 1, fheader);
+   last_pos = ftell(fsource);
+   }
+   while (opts.last_vd == false);
+
+// add padding data to header file
+
+for(i = 0; i < (long)sizeof(buffer); i++)  // clear buffer
+   buffer[i] = 0;
+
+remaining_length = 300 - (last_pos/sector_size);
+for(i = 0; i < remaining_length; i++)
+   {
+   if (opts.macformat == true) fwrite (SUB_HEADER, 8, 1, fheader);
+   fwrite(buffer, 2048, 1, fheader);
+   }
+
+fclose(fheader);
+if (opts.extractheaderonly == true) exit(0); // header saved, exit
+
+// add padding data to iso image
+
+if (last_pos > start_lba*sector_size)
+   { printf("Sorry, LBA value is too small...\nIt should be at least %d for current ISO image (probably greater)", last_pos/sector_size); exit(1); }
+if (start_lba < 11700)
+   printf("Warning! LBA value should be greater or equal to 11700 for multisession images\n");
+
+printf("Adding padding data up to start LBA value...");
+
+remaining_length = start_lba - (last_pos/sector_size);
+
+printf("   ");
+for(i = 0; i < remaining_length; i++)
+   {
+   if (!(i%512))
+      {
+      progress = i*100/remaining_length;
+      printf("\b\b\b%02d%%", progress);
+      }
+   if (opts.macformat == true) fwrite (SUB_HEADER, 8, 1, fdest);
+   if (!fwrite(buffer, 2048, 1, fdest))  { printf("\nCan't write file! (disk full?)"); exit(1); }
+   }
+printf("\b\b\b   \b\b\b");
+
+printf("Done!\n");
+
+// append original iso image
+
+printf("Appending ISO image...");
+
+fseek(fsource, 0L, SEEK_SET);
+
+remaining_length = image_length/sector_size;
+
+printf("   ");
+for(i = 0; i < remaining_length; i++)
+   {
+   if (!(i%512))
+      {
+      progress = i*100/remaining_length;
+      printf("\b\b\b%02d%%", progress);
+      }
+      if (!sector_read(buffer, sector_size, mode, fsource)) { printf("\nCan't read image!"); exit(1); }
+      if (opts.macformat == true) fwrite (SUB_HEADER, 8, 1, fdest);
+      if (!fwrite(buffer, 2048, 1, fdest))  { printf("\nCan't write file! (disk full?)"); exit(1); }
+   }
+printf("\b\b\b   \b\b\b");
+
+printf("Done!\n");
+
+printf("\nImage is now fixed!\n");
+
+fclose(fsource);
+fclose(fdest);
+
+return 0;
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+
+// seek_pvd() will search for valid PVD in sector 16 of source image
+
+int seek_pvd(char *buffer, int sector_size, int mode, FILE *fsource)
+{
+   fseek(fsource, 0L, SEEK_SET);   
+   fseek(fsource, 16*sector_size, SEEK_CUR);              // boot area
+   if (sector_size == 2352) fseek(fsource, 16, SEEK_CUR); // header
+   if (mode == 2) fseek(fsource, 8, SEEK_CUR);            // subheader
+   fread(buffer, 1, 8, fsource);
+   if (!memcmp(PVD_STRING, buffer, 8)) return 1;
+
+return 0;
+}
+
+// sector_read() will put user data into buffer no matter the source format
+
+int sector_read(char *buffer, int sector_size, int mode, FILE *fsource)
+{
+int status;
+
+   if (sector_size == 2352) fseek(fsource, 16, SEEK_CUR); // header
+   if (mode == 2) fseek(fsource, 8, SEEK_CUR);            // subheader
+   status = fread(buffer, 2048, 1, fsource);
+   if (sector_size >= 2336)
+      {
+      fseek(fsource, 280, SEEK_CUR);
+      if (mode == 1) fseek(fsource, 8, SEEK_CUR);
+      }
+
+return status;
+}
+
diff --git a/selfboot/isofix.h b/selfboot/isofix.h
@@ -0,0 +1,25 @@
+#ifdef __linux__
+  #define stricmp strcasecmp
+#endif
+
+
+typedef enum bool_t { false, true } bool;
+
+struct opts_s {
+              bool last_vd;
+              bool askforimage;
+              bool extractbootonly;
+              bool extractheaderonly;
+              bool macformat;
+              bool isoformat;
+              };
+
+static const char PVD_STRING[8] = { 0x01, 0x43, 0x44, 0x30, 0x30, 0x31, 0x01, 0 }; //"\x01" "CD001" "\x01" "\0";
+static const char SVD_STRING[8] = { 0x02, 0x43, 0x44, 0x30, 0x30, 0x31, 0x01, 0 }; //"\x02" "CD001" "\x01" "\0";
+static const char VDT_STRING[8] = { 0xff, 0x43, 0x44, 0x30, 0x30, 0x31, 0x01, 0 }; //"\xFF" "CD001" "\x01" "\0";
+static const char SYNC_DATA[12] = { 0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0 };
+static const char SUB_HEADER[8] = { 0, 0, 0x08, 0, 0, 0, 0x08, 0 };
+
+int seek_pvd(char *buffer, int sector_size, int mode, FILE *fsource);
+int sector_read(char *buffer, int sector_size, int mode, FILE *fsource);
+