OMGWTFBBQ!!!! We can now boot our ISOs on UEFI systems!!
authorHermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
Wed, 9 Sep 2015 02:11:49 +0000 (02:11 +0000)
committerHermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
Wed, 9 Sep 2015 02:11:49 +0000 (02:11 +0000)
Thanks gigaherz for the "fatten" utility!, and others for testing.

[CDMAKE]
- Add multi-boot CD support, following El-Torito specification, such that we can the usual ISO boot sector on BIOS-based PCs, and the UEFI loader on UEFI-based PCs.
- Load segment should be stored in little endian.
- Fix the computation of the sector count (count in 512 byte sectors and rounded up).
- Rework the command-line options to make them more compatible with CDIMAGE / OSCDIMG.
CORE-10120

[BOOTDATA]
- Activate the UEFI boot support for our ISOs.

svn path=/trunk/; revision=69139

reactos/boot/CMakeLists.txt
reactos/tools/cdmake/cdmake.c
reactos/tools/cdmake/config.h
reactos/tools/cdmake/dirhash.c
reactos/tools/cdmake/dirhash.h

index 607d0f1..dd6f3c1 100644 (file)
@@ -16,7 +16,7 @@ else()
 endif()
 
 add_custom_target(efisys
 endif()
 
 add_custom_target(efisys
-    COMMAND native-fatten ${CMAKE_CURRENT_BINARY_DIR}/efisys.bin -format 2880 -boot ${CMAKE_CURRENT_BINARY_DIR}/freeldr/bootsect/fat.bin -mkdir EFI -mkdir EFI/BOOT -add $<TARGET_FILE:bootmgfw> EFI/BOOT/boot${EFI_PLATFORM_ID}.EFI
+    COMMAND native-fatten ${CMAKE_CURRENT_BINARY_DIR}/efisys.bin -format 2880 -boot ${CMAKE_CURRENT_BINARY_DIR}/freeldr/bootsect/fat.bin -mkdir EFI -mkdir EFI/BOOT -add $<TARGET_FILE:bootmgfw> EFI/BOOT/boot${EFI_PLATFORM_ID}.efi
     DEPENDS native-fatten bootmgfw fat
     VERBATIM)
 
     DEPENDS native-fatten bootmgfw fat
     VERBATIM)
 
@@ -25,8 +25,7 @@ add_custom_target(efisys
 file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/bootcd.lst "")
 
 add_custom_target(bootcd
 file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/bootcd.lst "")
 
 add_custom_target(bootcd
-#    COMMAND native-cdmake -j -m -bootdata:2\#p0,e,b${CMAKE_CURRENT_BINARY_DIR}/freeldr/bootsect/isoboot.bin\#pEF,e,b${CMAKE_CURRENT_BINARY_DIR}/efisys.bin @${CMAKE_CURRENT_BINARY_DIR}/bootcd.lst REACTOS ${REACTOS_BINARY_DIR}/bootcd.iso
-    COMMAND native-cdmake -j -m -b ${CMAKE_CURRENT_BINARY_DIR}/freeldr/bootsect/isoboot.bin @${CMAKE_CURRENT_BINARY_DIR}/bootcd.lst REACTOS ${REACTOS_BINARY_DIR}/bootcd.iso
+    COMMAND native-cdmake -j -m -bootdata:2\#p0,e,b${CMAKE_CURRENT_BINARY_DIR}/freeldr/bootsect/isoboot.bin\#pEF,e,b${CMAKE_CURRENT_BINARY_DIR}/efisys.bin @${CMAKE_CURRENT_BINARY_DIR}/bootcd.lst REACTOS ${REACTOS_BINARY_DIR}/bootcd.iso
     DEPENDS native-cdmake efisys
     VERBATIM)
 
     DEPENDS native-cdmake efisys
     VERBATIM)
 
@@ -35,8 +34,8 @@ add_custom_target(bootcd
 file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/bootcdregtest.lst "")
 
 add_custom_target(bootcdregtest
 file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/bootcdregtest.lst "")
 
 add_custom_target(bootcdregtest
-    COMMAND native-cdmake -j -m -b ${CMAKE_CURRENT_BINARY_DIR}/freeldr/bootsect/isobtrt.bin @${CMAKE_CURRENT_BINARY_DIR}/bootcdregtest.lst REACTOS ${REACTOS_BINARY_DIR}/bootcdregtest.iso
-    DEPENDS native-cdmake
+    COMMAND native-cdmake -j -m -bootdata:2\#p0,e,b${CMAKE_CURRENT_BINARY_DIR}/freeldr/bootsect/isobtrt.bin\#pEF,e,b${CMAKE_CURRENT_BINARY_DIR}/efisys.bin @${CMAKE_CURRENT_BINARY_DIR}/bootcdregtest.lst REACTOS ${REACTOS_BINARY_DIR}/bootcdregtest.iso
+    DEPENDS native-cdmake efisys
     VERBATIM)
 
 ##livecd
     VERBATIM)
 
 ##livecd
@@ -49,8 +48,8 @@ file(APPEND ${CMAKE_CURRENT_BINARY_DIR}/livecd.lst "Profiles/Default User/Favori
 file(APPEND ${CMAKE_CURRENT_BINARY_DIR}/livecd.lst "Profiles/Default User/Start Menu/Programs\n")
 
 add_custom_target(livecd
 file(APPEND ${CMAKE_CURRENT_BINARY_DIR}/livecd.lst "Profiles/Default User/Start Menu/Programs\n")
 
 add_custom_target(livecd
-    COMMAND native-cdmake -j -m -b ${CMAKE_CURRENT_BINARY_DIR}/freeldr/bootsect/isoboot.bin @${CMAKE_CURRENT_BINARY_DIR}/livecd.lst REACTOS ${REACTOS_BINARY_DIR}/livecd.iso
-    DEPENDS native-cdmake
+    COMMAND native-cdmake -j -m -bootdata:2\#p0,e,b${CMAKE_CURRENT_BINARY_DIR}/freeldr/bootsect/isoboot.bin\#pEF,e,b${CMAKE_CURRENT_BINARY_DIR}/efisys.bin @${CMAKE_CURRENT_BINARY_DIR}/livecd.lst REACTOS ${REACTOS_BINARY_DIR}/livecd.iso
+    DEPENDS native-cdmake efisys
     VERBATIM)
 
 ##hybridcd
     VERBATIM)
 
 ##hybridcd
@@ -63,11 +62,10 @@ file(APPEND ${CMAKE_CURRENT_BINARY_DIR}/hybridcd.lst "Profiles/Default User/Favo
 file(APPEND ${CMAKE_CURRENT_BINARY_DIR}/hybridcd.lst "livecd/Profiles/Default User/Start Menu/Programs\n")
 
 add_custom_target(hybridcd
 file(APPEND ${CMAKE_CURRENT_BINARY_DIR}/hybridcd.lst "livecd/Profiles/Default User/Start Menu/Programs\n")
 
 add_custom_target(hybridcd
-    COMMAND native-cdmake -j -m -b ${CMAKE_CURRENT_BINARY_DIR}/freeldr/bootsect/isoboot.bin @${CMAKE_CURRENT_BINARY_DIR}/hybridcd.lst REACTOS ${REACTOS_BINARY_DIR}/hybridcd.iso
-    DEPENDS native-cdmake bootcd livecd
+    COMMAND native-cdmake -j -m -bootdata:2\#p0,e,b${CMAKE_CURRENT_BINARY_DIR}/freeldr/bootsect/isoboot.bin\#pEF,e,b${CMAKE_CURRENT_BINARY_DIR}/efisys.bin @${CMAKE_CURRENT_BINARY_DIR}/hybridcd.lst REACTOS ${REACTOS_BINARY_DIR}/hybridcd.iso
+    DEPENDS native-cdmake efisys bootcd livecd
     VERBATIM)
 
 add_subdirectory(freeldr)
 add_subdirectory(bootdata)
 add_subdirectory(environ)
     VERBATIM)
 
 add_subdirectory(freeldr)
 add_subdirectory(bootdata)
 add_subdirectory(environ)
-
index 04d5866..5fcaaf6 100644 (file)
@@ -68,6 +68,7 @@
 #include "config.h"
 #include "dirhash.h"
 
 #include "config.h"
 #include "dirhash.h"
 
+// FIXME! FIXME! Do it in a portable way!!
 typedef unsigned char BYTE;
 typedef unsigned short WORD;
 typedef unsigned long DWORD;
 typedef unsigned char BYTE;
 typedef unsigned short WORD;
 typedef unsigned long DWORD;
@@ -83,8 +84,8 @@ typedef int BOOL;
 #define SECTOR_SIZE             2048
 #define BUFFER_SIZE             (8 * SECTOR_SIZE)
 
 #define SECTOR_SIZE             2048
 #define BUFFER_SIZE             (8 * SECTOR_SIZE)
 
-const BYTE HIDDEN_FLAG    = 1;
-const BYTE DIRECTORY_FLAG = 2;
+#define HIDDEN_FLAG     1
+#define DIRECTORY_FLAG  2
 
 
 struct cd_image
 
 
 struct cd_image
@@ -97,6 +98,35 @@ struct cd_image
     BYTE *buffer;
 };
 
     BYTE *buffer;
 };
 
