/* dvdisaster: Additional error correction for optical media. * Copyright (C) 2004-2017 Carsten Gnoerlich. * Copyright (C) 2019-2021 The dvdisaster development team. * * Email: support@dvdisaster.org * * This file is part of dvdisaster. * * dvdisaster 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 3 of the License, or * (at your option) any later version. * * dvdisaster 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 dvdisaster. If not, see . */ /*** src type: some GUI code ***/ #include "dvdisaster.h" #include "scsi-layer.h" #include "udf.h" /* * Local data */ typedef struct _medium_info { GtkWidget *profileDescr; GtkWidget *physicalType; GtkWidget *bookType; GtkWidget *manufID; GtkWidget *discStatus; GtkWidget *usedCapacity1; GtkWidget *usedCapacity2; GtkWidget *blankCapacity; GtkWidget *isoLabel; GtkWidget *isoSize; GtkWidget *isoTime; GtkWidget *eccState; GtkWidget *eccSize; GtkWidget *eccVersion; GtkWidget *exhaustiveSearch; GtkWidget *exhaustiveSearchButton; } medium_info; /*** *** Find out about the medium ***/ static void print_defaults(medium_info *mi) { GuiSetLabelText(mi->physicalType, _("Please wait...")); GuiSetLabelText(mi->bookType, "-"); GuiSetLabelText(mi->manufID, "-"); GuiSetLabelText(mi->profileDescr, "-"); GuiSetLabelText(mi->discStatus, "-"); GuiSetLabelText(mi->usedCapacity1, "-"); GuiSetLabelText(mi->usedCapacity2, " "); GuiSetLabelText(mi->blankCapacity, "-"); GuiSetLabelText(mi->isoLabel, "-"); GuiSetLabelText(mi->isoSize, "-"); GuiSetLabelText(mi->isoTime, "-"); GuiSetLabelText(mi->eccState, "-"); GuiSetLabelText(mi->eccSize, "-"); GuiSetLabelText(mi->eccVersion, "-"); GuiSetLabelText(mi->exhaustiveSearch, "-"); } static void print_tab(char *label, int tab_width) { char *translation=_(label); int length = tab_width-g_utf8_strlen(translation, -1); char pad[tab_width+1]; if(length < 1) pad[0] = 0; else { memset(pad, ' ', length); pad[length]=0; } PrintCLI("%s%s", translation, pad); } void PrintMediumInfo(void *mi_ptr) { Image *image; DeviceHandle *dh; medium_info *mi=(medium_info*)mi_ptr; char *disc_status; char *sess_status; int tab_width=30; if(!mi) /* create dummy medium_info in CLI mode so that PrintCLIorLabel() won't crash */ { mi=alloca(sizeof(medium_info)); memset(mi, 0, sizeof(medium_info)); } if(Closure->guiMode) print_defaults(mi); #ifdef WITH_GUI_YES /*** Ensure the UI is fully updated before our thread is stuck doing i/o */ while (gtk_events_pending()) gtk_main_iteration(); #endif image = OpenImageFromDevice(Closure->device, 2 /* allow blanks, see comment in OpenImageFromDevice() */); /*** in case of !image, say that we didn't find any medium */ GuiSetLabelText(mi->physicalType, _("Medium not present")); if(!image) return; dh = image->dh; QueryBlankCapacity(dh); /* Medium properties */ PrintCLI(_("Physical medium info")); PrintCLI("\n\n"); tab_width=GetLongestTranslation("Medium type:", "Book type:", "Manuf.-ID:", "Drive profile:", "Disc status:", "Used sectors:", "Blank capacity:", NULL)+1; print_tab("Medium type:",tab_width); PrintCLIorLabel(mi->physicalType, "%s\n", dh->typeDescr); print_tab("Book type:",tab_width); PrintCLIorLabel(mi->bookType, "%s\n", dh->bookDescr); print_tab("Manuf.-ID:",tab_width); PrintCLIorLabel(mi->manufID, "%s\n", dh->manuID); print_tab("Drive profile:",tab_width); PrintCLIorLabel(mi->profileDescr, "%s\n", dh->profileDescr); switch(dh->discStatus&3) { case 0: disc_status = g_strdup(_("empty")); break; case 1: disc_status = g_strdup(_("appendable")); break; case 2: disc_status = g_strdup(_("finalized")); break; default: disc_status = g_strdup(_("unknown")); break; } switch((dh->discStatus>>2)&3) { case 0: sess_status = g_strdup(_("empty")); break; case 1: sess_status = g_strdup(_("incomplete")); break; case 2: sess_status = g_strdup(_("damaged")); break; default: sess_status = g_strdup(_("complete")); break; } print_tab("Disc status:",tab_width); PrintCLIorLabel(mi->discStatus, _("%s (%d sessions; last session %s)\n"), disc_status, dh->sessions, sess_status); g_free(disc_status); g_free(sess_status); print_tab("Used sectors:",tab_width); PrintCLIorLabel(mi->usedCapacity1, _("%" PRId64 " sectors (%" PRId64 " MiB), from READ CAPACITY\n"), dh->readCapacity+1, (dh->readCapacity+1)>>9); print_tab(" ",tab_width); PrintCLIorLabel(mi->usedCapacity2, _("%" PRId64 " sectors (%" PRId64 " MiB), from DVD structure\n"), dh->userAreaSize, dh->userAreaSize>>9); print_tab("Blank capacity:",tab_width); PrintCLIorLabel(mi->blankCapacity, _("%" PRId64 " sectors (%" PRId64 " MiB)\n"), dh->blankCapacity, (dh->blankCapacity)>>9); /* Filesystem properties */ if(image->isoInfo) { tab_width=GetLongestTranslation("Medium label:", "File system size:", "Creation time:", NULL)+1; PrintCLI("\n\n"); PrintCLI(_("Filesystem info")); PrintCLI("\n\n"); print_tab("Medium label:",tab_width); PrintCLIorLabel(mi->isoLabel, "%s\n", image->isoInfo->volumeLabel); print_tab("File system size:",tab_width); PrintCLIorLabel(mi->isoSize, _("%d sectors (%" PRId64 " MiB)\n"), image->isoInfo->volumeSize, (gint64)image->isoInfo->volumeSize>>9); print_tab("Creation time:",tab_width); PrintCLIorLabel(mi->isoTime, "%s\n", image->isoInfo->creationDate); } /* Augmented image properties fixme: verify RS03 correctness */ if(image->eccHeader) { EccHeader *eh = image->eccHeader; int major = eh->creatorVersion/10000; int minor = (eh->creatorVersion%10000)/100; int micro = eh->creatorVersion%100; char method[5]; tab_width=GetLongestTranslation("Error correction data:", "Augmented image size:", "dvdisaster version:", NULL)+1; PrintCLI("\n\n"); PrintCLI(_("Augmented image info")); PrintCLI("\n\n"); memcpy(method, eh->method, 4); method[4] = 0; print_tab("Error correction data:",tab_width); PrintCLIorLabel(mi->eccState, _("%s, %d roots, %4.1f%% redundancy.\n"), method, eh->eccBytes, ((double)eh->eccBytes*100.0)/(double)eh->dataBytes); print_tab("Augmented image size:",tab_width); PrintCLIorLabel(mi->eccSize, _("%" PRIu64 " sectors (%" PRId64 " MiB)\n"), image->expectedSectors, image->expectedSectors>>9); print_tab("dvdisaster version:", tab_width); if(micro) PrintCLIorLabel(mi->eccVersion, "%d.%d.%d", major, minor, micro); else PrintCLIorLabel(mi->eccVersion, "%d.%d", major, minor); } #ifdef WITH_GUI_YES if (Closure->examineRS02 && Closure->examineRS03) { GuiSetLabelText(mi->exhaustiveSearch, _("yes")); /*** Hide exhaustive search button if exhaustive search is already enabled for RS02 / RS03 */ gtk_widget_hide(mi->exhaustiveSearchButton); } else { GuiSetLabelText(mi->exhaustiveSearch, _("no")); gtk_widget_show(mi->exhaustiveSearchButton); } #endif /* Clean up */ CloseImage(image); } #ifdef WITH_GUI_YES /*** *** GUI callbacks ***/ /* * Callback for drive selection */ static void drive_select_cb(GtkWidget *widget, gpointer data) { int n; char *dnode; if(!Closure->deviceNodes->len) /* No drives available */ return; n = gtk_combo_box_get_active(GTK_COMBO_BOX(widget)); if(n<0) return; dnode = g_ptr_array_index(Closure->deviceNodes, n); g_free(Closure->device); Closure->device = g_strdup(dnode); gtk_combo_box_set_active(GTK_COMBO_BOX(Closure->driveCombo), n); } /* * Callback for updating the medium information */ static void update_cb(GtkWidget *widget, gpointer data) { medium_info *mi=(medium_info*)data; PrintMediumInfo(mi); } /* * Callback for forcing exhaustive search */ static void es_cb(GtkWidget *widget, gpointer data) { medium_info *mi=(medium_info*)data; int oldRS02 = Closure->examineRS02; int oldRS03 = Closure->examineRS03; gtk_widget_hide(mi->exhaustiveSearchButton); Closure->examineRS02 = TRUE; Closure->examineRS03 = TRUE; PrintMediumInfo(mi); Closure->examineRS02 = oldRS02; Closure->examineRS03 = oldRS03; } /* * Close notification */ static void mi_destroy_cb(GtkWidget *widget, gpointer data) { Closure->mediumWindow = NULL; Closure->mediumDrive = NULL; g_free(Closure->mediumInfoContext); } /*** *** Create the medium info window ***/ void GuiCreateMediumInfoWindow() { GtkWidget *dialog,*vbox,*hbox,*table,*button,*lab,*sep,*frame,*combo_box; medium_info *mi; int i; int dev_idx = 0; if(Closure->mediumWindow) { gtk_widget_show(Closure->mediumWindow); return; } /*** Create the dialog */ dialog = gtk_dialog_new_with_buttons(_utf("windowtitle|Medium info"), Closure->window, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_STOCK_CLOSE, GTK_RESPONSE_ACCEPT, NULL); g_signal_connect_swapped(dialog, "response", G_CALLBACK(gtk_widget_destroy), dialog); Closure->mediumInfoContext = mi = g_malloc0(sizeof(medium_info)); /*** Inner vbox and title */ vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); gtk_box_pack_start(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), vbox, TRUE, TRUE, 0); gtk_container_set_border_width(GTK_CONTAINER(vbox), 10); lab = gtk_label_new(NULL); gtk_label_set_markup(GTK_LABEL(lab), _utf("Medium info\n" "Properties of the currently inserted medium")); gtk_label_set_xalign(GTK_LABEL(lab), 0.0); gtk_box_pack_start(GTK_BOX(vbox), lab, FALSE, FALSE, 0); sep = gtk_separator_new(GTK_ORIENTATION_HORIZONTAL); gtk_box_pack_start(GTK_BOX(vbox), sep, FALSE, FALSE, 0); gtk_box_pack_start(GTK_BOX(vbox), gtk_label_new(" "), FALSE, FALSE, 0); /*** Drive selection */ frame = gtk_frame_new(_utf("Drive selection")); gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 0); hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); gtk_container_set_border_width(GTK_CONTAINER(hbox), 10); gtk_container_add(GTK_CONTAINER(frame), hbox); lab = gtk_label_new(_utf("Drive:")); gtk_box_pack_start(GTK_BOX(hbox), lab, FALSE, FALSE, 0); lab = gtk_label_new(" "); gtk_box_pack_start(GTK_BOX(hbox), lab, FALSE, FALSE, 0); combo_box = gtk_combo_box_text_new(); gtk_box_pack_start(GTK_BOX(hbox), combo_box, FALSE, FALSE, 0); g_signal_connect(G_OBJECT(combo_box), "changed", G_CALLBACK(drive_select_cb), NULL); for(i=0; ideviceNames->len; i++) { gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo_box), g_ptr_array_index(Closure->deviceNames,i)); if(!strcmp(Closure->device, g_ptr_array_index(Closure->deviceNodes,i))) dev_idx = i; } if(!Closure->deviceNodes->len) { gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo_box), _utf("No drives found")); } gtk_combo_box_set_active(GTK_COMBO_BOX(combo_box), dev_idx); lab = gtk_label_new(_utf(" ")); gtk_box_pack_start(GTK_BOX(hbox), lab, FALSE, FALSE, 0); button = gtk_button_new_with_label(_utf("Update medium info")); g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(update_cb), mi); gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 10); /*** Medium info */ frame = gtk_frame_new(_utf("Physical medium info")); gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 0); table = gtk_table_new(2, 8, FALSE); gtk_container_set_border_width(GTK_CONTAINER(table), 5); gtk_container_add(GTK_CONTAINER(frame), table); lab = gtk_label_new(_utf("Medium type:")); gtk_label_set_xalign(GTK_LABEL(lab), 0.0); gtk_table_attach(GTK_TABLE(table), lab, 0, 1, 0, 1, GTK_SHRINK | GTK_FILL, GTK_SHRINK, 5, 2 ); lab = gtk_label_new(" "); mi->physicalType = lab; gtk_label_set_xalign(GTK_LABEL(lab), 0.0); gtk_table_attach(GTK_TABLE(table), lab, 1, 2, 0, 1, GTK_EXPAND | GTK_FILL, GTK_SHRINK, 0, 0); lab = gtk_label_new(_utf("Book type:")); gtk_label_set_xalign(GTK_LABEL(lab), 0.0); gtk_table_attach(GTK_TABLE(table), lab, 0, 1, 1, 2, GTK_SHRINK | GTK_FILL, GTK_SHRINK, 5, 2 ); lab = gtk_label_new(" "); mi->bookType = lab; gtk_label_set_xalign(GTK_LABEL(lab), 0.0); gtk_table_attach(GTK_TABLE(table), lab, 1, 2, 1, 2, GTK_EXPAND | GTK_FILL, GTK_SHRINK, 0, 0); lab = gtk_label_new(_utf("Manuf.-ID:")); gtk_label_set_xalign(GTK_LABEL(lab), 0.0); gtk_table_attach(GTK_TABLE(table), lab, 0, 1, 2, 3, GTK_SHRINK | GTK_FILL, GTK_SHRINK, 5, 2 ); lab = gtk_label_new(" "); mi->manufID = lab; gtk_label_set_xalign(GTK_LABEL(lab), 0.0); gtk_table_attach(GTK_TABLE(table), lab, 1, 2, 2, 3, GTK_EXPAND | GTK_FILL, GTK_SHRINK, 0, 0); lab = gtk_label_new(_utf("Drive profile:")); gtk_label_set_xalign(GTK_LABEL(lab), 0.0); gtk_table_attach(GTK_TABLE(table), lab, 0, 1, 3, 4, GTK_SHRINK | GTK_FILL, GTK_SHRINK, 5, 2 ); lab = gtk_label_new(" "); mi->profileDescr = lab; gtk_label_set_xalign(GTK_LABEL(lab), 0.0); gtk_table_attach(GTK_TABLE(table), lab, 1, 2, 3, 4, GTK_EXPAND | GTK_FILL, GTK_SHRINK, 0, 0); lab = gtk_label_new(_utf("Disc status:")); gtk_label_set_xalign(GTK_LABEL(lab), 0.0); gtk_table_attach(GTK_TABLE(table), lab, 0, 1, 4, 5, GTK_SHRINK | GTK_FILL, GTK_SHRINK, 5, 2 ); lab = gtk_label_new(" "); mi->discStatus = lab; gtk_label_set_xalign(GTK_LABEL(lab), 0.0); gtk_table_attach(GTK_TABLE(table), lab, 1, 2, 4, 5, GTK_EXPAND | GTK_FILL, GTK_SHRINK, 0, 0); lab = gtk_label_new(_utf("Used sectors:")); gtk_label_set_xalign(GTK_LABEL(lab), 0.0); gtk_table_attach(GTK_TABLE(table), lab, 0, 1, 5, 6, GTK_SHRINK | GTK_FILL, GTK_SHRINK, 5, 2 ); lab = gtk_label_new(" "); mi->usedCapacity1 = lab; gtk_label_set_xalign(GTK_LABEL(lab), 0.0); gtk_table_attach(GTK_TABLE(table), lab, 1, 2, 5, 6, GTK_EXPAND | GTK_FILL, GTK_SHRINK, 0, 0); lab = gtk_label_new(" "); gtk_label_set_xalign(GTK_LABEL(lab), 0.0); gtk_table_attach(GTK_TABLE(table), lab, 0, 1, 6, 7, GTK_SHRINK | GTK_FILL, GTK_SHRINK, 5, 2 ); lab = gtk_label_new(" "); mi->usedCapacity2 = lab; gtk_label_set_xalign(GTK_LABEL(lab), 0.0); gtk_table_attach(GTK_TABLE(table), lab, 1, 2, 6, 7, GTK_EXPAND | GTK_FILL, GTK_SHRINK, 0, 0); lab = gtk_label_new(_utf("Blank capacity:")); gtk_label_set_xalign(GTK_LABEL(lab), 0.0); gtk_table_attach(GTK_TABLE(table), lab, 0, 1, 7, 8, GTK_SHRINK | GTK_FILL, GTK_SHRINK, 5, 2 ); lab = gtk_label_new(" "); mi->blankCapacity = lab; gtk_label_set_xalign(GTK_LABEL(lab), 0.0); gtk_table_attach(GTK_TABLE(table), lab, 1, 2, 7, 8, GTK_EXPAND | GTK_FILL, GTK_SHRINK, 0, 0); /*** Filesystem info */ frame = gtk_frame_new(_utf("Filesystem info")); gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 0); table = gtk_table_new(2, 3, FALSE); gtk_container_set_border_width(GTK_CONTAINER(table), 5); gtk_container_add(GTK_CONTAINER(frame), table); lab = gtk_label_new(_utf("Medium label:")); gtk_label_set_xalign(GTK_LABEL(lab), 0.0); gtk_table_attach(GTK_TABLE(table), lab, 0, 1, 0, 1, GTK_SHRINK | GTK_FILL, GTK_SHRINK, 5, 2 ); lab = gtk_label_new(" "); mi->isoLabel = lab; gtk_label_set_xalign(GTK_LABEL(lab), 0.0); gtk_table_attach(GTK_TABLE(table), lab, 1, 2, 0, 1, GTK_EXPAND | GTK_FILL, GTK_SHRINK, 0, 0); lab = gtk_label_new(_utf("File system size:")); gtk_label_set_xalign(GTK_LABEL(lab), 0.0); gtk_table_attach(GTK_TABLE(table), lab, 0, 1, 1, 2, GTK_SHRINK | GTK_FILL, GTK_SHRINK, 5, 2 ); lab = gtk_label_new(" "); mi->isoSize = lab; gtk_label_set_xalign(GTK_LABEL(lab), 0.0); gtk_table_attach(GTK_TABLE(table), lab, 1, 2, 1, 2, GTK_EXPAND | GTK_FILL, GTK_SHRINK, 0, 0); lab = gtk_label_new(_utf("Creation time:")); gtk_label_set_xalign(GTK_LABEL(lab), 0.0); gtk_table_attach(GTK_TABLE(table), lab, 0, 1, 2, 3, GTK_SHRINK | GTK_FILL, GTK_SHRINK, 5, 2 ); lab = gtk_label_new(" "); mi->isoTime = lab; gtk_label_set_xalign(GTK_LABEL(lab), 0.0); gtk_table_attach(GTK_TABLE(table), lab, 1, 2, 2, 3, GTK_EXPAND | GTK_FILL, GTK_SHRINK, 0, 0); /*** Error correction info */ frame = gtk_frame_new(_utf("Augmented image info")); gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 0); table = gtk_table_new(3, 4, FALSE); gtk_container_set_border_width(GTK_CONTAINER(table), 5); gtk_container_add(GTK_CONTAINER(frame), table); lab = gtk_label_new(_utf("Error correction data:")); gtk_label_set_xalign(GTK_LABEL(lab), 0.0); gtk_table_attach(GTK_TABLE(table), lab, 0, 1, 0, 1, GTK_SHRINK | GTK_FILL, GTK_SHRINK, 5, 2 ); lab = gtk_label_new(" "); mi->eccState = lab; gtk_label_set_xalign(GTK_LABEL(lab), 0.0); gtk_table_attach(GTK_TABLE(table), lab, 1, 3, 0, 1, GTK_EXPAND | GTK_FILL, GTK_SHRINK, 0, 0); lab = gtk_label_new(_utf("Augmented image size:")); gtk_label_set_xalign(GTK_LABEL(lab), 0.0); gtk_table_attach(GTK_TABLE(table), lab, 0, 1, 1, 2, GTK_SHRINK | GTK_FILL, GTK_SHRINK, 5, 2 ); lab = gtk_label_new(" "); mi->eccSize = lab; gtk_label_set_xalign(GTK_LABEL(lab), 0.0); gtk_table_attach(GTK_TABLE(table), lab, 1, 3, 1, 2, GTK_EXPAND | GTK_FILL, GTK_SHRINK, 0, 0); lab = gtk_label_new(_utf("dvdisaster version:")); gtk_label_set_xalign(GTK_LABEL(lab), 0.0); gtk_table_attach(GTK_TABLE(table), lab, 0, 1, 2, 3, GTK_SHRINK | GTK_FILL, GTK_SHRINK, 5, 2 ); lab = gtk_label_new(" "); mi->eccVersion = lab; gtk_label_set_xalign(GTK_LABEL(lab), 0.0); gtk_table_attach(GTK_TABLE(table), lab, 1, 3, 2, 3, GTK_EXPAND | GTK_FILL, GTK_SHRINK, 0, 0); lab = gtk_label_new(_utf("Exhaustive search:")); gtk_label_set_xalign(GTK_LABEL(lab), 0.0); gtk_label_set_yalign(GTK_LABEL(lab), 0.0); gtk_table_attach(GTK_TABLE(table), lab, 0, 1, 3, 4, GTK_SHRINK | GTK_FILL, GTK_SHRINK, 5, 2 ); lab = gtk_label_new(" "); mi->exhaustiveSearch = lab; gtk_label_set_xalign(GTK_LABEL(lab), 0.0); gtk_label_set_yalign(GTK_LABEL(lab), 0.0); gtk_table_attach(GTK_TABLE(table), lab, 1, 2, 3, 4, GTK_EXPAND | GTK_FILL, GTK_SHRINK, 0, 0); mi->exhaustiveSearchButton = gtk_button_new_with_label(_utf("Run exhaustive search")); g_signal_connect(G_OBJECT(mi->exhaustiveSearchButton), "clicked", G_CALLBACK(es_cb), mi); gtk_table_attach(GTK_TABLE(table), mi->exhaustiveSearchButton, 2, 3, 3, 4, GTK_SHRINK | GTK_FILL, GTK_SHRINK, 0, 0); /*** Show it */ g_signal_connect(G_OBJECT(dialog), "destroy", G_CALLBACK(mi_destroy_cb), NULL); Closure->mediumWindow = dialog; Closure->mediumDrive = combo_box; gtk_widget_show_all(dialog); /*** Hide it by default, it'll be unhidden by PrintMediumInfo if needed */ gtk_widget_hide(mi->exhaustiveSearchButton); PrintMediumInfo(mi); } #endif