+ // 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);