+typedef struct _boot_validation_header
+{
+    BYTE  header_id;
+    BYTE  platform_id;
+} BOOT_VALIDATION_HEADER, *PBOOT_VALIDATION_HEADER;
+
+typedef struct boot_entry
+{
+    struct boot_entry *next_entry;
+    BYTE  boot_id;
+    BYTE  boot_emu_type;
+    WORD  load_segment;
+    BYTE  system_type;
+    WORD  sector_count; // boot_image_size
+    DWORD load_rba;     // boot_image_sector
+    // BYTE  unused[20];
+    char bootimage[512];
+} BOOT_ENTRY, *PBOOT_ENTRY;
+
+typedef struct boot_header
+{
+    struct boot_header *next_header;
+    BYTE  header_id;
+    BYTE  platform_id;
+    WORD  num_entries;
+    // char  id_string[28];
+    PBOOT_ENTRY entry_list;
+} BOOT_HEADER, *PBOOT_HEADER;
+
 typedef struct date_and_time
 {
     BYTE second;
 typedef struct date_and_time
 {
     BYTE second;
@@ -166,11 +196,12 @@ DWORD unused_bytes_at_ends_of_files;
 DWORD number_of_directories;
 DWORD bytes_in_directories;
 
 DWORD number_of_directories;
 DWORD bytes_in_directories;
 
-BOOL eltorito;
+BOOL eltorito;   // TRUE/FALSE: bootable/non-bootable CD-ROM
+BOOL multi_boot; // TRUE/FALSE: multi/single-boot CD-ROM
 DWORD boot_catalog_sector;
 DWORD boot_catalog_sector;
-DWORD boot_image_sector;
-WORD boot_image_size;  // counted in 512 byte sectors
-char bootimage[512];
+BOOT_VALIDATION_HEADER boot_validation_header;
+BOOT_ENTRY default_boot_entry;
+PBOOT_HEADER boot_header_list;
 
 BOOL joliet;
 DWORD joliet_path_table_size;
 
 BOOL joliet;
 DWORD joliet_path_table_size;
@@ -213,10 +244,24 @@ This function releases all allocated memory blocks.
 
 static void release_memory(void)
 {
 
 static void release_memory(void)
 {
+    while (boot_header_list)
+    {
+        PBOOT_HEADER next_header = boot_header_list->next_header;
+
+        while (boot_header_list->entry_list)
+        {
+            PBOOT_ENTRY next_entry = boot_header_list->entry_list->next_entry;
+            free(boot_header_list->entry_list);
+            boot_header_list->entry_list = next_entry;
+        }
+
+        free(boot_header_list);
+        boot_header_list = next_header;
+    }
+
     while (root.next_in_memory != NULL)
     {
     while (root.next_in_memory != NULL)
     {
-        struct directory_record *next =
-            root.next_in_memory->next_in_memory;
+        PDIR_RECORD next = root.next_in_memory->next_in_memory;
         if (joliet)
             free(root.next_in_memory->joliet_name);
         free(root.next_in_memory);
         if (joliet)
             free(root.next_in_memory->joliet_name);
         free(root.next_in_memory);
@@ -224,6 +269,7 @@ static void release_memory(void)
     }
     if (joliet)
         free(root.joliet_name);
     }
     if (joliet)
         free(root.joliet_name);
+
     if (cd.buffer != NULL)
     {
         free(cd.buffer);
     if (cd.buffer != NULL)
     {
         free(cd.buffer);
@@ -236,7 +282,7 @@ This function edits and displays an error message and then jumps back to the
 error exit point in main().
 -----------------------------------------------------------------------------*/
 
 error exit point in main().
 -----------------------------------------------------------------------------*/
 
-void error_exit(const char* fmt, ...)
+static void error_exit(const char* fmt, ...)
 {
     va_list arg;
 
 {
     va_list arg;
 
@@ -356,7 +402,7 @@ static void write_string(char *s)
         write_byte(*s++);
 }
 
         write_byte(*s++);
 }
 
-static void write_bytecounted_string(unsigned bytecount, char *s)
+static void write_bytecounted_string(unsigned bytecount, char *s, char padding)
 {
     while (*s != 0 && bytecount != 0)
     {
 {
     while (*s != 0 && bytecount != 0)
     {
@@ -365,7 +411,7 @@ static void write_bytecounted_string(unsigned bytecount, char *s)
     }
     while (bytecount != 0)
     {
     }
     while (bytecount != 0)
     {
-        write_byte(' ');
+        write_byte(padding);
         bytecount--;
     }
 }
         bytecount--;
     }
 }
@@ -383,7 +429,7 @@ static void write_string_as_big_endian_unicode(char *s)
     }
 }
 
     }
 }
 
-static void write_bytecounted_string_as_big_endian_unicode(unsigned bytecount, char *s)
+static void write_bytecounted_string_as_big_endian_unicode(unsigned bytecount, char *s, char padding)
 {
     unsigned wordcount = bytecount / 2;
 
 {
     unsigned wordcount = bytecount / 2;
 
@@ -394,12 +440,12 @@ static void write_bytecounted_string_as_big_endian_unicode(unsigned bytecount, c
     }
     while (wordcount != 0)
     {
     }
     while (wordcount != 0)
     {
-        write_big_endian_word(' ');
+        write_big_endian_word(padding);
         wordcount--;
     }
 
     if (bytecount % 2 != 0)
         wordcount--;
     }
 
     if (bytecount % 2 != 0)
-        write_byte(' ');
+        write_byte(padding);
 }
 
 /*-----------------------------------------------------------------------------
 }
 
 /*-----------------------------------------------------------------------------
@@ -497,7 +543,7 @@ write_directory_record(PDIR_RECORD d,
     write_byte(d->flags);
     write_byte(0);    // file unit size for an interleaved file
     write_byte(0);    // interleave gap size for an interleaved file
     write_byte(d->flags);
     write_byte(0);    // file unit size for an interleaved file
     write_byte(0);    // interleave gap size for an interleaved file
-    write_both_endian_word((WORD) 1); // volume sequence number
+    write_both_endian_word(1); // volume sequence number
     write_byte((BYTE)identifier_size);
     switch (DirType)
     {
     write_byte((BYTE)identifier_size);
     switch (DirType)
     {
@@ -575,7 +621,7 @@ This function checks to see if there's a cdname conflict.
 #define strcasecmp stricmp
 #endif//_WIN32
 
 #define strcasecmp stricmp
 #endif//_WIN32
 
-BOOL cdname_exists(PDIR_RECORD d)
+static BOOL cdname_exists(PDIR_RECORD d)
 {
     PDIR_RECORD p = d->parent->first_record;
     while (p)
 {
     PDIR_RECORD p = d->parent->first_record;
     while (p)
@@ -589,7 +635,7 @@ BOOL cdname_exists(PDIR_RECORD d)
     return FALSE;
 }
 
     return FALSE;
 }
 
-void parse_filename_into_dirrecord(const char* filename, PDIR_RECORD d, BOOL dir)
+static void parse_filename_into_dirrecord(const char* filename, PDIR_RECORD d, BOOL dir)
 {
     const char *s = filename;
     char *t = d->name_on_cd;
 {
     const char *s = filename;
     char *t = d->name_on_cd;
@@ -608,7 +654,8 @@ void parse_filename_into_dirrecord(const char* filename, PDIR_RECORD d, BOOL dir
         if ((size_t)(t-d->name_on_cd) < sizeof(d->name_on_cd)-1)
             *t++ = check_for_punctuation(*s, filename);
         else if (!joliet)
         if ((size_t)(t-d->name_on_cd) < sizeof(d->name_on_cd)-1)
             *t++ = check_for_punctuation(*s, filename);
         else if (!joliet)
-        error_exit("'%s' is not ISO-9660, aborting...", filename);
+            error_exit("'%s' is not ISO-9660, aborting...", filename);
+
         if ((size_t)(n-d->name) < sizeof(d->name)-1)
             *n++ = *s;
         else if (!joliet)
         if ((size_t)(n-d->name) < sizeof(d->name)-1)
             *n++ = *s;
         else if (!joliet)
@@ -914,7 +961,7 @@ make_directory_records(PDIR_RECORD d)
                 else
                 {
                     if (!getcwd(buf, sizeof(buf)))
                 else
                 {
                     if (!getcwd(buf, sizeof(buf)))
-                        error_exit("Can't get CWD: %s\n", strerror(errno));
+                        error_exit("Cannot get CWD: %s\n", strerror(errno));
                     strcat(buf, DIR_SEPARATOR_STRING);
                     strcat(buf, source);
                     strcat(buf, entry->d_name);
                     strcat(buf, DIR_SEPARATOR_STRING);
                     strcat(buf, source);
                     strcat(buf, entry->d_name);
@@ -922,7 +969,7 @@ make_directory_records(PDIR_RECORD d)
 
                 if (stat(buf, &stbuf) == -1)
                 {
 
                 if (stat(buf, &stbuf) == -1)
                 {
-                    error_exit("Can't access '%s' (%s)\n", buf, strerror(errno));
+                    error_exit("Cannot access '%s' (%s)\n", buf, strerror(errno));
                     return;
                 }
 
                     return;
                 }
 
@@ -944,7 +991,7 @@ make_directory_records(PDIR_RECORD d)
     }
     else
     {
     }
     else
     {
-        error_exit("Can't open %s\n", source);
+        error_exit("Cannot open %s\n", source);
         return;
     }
 
         return;
     }
 
@@ -976,14 +1023,14 @@ make_directory_records(PDIR_RECORD d)
                     else
                     {
                         if (!getcwd(buf, sizeof(buf)))
                     else
                     {
                         if (!getcwd(buf, sizeof(buf)))
-                            error_exit("Can't get CWD: %s\n", strerror(errno));
+                            error_exit("Cannot get CWD: %s\n", strerror(errno));
                         strcat(buf, DIR_SEPARATOR_STRING);
                         strcat(buf, source);
                     }
 
                     if (stat(buf, &stbuf) == -1)
                     {
                         strcat(buf, DIR_SEPARATOR_STRING);
                         strcat(buf, source);
                     }
 
                     if (stat(buf, &stbuf) == -1)
                     {
-                        error_exit("Can't access '%s' (%s)\n", buf, strerror(errno));
+                        error_exit("Cannot access '%s' (%s)\n", buf, strerror(errno));
                         return;
                     }
                     new_d = new_directory_record(entry, &stbuf, d);
                         return;
                     }
                     new_d = new_directory_record(entry, &stbuf, d);
@@ -1004,7 +1051,7 @@ make_directory_records(PDIR_RECORD d)
     }
     else
     {
     }
     else
     {
-        error_exit("Can't open %s\n", source);
+        error_exit("Cannot open %s\n", source);
         return;
     }
 
         return;
     }
 
@@ -1028,7 +1075,7 @@ make_directory_records(PDIR_RECORD d)
             else
             {
                 if (!getcwd(buf, sizeof(buf)))
             else
             {
                 if (!getcwd(buf, sizeof(buf)))
-                    error_exit("Can't get CWD: %s\n", strerror(errno));
+                    error_exit("Cannot get CWD: %s\n", strerror(errno));
                 strcat(buf, DIR_SEPARATOR_STRING);
                 strcat(buf, source);
                 strcat(buf, entry->d_name);
                 strcat(buf, DIR_SEPARATOR_STRING);
                 strcat(buf, source);
                 strcat(buf, entry->d_name);
@@ -1036,7 +1083,7 @@ make_directory_records(PDIR_RECORD d)
 
             if (stat(buf, &stbuf) == -1)
             {
 
             if (stat(buf, &stbuf) == -1)
             {
-                error_exit("Can't access '%s' (%s)\n", buf, strerror(errno));
+                error_exit("Cannot access '%s' (%s)\n", buf, strerror(errno));
                 return;
             }
 
                 return;
             }
 
@@ -1087,7 +1134,7 @@ make_directory_records(PDIR_RECORD d)
     }
     else
     {
     }
     else
     {
-        error_exit("Can't open %s\n", source);
+        error_exit("Cannot open %s\n", source);
         return;
     }
 
         return;
     }
 
@@ -1172,18 +1219,18 @@ scan_specified_files(PDIR_RECORD d, struct target_dir_entry *dir)
                                          FILE_ATTRIBUTE_NORMAL,
                                          NULL)) == INVALID_HANDLE_VALUE)
             {
                                          FILE_ATTRIBUTE_NORMAL,
                                          NULL)) == INVALID_HANDLE_VALUE)
             {
-                error_exit("Can't open timestamp file %s\n", file->source_name);
+                error_exit("Cannot open timestamp file %s\n", file->source_name);
             }
 
             if (!get_cd_file_time(open_file, &d->date_and_time))
             {
             }
 
             if (!get_cd_file_time(open_file, &d->date_and_time))
             {
-                error_exit("Can't stat timestamp file %s\n", file->source_name);
+                error_exit("Cannot stat timestamp file %s\n", file->source_name);
             }
             CloseHandle(open_file);
 #else
             if (stat(file->target_name, &stbuf) == -1)
             {
             }
             CloseHandle(open_file);
 #else
             if (stat(file->target_name, &stbuf) == -1)
             {
-                error_exit("Can't stat timestamp file %s\n", file->source_name);
+                error_exit("Cannot stat timestamp file %s\n", file->source_name);
             }
             convert_date_and_time(&d->date_and_time, &stbuf.st_ctime);
 #endif
             }
             convert_date_and_time(&d->date_and_time, &stbuf.st_ctime);
 #endif
@@ -1208,15 +1255,15 @@ scan_specified_files(PDIR_RECORD d, struct target_dir_entry *dir)
                                          FILE_ATTRIBUTE_NORMAL,
                                          NULL)) == INVALID_HANDLE_VALUE)
             {
                                          FILE_ATTRIBUTE_NORMAL,
                                          NULL)) == INVALID_HANDLE_VALUE)
             {
-                error_exit("Can't open file %s\n", file->source_name);
+                error_exit("Cannot open file %s\n", file->source_name);
             }
             if (!get_cd_file_time(open_file, &new_d->date_and_time))
             {
             }
             if (!get_cd_file_time(open_file, &new_d->date_and_time))
             {
-                error_exit("Can't stat file %s\n", file->source_name);
+                error_exit("Cannot stat file %s\n", file->source_name);
             }
             if (!GetFileSizeEx(open_file, &file_size))
             {
             }
             if (!GetFileSizeEx(open_file, &file_size))
             {
-                error_exit("Can't get file size of %s\n", file->source_name);
+                error_exit("Cannot get file size of %s\n", file->source_name);
             }
             new_d->size = new_d->joliet_size = file_size.QuadPart;
             new_d->orig_name = file->source_name;
             }
             new_d->size = new_d->joliet_size = file_size.QuadPart;
             new_d->orig_name = file->source_name;
@@ -1224,7 +1271,7 @@ scan_specified_files(PDIR_RECORD d, struct target_dir_entry *dir)
 #else
             if (stat(file->source_name, &stbuf) == -1)
             {
 #else
             if (stat(file->source_name, &stbuf) == -1)
             {
-                error_exit("Can't find '%s' (target %s)\n",
+                error_exit("Cannot find '%s' (target %s)\n",
                            file->source_name,
                            file->target_name);
             }
                            file->source_name,
                            file->target_name);
             }
@@ -1296,24 +1343,32 @@ static void get_time_string(char *str)
 
 static BOOL write_from_file(FILE *file, DWORD size)
 {
 
 static BOOL write_from_file(FILE *file, DWORD size)
 {
-    int n;
-
-    fseek(file, 0, SEEK_SET);
-    while (size > 0)
+    if (cd.file != NULL)
     {
     {
-        n = BUFFER_SIZE - cd.count;
-        if ((DWORD)n > size)
-            n = size;
+        int n;
 
 
-        if (fread(cd.buffer + cd.count, n, 1, file) < 1)
-            return FALSE;
-
-        cd.count += n;
-        if (cd.count == BUFFER_SIZE)
-            flush_buffer();
-        cd.sector += n / SECTOR_SIZE;
-        cd.offset += n % SECTOR_SIZE;
-        size -= n;
+        fseek(file, 0, SEEK_SET);
+        while (size > 0)
+        {
+            n = BUFFER_SIZE - cd.count;
+            if ((DWORD)n > size)
+                n = size;
+
+            if (fread(cd.buffer + cd.count, n, 1, file) < 1)
+                return FALSE;
+
+            cd.count += n;
+            if (cd.count == BUFFER_SIZE)
+                flush_buffer();
+            cd.sector += n / SECTOR_SIZE;
+            cd.offset += n % SECTOR_SIZE;
+            size -= n;
+        }
+    }
+    else
+    {
+        cd.sector += size / SECTOR_SIZE;
+        cd.offset += size % SECTOR_SIZE;
     }
 
     return TRUE;
     }
 
     return TRUE;
@@ -1341,30 +1396,30 @@ static void pass(void)
 
     write_string("\1CD001\1");
     write_byte(0);
 
     write_string("\1CD001\1");
     write_byte(0);
-    write_bytecounted_string(32, "");           // system identifier
-    write_bytecounted_string(32, volume_label); // volume label
+    write_bytecounted_string(32, "", ' ');           // system identifier
+    write_bytecounted_string(32, volume_label, ' '); // volume label
 
     write_block(8, 0);
     write_both_endian_dword(total_sectors);
     write_block(32, 0);
 
     write_block(8, 0);
     write_both_endian_dword(total_sectors);
     write_block(32, 0);
-    write_both_endian_word((WORD) 1); // volume set size
-    write_both_endian_word((WORD) 1); // volume sequence number
-    write_both_endian_word((WORD) 2048); // sector size
+    write_both_endian_word(1); // volume set size
+    write_both_endian_word(1); // volume sequence number
+    write_both_endian_word(2048); // sector size
     write_both_endian_dword(path_table_size);
     write_little_endian_dword(little_endian_path_table_sector);
     write_both_endian_dword(path_table_size);
     write_little_endian_dword(little_endian_path_table_sector);
-    write_little_endian_dword((DWORD) 0);  // second little endian path table
+    write_little_endian_dword(0);  // second little endian path table
     write_big_endian_dword(big_endian_path_table_sector);
     write_big_endian_dword(big_endian_path_table_sector);
-    write_big_endian_dword((DWORD) 0);  // second big endian path table
+    write_big_endian_dword(0);  // second big endian path table
     write_directory_record(&root, DOT_RECORD, FALSE);
 
     write_directory_record(&root, DOT_RECORD, FALSE);
 
-    write_bytecounted_string(128, volume_label); // volume set identifier
-    write_bytecounted_string(128, PUBLISHER_ID); // publisher identifier
-    write_bytecounted_string(128, DATA_PREP_ID); // data preparer identifier
-    write_bytecounted_string(128, APP_ID);       // application identifier
+    write_bytecounted_string(128, volume_label, ' '); // volume set identifier
+    write_bytecounted_string(128, PUBLISHER_ID, ' '); // publisher identifier
+    write_bytecounted_string(128, DATA_PREP_ID, ' '); // data preparer identifier
+    write_bytecounted_string(128, APP_ID, ' ');       // application identifier
 
 
-    write_bytecounted_string(37, ""); // copyright file identifier
-    write_bytecounted_string(37, ""); // abstract file identifier
-    write_bytecounted_string(37, ""); // bibliographic file identifier
+    write_bytecounted_string(37, "", ' '); // copyright file identifier
+    write_bytecounted_string(37, "", ' '); // abstract file identifier
+    write_bytecounted_string(37, "", ' '); // bibliographic file identifier
 
     write_string(timestring);  // volume creation
     write_byte(0);
 
     write_string(timestring);  // volume creation
     write_byte(0);
@@ -1382,10 +1437,9 @@ static void pass(void)
     // Boot Volume Descriptor
     if (eltorito)
     {
     // Boot Volume Descriptor
     if (eltorito)
     {
-        write_byte(0);
+        write_byte(0);  // Boot record ID
         write_string("CD001\1");
         write_string("CD001\1");
-        write_string("EL TORITO SPECIFICATION");  // identifier
-        write_block(9, 0);  // padding
+        write_bytecounted_string(32, "EL TORITO SPECIFICATION", 0); // El-Torito identifier
         write_block(32, 0);  // unused
         write_little_endian_dword(boot_catalog_sector);  // pointer to boot catalog
         fill_sector();
         write_block(32, 0);  // unused
         write_little_endian_dword(boot_catalog_sector);  // pointer to boot catalog
         fill_sector();
@@ -1396,31 +1450,31 @@ static void pass(void)
     {
         write_string("\2CD001\1");
         write_byte(0);
     {
         write_string("\2CD001\1");
         write_byte(0);
-        write_bytecounted_string_as_big_endian_unicode(32, "");           // system identifier
-        write_bytecounted_string_as_big_endian_unicode(32, volume_label); // volume label
+        write_bytecounted_string_as_big_endian_unicode(32, "", ' ');           // system identifier
+        write_bytecounted_string_as_big_endian_unicode(32, volume_label, ' '); // volume label
 
         write_block(8, 0);
         write_both_endian_dword(total_sectors);
         write_string("%/E");
         write_block(29, 0);
 
         write_block(8, 0);
         write_both_endian_dword(total_sectors);
         write_string("%/E");
         write_block(29, 0);
-        write_both_endian_word((WORD) 1); // volume set size
-        write_both_endian_word((WORD) 1); // volume sequence number
-        write_both_endian_word((WORD) 2048); // sector size
+        write_both_endian_word(1); // volume set size
+        write_both_endian_word(1); // volume sequence number
+        write_both_endian_word(2048); // sector size
         write_both_endian_dword(joliet_path_table_size);
         write_little_endian_dword(joliet_little_endian_path_table_sector);
         write_both_endian_dword(joliet_path_table_size);
         write_little_endian_dword(joliet_little_endian_path_table_sector);
-        write_little_endian_dword((DWORD) 0);  // second little endian path table
+        write_little_endian_dword(0);  // second little endian path table
         write_big_endian_dword(joliet_big_endian_path_table_sector);
         write_big_endian_dword(joliet_big_endian_path_table_sector);
-        write_big_endian_dword((DWORD) 0);  // second big endian path table
+        write_big_endian_dword(0);  // second big endian path table
         write_directory_record(&root, DOT_RECORD, TRUE);
 
         write_directory_record(&root, DOT_RECORD, TRUE);
 
-        write_bytecounted_string_as_big_endian_unicode(128, volume_label); // volume set identifier
-        write_bytecounted_string_as_big_endian_unicode(128, PUBLISHER_ID); // publisher identifier
-        write_bytecounted_string_as_big_endian_unicode(128, DATA_PREP_ID); // data preparer identifier
-        write_bytecounted_string_as_big_endian_unicode(128, APP_ID);       // application identifier
+        write_bytecounted_string_as_big_endian_unicode(128, volume_label, ' '); // volume set identifier
+        write_bytecounted_string_as_big_endian_unicode(128, PUBLISHER_ID, ' '); // publisher identifier
+        write_bytecounted_string_as_big_endian_unicode(128, DATA_PREP_ID, ' '); // data preparer identifier
+        write_bytecounted_string_as_big_endian_unicode(128, APP_ID, ' ');       // application identifier
 
 
-        write_bytecounted_string_as_big_endian_unicode(37, ""); // copyright file identifier
-        write_bytecounted_string_as_big_endian_unicode(37, ""); // abstract file identifier
-        write_bytecounted_string_as_big_endian_unicode(37, ""); // bibliographic file identifier
+        write_bytecounted_string_as_big_endian_unicode(37, "", ' '); // copyright file identifier
+        write_bytecounted_string_as_big_endian_unicode(37, "", ' '); // abstract file identifier
+        write_bytecounted_string_as_big_endian_unicode(37, "", ' '); // bibliographic file identifier
 
         write_string(timestring);  // volume creation
         write_byte(0);
 
         write_string(timestring);  // volume creation
         write_byte(0);
@@ -1439,40 +1493,72 @@ static void pass(void)
     write_string("\377CD001\1");
     fill_sector();
 
     write_string("\377CD001\1");
     fill_sector();
 
-    // Boot Catalog
+    // Boot Catalog and Images
     if (eltorito)
     {
     if (eltorito)
     {
+        PBOOT_HEADER header;
+        PBOOT_ENTRY  entry;
+
+        // Boot Catalog
+
         boot_catalog_sector = cd.sector;
 
         boot_catalog_sector = cd.sector;
 
-        // Validation entry
-        write_byte(1);
-        write_byte(0);  // x86 boot code
+        // Validation entry header
+        write_byte(boot_validation_header.header_id);
+        write_byte(boot_validation_header.platform_id);
         write_little_endian_word(0);  // reserved
         write_little_endian_word(0);  // reserved
-        write_string("ReactOS Foundation");
-        write_block(6, 0); // padding
+        write_bytecounted_string(24, MANUFACTURER_ID, 0); // Manufacturer identifier
         write_little_endian_word(0x62E);  // checksum // FIXME: This is hardcoded!!
         write_little_endian_word(0xAA55);  // signature
 
         write_little_endian_word(0x62E);  // checksum // FIXME: This is hardcoded!!
         write_little_endian_word(0xAA55);  // signature
 
-        // default entry
-        write_byte(0x88);  // bootable
-        write_byte(0);  // no emulation
-        write_big_endian_word(0);  // load segment = default (0x07c0)
+        // Default entry
+        write_byte(default_boot_entry.boot_id);
+        write_byte(default_boot_entry.boot_emu_type);
+        write_little_endian_word(default_boot_entry.load_segment);
         write_byte(0);  // partition type
         write_byte(0);  // unused
         write_byte(0);  // partition type
         write_byte(0);  // unused
-        write_little_endian_word(boot_image_size);  // sector count
-        write_little_endian_dword(boot_image_sector);  // sector
+        write_little_endian_word(default_boot_entry.sector_count);
+        write_little_endian_dword(default_boot_entry.load_rba);
+        write_block(20, 0); // unused
+
+        // Loop through each boot header
+        header = boot_header_list;
+        while (header)
+        {
+            write_byte(header->header_id);
+            write_byte(header->platform_id);
+            write_little_endian_word(header->num_entries);
+            write_block(28, 0); // Identifier string (unused)
+
+            // Loop through each boot entry
+            entry = header->entry_list;
+            while (entry)
+            {
+                write_byte(entry->boot_id);
+                write_byte(entry->boot_emu_type);
+                write_little_endian_word(entry->load_segment);
+                write_byte(0);  // partition type
+                write_byte(0);  // unused
+                write_little_endian_word(entry->sector_count);
+                write_little_endian_dword(entry->load_rba);
+                write_block(20, 0); // Selection criteria (unused)
+
+                entry = entry->next_entry;
+            }
+
+            header = header->next_header;
+        }
 
         fill_sector();
 
         fill_sector();
-    }
 
 
-    // Boot Image
-    if (eltorito)
-    {
-        boot_image_sector = cd.sector;
 
 
-        file = fopen(bootimage, "rb");
+        // Boot Images
+
+        default_boot_entry.load_rba = cd.sector;
+
+        file = fopen(default_boot_entry.bootimage, "rb");
         if (file == NULL)
         if (file == NULL)
-            error_exit("Can't open %s\n", bootimage);
+            error_exit("Cannot open %s\n", default_boot_entry.bootimage);
         fseek(file, 0, SEEK_END);
         size = ftell(file);
         if (size == 0 || (size % 2048))
         fseek(file, 0, SEEK_END);
         size = ftell(file);
         if (size == 0 || (size % 2048))
@@ -1480,13 +1566,50 @@ static void pass(void)
             fclose(file);
             error_exit("Invalid boot image size (%lu bytes)\n", size);
         }
             fclose(file);
             error_exit("Invalid boot image size (%lu bytes)\n", size);
         }
-        boot_image_size = size / 512;
+        // Sector count in 512 byte sectors and rounded up
+        default_boot_entry.sector_count = (size + 511) / 512;
         if (!write_from_file(file, size))
         {
             fclose(file);
         if (!write_from_file(file, size))
         {
             fclose(file);
-            error_exit("Read error in file %s\n", bootimage);
+            error_exit("Read error in file %s\n", default_boot_entry.bootimage);
         }
         fclose(file);
         }
         fclose(file);
+
+        // Loop through each boot header
+        header = boot_header_list;
+        while (header)
+        {
+            // Loop through each boot entry
+            entry = header->entry_list;
+            while (entry)
+            {
+                entry->load_rba = cd.sector;
+
+                file = fopen(entry->bootimage, "rb");
+                if (file == NULL)
+                    error_exit("Cannot open %s\n", entry->bootimage);
+                fseek(file, 0, SEEK_END);
+                size = ftell(file);
+                if (size == 0 || (size % 2048))
+                {
+                    fclose(file);
+                    error_exit("Invalid boot image size (%lu bytes)\n", size);
+                }
+                // Sector count in 512 byte sectors and rounded up
+                entry->sector_count = (size + 511) / 512;
+                if (!write_from_file(file, size))
+                {
+                    fclose(file);
+                    error_exit("Read error in file %s\n", entry->bootimage);
+                }
+                fclose(file);
+
+                entry = entry->next_entry;
+            }
+
+            header = header->next_header;
+        }
+
 //      fill_sector();
     }
 
 //      fill_sector();
     }
 
@@ -1495,7 +1618,7 @@ static void pass(void)
     write_byte(1);
     write_byte(0);  // number of sectors in extended attribute record
     write_little_endian_dword(root.sector);
     write_byte(1);
     write_byte(0);  // number of sectors in extended attribute record
     write_little_endian_dword(root.sector);
-    write_little_endian_word((WORD) 1);
+    write_little_endian_word(1);
     write_byte(0);
     write_byte(0);
 
     write_byte(0);
     write_byte(0);
 
@@ -1524,7 +1647,7 @@ static void pass(void)
     write_byte(1);
     write_byte(0);  // number of sectors in extended attribute record
     write_big_endian_dword(root.sector);
     write_byte(1);
     write_byte(0);  // number of sectors in extended attribute record
     write_big_endian_dword(root.sector);
-    write_big_endian_word((WORD) 1);
+    write_big_endian_word(1);
     write_byte(0);
     write_byte(0);
 
     write_byte(0);
     write_byte(0);
 
@@ -1549,7 +1672,7 @@ static void pass(void)
         write_byte(1);
         write_byte(0);  // number of sectors in extended attribute record
         write_little_endian_dword(root.joliet_sector);
         write_byte(1);
         write_byte(0);  // number of sectors in extended attribute record
         write_little_endian_dword(root.joliet_sector);
-        write_little_endian_word((WORD) 1);
+        write_little_endian_word(1);
         write_byte(0);
         write_byte(0);
 
         write_byte(0);
         write_byte(0);
 
@@ -1573,7 +1696,7 @@ static void pass(void)
         write_byte(1);
         write_byte(0);  // number of sectors in extended attribute record
         write_big_endian_dword(root.joliet_sector);
         write_byte(1);
         write_byte(0);  // number of sectors in extended attribute record
         write_big_endian_dword(root.joliet_sector);
-        write_big_endian_word((WORD) 1);
+        write_big_endian_word(1);
         write_byte(0);
         write_byte(0);
 
         write_byte(0);
         write_byte(0);
 
@@ -1659,7 +1782,7 @@ static void pass(void)
                         printf("Writing contents of %s\n", file_source);
                     file = fopen(file_source, "rb");
                     if (file == NULL)
                         printf("Writing contents of %s\n", file_source);
                     file = fopen(file_source, "rb");
                     if (file == NULL)
-                        error_exit("Can't open %s\n", file_source);
+                        error_exit("Cannot open %s\n", file_source);
                     if (!write_from_file(file, size))
                     {
                         fclose(file);
                     if (!write_from_file(file, size))
                     {
                         fclose(file);
@@ -1682,32 +1805,79 @@ static char HELP[] =
     "Copyright (C) Philip J. Erdelsky\n"
     "Copyright (C) 2003-2015 ReactOS Team\n"
     "\n\n"
     "Copyright (C) Philip J. Erdelsky\n"
     "Copyright (C) 2003-2015 ReactOS Team\n"
     "\n\n"
-    "CDMAKE [-q] [-v] [-p] [-s N] [-m] [-b bootimage] [-j] source volume image\n"
+    "CDMAKE [-vN] [-p] [-s N] [-m] [-j] [-pN] [-eN] [-b bootimage]\n"
+    "       [-bootdata:N#<defaultBootEntry>#<bootEntry1>#...#<bootEntryN>]\n"
+    "       source volume image\n"
+    "\n"
+    "  -vN           Verbosity level. Valid values for 'N' are:\n"
+    "                    0: Quiet mode - display nothing but error messages.\n"
+    "                    1: Normal mode (default).\n"
+    "                    2: Verbose mode - display file information as files are\n"
+    "                       scanned and written. Overrides the -p option.\n"
+    "  -p            Show progress while writing.\n"
+    "  -s N          Abort operation before beginning write if image will be larger\n"
+    "                than N megabytes (i.e. 1024*1024*N bytes).\n"
+    "  -m            Accept punctuation marks other than underscores in names and\n"
+    "                extensions.\n"
+    "  -j            Generate Joliet filename records.\n"
+    "\n"
+    "  -pN           Boot platform ID in hex format (default: 00 for a BIOS system).\n"
+    "  -eN           Boot media emulation. Valid values for 'N' are:\n"
+    "                    0 (or nothing): No emulation.\n"
+    "                    1: 1.2Mb  diskette.\n"
+    "                    2: 1.44Mb diskette.\n"
+    "                    3: 2.88Mb diskette.\n"
+    "                    4: Hard disk.\n"
+    "  -b bootimage  Create a single-boot El-Torito image.\n"
+    "  -bootdata:    Create a multi-boot El-Torito image. This option cannot be\n"
+    "                combined with the -b option.\n"
+    "       Syntax:\n"
+    "       -bootdata:N#<defaultBootEntry>#<bootEntry2>#...#<bootEntryN>\n"
+    "            'N': number of boot entries following.\n"
+    "            defaultBootEntry: The default boot entry, needed in all cases.\n"
+    "                Used by BIOSes which do not support additional boot entries.\n"
+    "            bootEntryX: Additional boot entries.\n"
+    "            - Do not use spaces.\n"
+    "            - Each multi-boot entry must be delimited with a hash symbol (#).\n"
+    "            - Each option for a boot entry must be delimited with a comma (,).\n"
+    "            - Each boot entry must specify the platform ID.\n"
     "\n"
     "\n"
-    "  source        Specifications of base directory containing all files to\n"
-    "                be written to CD-ROM image\n"
-    "  volume        Volume label\n"
-    "  image         Image file or device\n"
-    "  -q            Quiet mode - display nothing but error messages\n"
-    "  -v            Verbose mode - display file information as files are\n"
-    "                scanned and written - overrides -p option\n"
-    "  -p            Show progress while writing\n"
-    "  -s N          Abort operation before beginning write if image will be\n"
-    "                larger than N megabytes (i.e. 1024*1024*N bytes)\n"
-    "  -m            Accept punctuation marks other than underscores in\n"
-    "                names and extensions\n"
-    "  -b bootimage  Create bootable ElTorito CD-ROM using 'no emulation' mode\n"
-    "  -j            Generate Joliet filename records\n";
+    "  source        Specifications of base directory containing all files to be\n"
+    "                written to CD-ROM image.\n"
+    "  volume        Volume label.\n"
+    "  image         Image file or device.\n";
 
 /*-----------------------------------------------------------------------------
 Program execution starts here.
 -----------------------------------------------------------------------------*/
 
 
 /*-----------------------------------------------------------------------------
 Program execution starts here.
 -----------------------------------------------------------------------------*/
 
+char* strtok_s(char *str, const char *delim, char **ctx)
+{
+    if (delim == NULL || ctx == NULL || (str == NULL && *ctx == NULL))
+    {
+        return NULL;
+    }
+
+    if (!str)
+        str = *ctx;
+
+    while (*str && strchr(delim, *str))
+        str++;
+    if (!*str)
+        return NULL;
+
+    *ctx = str + 1;
+    while (**ctx && !strchr(delim, **ctx))
+        (*ctx)++;
+    if (**ctx)
+        *(*ctx)++ = '\0';
+
+    return str;
+}
+
 int main(int argc, char **argv)
 {
     time_t timestamp = time(NULL);
 int main(int argc, char **argv)
 {
     time_t timestamp = time(NULL);
-    BOOL q_option = FALSE;
-    BOOL v_option = FALSE;
     int i;
     char *t;
 
     int i;
     char *t;
 
@@ -1717,7 +1887,7 @@ int main(int argc, char **argv)
         return 1;
     }
 
         return 1;
     }
 
-    // initialize root directory
+    // Initialize root directory
 
     cd.buffer = malloc(BUFFER_SIZE);
     if (cd.buffer == NULL)
 
     cd.buffer = malloc(BUFFER_SIZE);
     if (cd.buffer == NULL)
@@ -1728,27 +1898,57 @@ int main(int argc, char **argv)
     root.flags = DIRECTORY_FLAG;
     convert_date_and_time(&root.date_and_time, &timestamp);
 
     root.flags = DIRECTORY_FLAG;
     convert_date_and_time(&root.date_and_time, &timestamp);
 
-    // initialize CD-ROM write buffer
+    // Initialize CD-ROM write buffer
 
     cd.file = NULL;
     cd.filespecs[0] = 0;
 
 
     cd.file = NULL;
     cd.filespecs[0] = 0;
 
-    // initialize parameters
+    // Initialize parameters
 
     verbosity = NORMAL;
 
     verbosity = NORMAL;
-    size_limit = 0;
     show_progress = FALSE;
     show_progress = FALSE;
+    size_limit = 0;
     accept_punctuation_marks = FALSE;
     source[0] = 0;
     volume_label[0] = 0;
 
     accept_punctuation_marks = FALSE;
     source[0] = 0;
     volume_label[0] = 0;
 
-    eltorito = FALSE;
-
-    // scan command line arguments
+    // Initialize boot information
+    eltorito   = FALSE;
+    multi_boot = FALSE;
+    boot_validation_header.header_id   = 1;  // Validation header ID
+    boot_validation_header.platform_id = 0;  // x86/64 BIOS system
+    default_boot_entry.boot_id       = 0x88; // Bootable entry
+    default_boot_entry.boot_emu_type = 0;    // No emulation
+    default_boot_entry.load_segment  = 0;    // 0 --> use default 0x07C0
+    default_boot_entry.sector_count  = 0;
+    default_boot_entry.load_rba      = 0;
+    default_boot_entry.bootimage[0]  = '\0';
+    boot_header_list = NULL;
+
+    // Scan command line arguments
 
     for (i = 1; i < argc; i++)
     {
 
     for (i = 1; i < argc; i++)
     {
-        if (memcmp(argv[i], "-s", 2) == 0)
+        if (strncmp(argv[i], "-v", 2) == 0)
+        {
+            t = argv[i] + 2;
+            if (*t == 0) // Normal verbosity level.
+                verbosity = NORMAL;
+            else // Verbosity level in decimal
+                verbosity = strtoul(t, NULL, 10);
+
+            // Check for validity
+            if (verbosity > VERBOSE)
+                verbosity = NORMAL;
+
+            // Disable by default, unless we are in normal verbosity level.
+            // If progress is still wanted, use '-p'.
+            if (verbosity == QUIET || verbosity == VERBOSE)
+                show_progress = FALSE;
+        }
+        else if (strcmp(argv[i], "-p") == 0)
+            show_progress = TRUE;
+        else if (strncmp(argv[i], "-s", 2) == 0)
         {
             t = argv[i] + 2;
             if (*t == 0)
         {
             t = argv[i] + 2;
             if (*t == 0)
@@ -1758,26 +1958,254 @@ int main(int argc, char **argv)
                 else
                     error_exit("Missing size limit parameter");
             }
                 else
                     error_exit("Missing size limit parameter");
             }
+            // size_limit = strtoul(t, NULL, 10);
             while (isdigit(*t))
                 size_limit = size_limit * 10 + *t++ - '0';
             if (size_limit < 1 || size_limit > 800)
                 error_exit("Invalid size limit");
             size_limit <<= 9;  // convert megabyte to sector count
         }
             while (isdigit(*t))
                 size_limit = size_limit * 10 + *t++ - '0';
             if (size_limit < 1 || size_limit > 800)
                 error_exit("Invalid size limit");
             size_limit <<= 9;  // convert megabyte to sector count
         }
-        else if (strcmp(argv[i], "-q") == 0)
-            q_option = TRUE;
-        else if (strcmp(argv[i], "-v") == 0)
-            v_option = TRUE;
-        else if (strcmp(argv[i], "-p") == 0)
-            show_progress = TRUE;
         else if (strcmp(argv[i], "-m") == 0)
             accept_punctuation_marks = TRUE;
         else if (strcmp(argv[i], "-j") == 0)
             joliet = TRUE;
         else if (strcmp(argv[i], "-m") == 0)
             accept_punctuation_marks = TRUE;
         else if (strcmp(argv[i], "-j") == 0)
             joliet = TRUE;
+        else if (strncmp(argv[i], "-e", 2) == 0)
+        {
+            // Check whether the multi-boot option '-bootdata:' was already set.
+            // If so, print an error and bail out.
+            if (eltorito && multi_boot)
+                error_exit("Single-boot and multi-boot entries cannot be combined");
+
+            eltorito   = TRUE;
+            multi_boot = FALSE;
+
+            t = argv[i] + 2;
+            if (*t == 0) // No emulation
+                default_boot_entry.boot_emu_type = 0;
+            else // ID in decimal
+                default_boot_entry.boot_emu_type = (BYTE)strtoul(t, NULL, 10);
+        }
+        else if (strncmp(argv[i], "-p", 2) == 0)
+        {
+            // Check whether the multi-boot option '-bootdata:' was already set.
+            // If so, print an error and bail out.
+            if (eltorito && multi_boot)
+                error_exit("Single-boot and multi-boot entries cannot be combined");
+
+            eltorito   = TRUE;
+            multi_boot = FALSE;
+
+            // Platform ID in hexadecimal
+            boot_validation_header.platform_id = (BYTE)strtoul(argv[i] + 2, NULL, 16);
+        }
         else if (strcmp(argv[i], "-b") == 0)
         {
         else if (strcmp(argv[i], "-b") == 0)
         {
-            strcpy(bootimage, argv[++i]);
-            eltorito = TRUE;
+            // Check whether the multi-boot option '-bootdata:' was already set.
+            // If so, print an error and bail out.
+            if (eltorito && multi_boot)
+                error_exit("Single-boot and multi-boot entries cannot be combined");
+
+            eltorito   = TRUE;
+            multi_boot = FALSE;
+
+            strncpy(default_boot_entry.bootimage, argv[++i], sizeof(default_boot_entry.bootimage));
+            default_boot_entry.bootimage[sizeof(default_boot_entry.bootimage)-1] = '\0';
+        }
+        else if (strncmp(argv[i], "-bootdata:", sizeof("-bootdata:") - 1) == 0)
+        {
+            char *bootdata, *entry_ctx, *option_ctx;
+            DWORD num_boot_entries = 0;
+
+            BOOL default_entry = TRUE; // Start by setting the default boot entry
+            PBOOT_HEADER boot_header = NULL; // Current boot header
+            PBOOT_ENTRY  boot_entry  = NULL; // The last boot entry in the current boot header
+            BYTE platform_id, old_platform_id = 0;
+            BYTE boot_emu_type;
+            WORD load_segment;
+            char bootimage[512];
+
+            // Check whether the single-boot option '-b' was already set.
+            // If so, print an error and bail out.
+            if (eltorito && !multi_boot)
+                error_exit("Single-boot and multi-boot entries cannot be combined");
+
+            t = argv[i] + (sizeof("-bootdata:") - 1);
+            bootdata = strdup(t);
+            if (bootdata == NULL)
+                error_exit("Insufficient memory");
+
+            eltorito   = TRUE;
+            multi_boot = TRUE;
+
+            // FIXME: Paths with '#' or ',' or ' ' inside are not yet supported!!
+
+            // Start parsing...
+            t = strtok_s(bootdata, "#", &entry_ctx);
+            if (t == NULL)
+            {
+                free(bootdata);
+                error_exit("Malformed bootdata command");
+            }
+
+            num_boot_entries = strtoul(t, NULL, 10);
+
+            while (num_boot_entries--)
+            {
+                // Reset to default values
+                platform_id   = 0;  // x86/64 BIOS system
+                boot_emu_type = 0;  // No emulation
+                load_segment  = 0;  // 0 --> use default 0x07C0
+                bootimage[0]  = '\0';
+
+                t = strtok_s(NULL, "#", &entry_ctx);
+                if (t == NULL)
+                {
+                    free(bootdata);
+                    error_exit("Malformed bootdata command");
+                }
+
+                t = strtok_s(t, ",", &option_ctx);
+                while (t != NULL)
+                {
+                    switch (*t++)
+                    {
+                        case 'b': // Boot sector file
+                        {
+                            char *q;
+
+                            // Searches for any of the valid separators:
+                            // '#' starts a new boot entry;
+                            // ',' starts a new boot option;
+                            // ' ' finishes the bootdata command.
+                            q = strpbrk(t, "#, ");
+                            if (!q) q = t + strlen(t);
+                            strncpy(bootimage, t, q - t + 1);
+                            break;
+                        }
+
+                        case 'p': // Platform ID
+                        {
+                            // Platform ID in hexadecimal
+                            platform_id = (BYTE)strtoul(t, NULL, 16);
+                            break;
+                        }
+
+                        case 'e': // No floppy-disk emulation
+                        {
+                            if (*t == 0) // No emulation
+                                boot_emu_type = 0;
+                            else // ID in decimal
+                                boot_emu_type = (BYTE)strtoul(t, NULL, 10);
+
+                            break;
+                        }
+
+                        case 't': // Loading segment
+                        {
+                            if (*t == 0) // Not specified --> use default 0x07C0
+                                load_segment = 0;
+                            else // Segment in hexadecimal
+                                load_segment = (BYTE)strtoul(t, NULL, 16);
+
+                            break;
+                        }
+
+                        default:
+                            free(bootdata);
+                            error_exit("Malformed bootdata command");
+                    }
+
+                    t = strtok_s(NULL, ",", &option_ctx);
+                }
+
+                // Create a new entry and possibly a boot header
+                if (default_entry)
+                {
+                    // Initialize the default boot entry and header
+
+                    boot_validation_header.header_id   = 1;  // Validation header ID
+                    boot_validation_header.platform_id = platform_id;
+                    default_boot_entry.boot_id       = 0x88; // Bootable entry
+                    default_boot_entry.boot_emu_type = boot_emu_type;
+                    default_boot_entry.load_segment  = load_segment;
+
+                    strncpy(default_boot_entry.bootimage, bootimage, sizeof(default_boot_entry.bootimage));
+                    default_boot_entry.bootimage[sizeof(default_boot_entry.bootimage)-1] = '\0';
+
+                    // Default entry is now initialized.
+                    default_entry = FALSE;
+                }
+                else
+                {
+                    // Initialize a new boot entry
+                    PBOOT_ENTRY old_boot_entry = boot_entry;
+
+                    boot_entry = calloc(1, sizeof(*boot_entry));
+                    if (boot_entry == NULL)
+                        error_exit("Insufficient memory");
+                    // boot_entry->next_entry = NULL;
+
+                    boot_entry->boot_id       = 0x88;   // Bootable entry
+                    boot_entry->boot_emu_type = boot_emu_type;
+                    boot_entry->load_segment  = load_segment;
+
+                    strncpy(boot_entry->bootimage, bootimage, sizeof(boot_entry->bootimage));
+                    boot_entry->bootimage[sizeof(boot_entry->bootimage)-1] = '\0';
+
+                    // Create a new boot header if we don't have one yet
+                    if (boot_header == NULL)
+                    {
+                        boot_header = calloc(1, sizeof(*boot_header));
+                        if (boot_header == NULL)
+                            error_exit("Insufficient memory");
+
+                        boot_header->header_id   = 0x91; // So far this is the last boot header
+                        boot_header->platform_id = platform_id;
+                        // boot_header->next_header = NULL;
+                        // boot_header->num_entries = 0;
+                        // boot_header->entry_list  = NULL;
+
+                        old_boot_entry  = NULL;
+                        old_platform_id = platform_id;
+
+                        boot_header_list = boot_header;
+                    }
+                    else
+                    {
+                        // Create a new boot header if we change the platform ID
+                        if (old_platform_id != platform_id)
+                        {
+                            PBOOT_HEADER prev_boot_header = boot_header;
+
+                            boot_header = calloc(1, sizeof(*boot_header));
+                            if (boot_header == NULL)
+                                error_exit("Insufficient memory");
+
+                            boot_header->header_id   = 0x91; // So far this is the last boot header
+                            boot_header->platform_id = platform_id;
+                            // boot_header->next_header = NULL;
+                            // boot_header->num_entries = 0;
+                            // boot_header->entry_list  = NULL;
+
+                            old_boot_entry  = NULL;
+                            old_platform_id = platform_id;
+
+                            // Link into the header list
+                            prev_boot_header->header_id = 0x90; // The previous boot header was not the last one
+                            prev_boot_header->next_header = boot_header;
+                        }
+                    }
+
+                    // Add the entry into the header
+                    ++boot_header->num_entries;
+                    if (old_boot_entry == NULL)
+                        boot_header->entry_list = boot_entry;
+                    else
+                        old_boot_entry->next_entry = boot_entry;
+                }
+            }
+
+            free(bootdata);
         }
         else if (i + 2 < argc)
         {
         }
         else if (i + 2 < argc)
         {
@@ -1788,16 +2216,7 @@ int main(int argc, char **argv)
         else
             error_exit("Missing command line argument");
     }
         else
             error_exit("Missing command line argument");
     }
-    if (v_option)
-    {
-        show_progress = FALSE;
-        verbosity = VERBOSE;
-    }
-    else if (q_option)
-    {
-        verbosity = QUIET;
-        show_progress = FALSE;
-    }
+
     if (source[0] == 0)
         error_exit("Missing source directory");
     if (volume_label[0] == 0)
     if (source[0] == 0)
         error_exit("Missing source directory");
     if (volume_label[0] == 0)
@@ -1820,13 +2239,13 @@ int main(int argc, char **argv)
     }
     else
     {
     }
     else
     {
-        char *trimmedline, *targetname, *srcname, *eq;
+        char *trimmedline, *targetname, *srcname, *eq, *normdir;
         char lineread[1024];
 
         FILE *f = fopen(source+1, "r");
         if (!f)
         {
         char lineread[1024];
 
         FILE *f = fopen(source+1, "r");
         if (!f)
         {
-            error_exit("Can't open cd description %s\n", source+1);
+            error_exit("Cannot open cd description %s\n", source+1);
         }
         while (fgets(lineread, sizeof(lineread), f))
         {
         }
         while (fgets(lineread, sizeof(lineread), f))
         {
@@ -1835,7 +2254,6 @@ int main(int argc, char **argv)
             eq = strchr(trimmedline, '=');
             if (!eq)
             {
             eq = strchr(trimmedline, '=');
             if (!eq)
             {
-                char *normdir;
                 /* Treat this as a directory name */
                 targetname = trimmedline;
                 normdir = strdup(targetname);
                 /* Treat this as a directory name */
                 targetname = trimmedline;
                 normdir = strdup(targetname);
@@ -1852,12 +2270,12 @@ int main(int argc, char **argv)
                 if (_access(srcname, R_OK) == 0)
                     dir_hash_add_file(&specified_files, srcname, targetname);
                 else
                 if (_access(srcname, R_OK) == 0)
                     dir_hash_add_file(&specified_files, srcname, targetname);
                 else
-                    error_exit("can't access file '%s' (target %s)\n", srcname, targetname);
+                    error_exit("Cannot access file '%s' (target %s)\n", srcname, targetname);
 #else
                 if (access(srcname, R_OK) == 0)
                     dir_hash_add_file(&specified_files, srcname, targetname);
                 else
 #else
                 if (access(srcname, R_OK) == 0)
                     dir_hash_add_file(&specified_files, srcname, targetname);
                 else
-                    error_exit("can't access file '%s' (target %s)\n", srcname, targetname);
+                    error_exit("Cannot access file '%s' (target %s)\n", srcname, targetname);
 #endif
             }
         }
 #endif
             }
         }
@@ -1877,7 +2295,7 @@ int main(int argc, char **argv)
     cd.file = NULL;
     cd.sector = 0;
     cd.offset = 0;
     cd.file = NULL;
     cd.sector = 0;
     cd.offset = 0;
-    cd.count = 0;
+    cd.count  = 0;
 
     // make non-writing pass over directory structure to obtain the proper
     // sector numbers and offsets and to determine the size of the image
 
     // make non-writing pass over directory structure to obtain the proper
     // sector numbers and offsets and to determine the size of the image
@@ -1909,10 +2327,10 @@ int main(int argc, char **argv)
 
     cd.file = fopen(cd.filespecs, "w+b");
     if (cd.file == NULL)
 
     cd.file = fopen(cd.filespecs, "w+b");
     if (cd.file == NULL)
-        error_exit("Can't open image file %s", cd.filespecs);
+        error_exit("Cannot open image file %s", cd.filespecs);
     cd.sector = 0;
     cd.offset = 0;
     cd.sector = 0;
     cd.offset = 0;
-    cd.count = 0;
+    cd.count  = 0;
 
 
     // make writing pass over directory structure
 
 
     // make writing pass over directory structure
index 5876315..ffb5dab 100644 (file)
@@ -9,6 +9,7 @@
 #define DIR_SEPARATOR_STRING "\\"
 #endif
 
 #define DIR_SEPARATOR_STRING "\\"
 #endif
 
+#define MANUFACTURER_ID "ReactOS Foundation"
 #define PUBLISHER_ID    "ReactOS Foundation"
 #define DATA_PREP_ID    "ReactOS Foundation"
 #define APP_ID          "CDMAKE CD-ROM Premastering Utility"
 #define PUBLISHER_ID    "ReactOS Foundation"
 #define DATA_PREP_ID    "ReactOS Foundation"
 #define APP_ID          "CDMAKE CD-ROM Premastering Utility"
index a75a7b2..b3af795 100644 (file)
@@ -1,3 +1,10 @@
+/*
+ * COPYRIGHT:       See COPYING in the top level directory
+ * PROJECT:         ReactOS CD-ROM Maker
+ * FILE:            tools/cdmake/dirhash.c
+ * PURPOSE:         CD-ROM Premastering Utility - Directory names hashing
+ * PROGRAMMERS:     Art Yerkes
+ */
 #include <string.h>
 #include <stdlib.h>
 #include <ctype.h>
 #include <string.h>
 #include <stdlib.h>
 #include <ctype.h>
index aaf9ff5..1825532 100644 (file)
@@ -1,3 +1,10 @@
+/*
+ * COPYRIGHT:       See COPYING in the top level directory
+ * PROJECT:         ReactOS CD-ROM Maker
+ * FILE:            tools/cdmake/dirhash.h
+ * PURPOSE:         CD-ROM Premastering Utility - Directory names hashing
+ * PROGRAMMERS:     Art Yerkes
+ */
 #ifndef _DIRHASH_H_
 #define _DIRHASH_H_
 
 #ifndef _DIRHASH_H_
 #define _DIRHASH_H_