mirror of
https://github.com/aaru-dps/libaaruformat.git
synced 2025-12-16 11:14:39 +00:00
Refactor compare for simplicity.
This commit is contained in:
782
tool/compare.c
782
tool/compare.c
@@ -26,518 +26,438 @@
|
||||
|
||||
#include "termbox2.h"
|
||||
|
||||
// Helper structure to track comparison state
|
||||
typedef struct {
|
||||
int mid_x;
|
||||
int height;
|
||||
int left_row;
|
||||
int right_row;
|
||||
bool has_differences;
|
||||
} compare_state_t;
|
||||
|
||||
void draw_progress_bar(int row, int percent)
|
||||
{
|
||||
const int width = tb_width() / 2;
|
||||
const int bar_width = width - 4; // leave space for borders
|
||||
const int bar_width = width - 4;
|
||||
const int filled = bar_width * percent / 100;
|
||||
|
||||
// Draw progress bar outline
|
||||
tb_printf(2, row, TB_YELLOW | TB_BOLD, TB_BLUE, "[");
|
||||
tb_printf(bar_width + 3, row, TB_YELLOW | TB_BOLD, TB_BLUE, "]");
|
||||
|
||||
// Fill progress bar
|
||||
for(int i = 0; i < filled; ++i) { tb_set_cell(3 + i, row, '=', TB_YELLOW | TB_BOLD, TB_BLUE); }
|
||||
for(int i = 0; i < filled; ++i) {
|
||||
tb_set_cell(3 + i, row, '=', TB_YELLOW | TB_BOLD, TB_BLUE);
|
||||
}
|
||||
|
||||
tb_present();
|
||||
}
|
||||
|
||||
int compare(const char *path1, const char *path2)
|
||||
static void setup_screen(compare_state_t *state)
|
||||
{
|
||||
int ret = AARUF_STATUS_OK;
|
||||
aaruformat_context *ctx1 = NULL;
|
||||
aaruformat_context *ctx2 = NULL;
|
||||
bool imagesAreDifferent = false;
|
||||
char *strBuffer = NULL;
|
||||
UErrorCode u_error_code = U_ZERO_ERROR;
|
||||
int lr = 0;
|
||||
int rr = 0;
|
||||
uintattr_t appVerColor = TB_WHITE;
|
||||
uintattr_t imageVerColor = TB_WHITE;
|
||||
uintattr_t mediaTypeColor = TB_WHITE;
|
||||
uintattr_t creationTimeColor = TB_WHITE;
|
||||
uintattr_t lastWrittenTimeColor = TB_WHITE;
|
||||
uintattr_t partitionsColor = TB_WHITE;
|
||||
uintattr_t sessionsColor = TB_WHITE;
|
||||
uintattr_t sectorsColor = TB_WHITE;
|
||||
uintattr_t sectorSizeColor = TB_WHITE;
|
||||
uintattr_t versionColor = TB_WHITE;
|
||||
uint8_t sector_status1 = 0;
|
||||
uint8_t sector_status2 = 0;
|
||||
int width = tb_width();
|
||||
int height = tb_height();
|
||||
state->mid_x = width / 2;
|
||||
state->height = height;
|
||||
state->left_row = 9;
|
||||
state->right_row = 9;
|
||||
state->has_differences = false;
|
||||
|
||||
// Initialize termbox2
|
||||
if(tb_init() != 0) return 1;
|
||||
tb_clear();
|
||||
|
||||
// Get terminal dimensions
|
||||
int width = tb_width(); // Total number of columns
|
||||
int height = tb_height(); // Total number of rows
|
||||
int mid_x = width / 2; // Midpoint for horizontal split
|
||||
|
||||
tb_clear(); // Clear the screen buffer
|
||||
|
||||
// Draw left panel (blue background)
|
||||
// Draw panels and divider
|
||||
for(int y = 0; y < height; ++y)
|
||||
{
|
||||
for(int x = 0; x < mid_x; ++x)
|
||||
{
|
||||
tb_set_cell(x, y, ' ', TB_WHITE, TB_BLUE); // Set each cell to blank with blue background
|
||||
}
|
||||
for(int x = 0; x < state->mid_x; ++x)
|
||||
tb_set_cell(x, y, ' ', TB_WHITE, TB_BLUE);
|
||||
|
||||
tb_set_cell(state->mid_x, y, '|', TB_BLACK | TB_BOLD, TB_BLUE);
|
||||
|
||||
for(int x = state->mid_x + 1; x < width; ++x)
|
||||
tb_set_cell(x, y, ' ', TB_WHITE, TB_BLUE);
|
||||
}
|
||||
}
|
||||
|
||||
// Draw right panel (green background)
|
||||
for(int y = 0; y < height; ++y)
|
||||
{
|
||||
for(int x = mid_x + 1; x < width; ++x)
|
||||
{
|
||||
tb_set_cell(x, y, ' ', TB_WHITE, TB_BLUE); // Set each cell to blank with green background
|
||||
}
|
||||
}
|
||||
// Helper to print a field on both sides with comparison
|
||||
static void print_field_pair(compare_state_t *state, const char *label,
|
||||
const char *fmt, uintattr_t color,
|
||||
void *val1, void *val2, int label_len)
|
||||
{
|
||||
tb_printf(2, state->left_row, TB_WHITE | TB_BOLD, TB_BLUE, "%s", label);
|
||||
tb_printf(label_len, state->left_row, color, TB_BLUE, fmt, val1);
|
||||
|
||||
// Draw vertical divider line (gray background)
|
||||
for(int y = 0; y < height; ++y)
|
||||
{
|
||||
tb_set_cell(mid_x, y, '|', TB_BLACK | TB_BOLD, TB_BLUE); // Draw a vertical bar at the split
|
||||
}
|
||||
tb_printf(state->mid_x + 2, state->right_row, TB_WHITE | TB_BOLD, TB_BLUE, "%s", label);
|
||||
tb_printf(state->mid_x + label_len, state->right_row, color, TB_BLUE, fmt, val2);
|
||||
|
||||
// Print labels in each panel
|
||||
tb_printf(2, 1, TB_WHITE | TB_BOLD, TB_BLUE, path1); // Label in left panel
|
||||
tb_printf(mid_x + 2, 1, TB_WHITE | TB_BOLD, TB_BLUE, path2); // Label in right panel
|
||||
state->left_row++;
|
||||
state->right_row++;
|
||||
}
|
||||
|
||||
tb_present(); // Render the buffer to the terminal
|
||||
// Helper to compare and print integer fields
|
||||
static void compare_int_field(compare_state_t *state, const char *label, int label_len,
|
||||
uint64_t val1, uint64_t val2, const char *fmt)
|
||||
{
|
||||
uintattr_t color = (val1 != val2) ? TB_RED : TB_WHITE;
|
||||
if(val1 != val2) state->has_differences = true;
|
||||
|
||||
// Open the first AaruFormat image
|
||||
tb_printf(2, 2, TB_WHITE | TB_BOLD, TB_BLUE, "Opening image...");
|
||||
tb_present(); // Render the buffer to the terminal
|
||||
ctx1 = aaruf_open(path1);
|
||||
if(ctx1 == NULL)
|
||||
{
|
||||
tb_printf(2, 3, TB_RED | TB_BOLD, TB_BLUE, "Error opening: %s", errno);
|
||||
tb_present();
|
||||
goto finished;
|
||||
}
|
||||
print_field_pair(state, label, fmt, color, &val1, &val2, label_len);
|
||||
}
|
||||
|
||||
tb_printf(2, 2, TB_WHITE | TB_BOLD, TB_BLUE, "Image opened successfully...");
|
||||
// Helper to compare and print string fields (if at least one is non-NULL)
|
||||
static void compare_string_field(compare_state_t *state, const char *label, int label_len,
|
||||
const char *val1, const char *val2)
|
||||
{
|
||||
if(val1 == NULL && val2 == NULL) return;
|
||||
|
||||
// Open the second AaruFormat image
|
||||
tb_printf(mid_x + 2, 2, TB_WHITE | TB_BOLD, TB_BLUE, "Opening image...");
|
||||
tb_present(); // Render the buffer to the terminal
|
||||
ctx2 = aaruf_open(path2);
|
||||
if(ctx2 == NULL)
|
||||
{
|
||||
tb_printf(mid_x + 2, 3, TB_RED | TB_BOLD, TB_BLUE, "Error opening: %s", errno);
|
||||
tb_present();
|
||||
goto finished;
|
||||
}
|
||||
tb_printf(2, state->left_row, TB_WHITE | TB_BOLD, TB_BLUE, "%s", label);
|
||||
if(val1) tb_printf(label_len, state->left_row, TB_WHITE, TB_BLUE, "%s", val1);
|
||||
|
||||
tb_printf(mid_x + 2, 2, TB_WHITE | TB_BOLD, TB_BLUE, "Image opened successfully...");
|
||||
tb_printf(state->mid_x + 2, state->right_row, TB_WHITE | TB_BOLD, TB_BLUE, "%s", label);
|
||||
if(val2) tb_printf(state->mid_x + label_len, state->right_row, TB_WHITE, TB_BLUE, "%s", val2);
|
||||
|
||||
u_error_code =
|
||||
u_strCompare((const UChar *)ctx1->header.application, -1, (const UChar *)ctx2->header.application, -1, false);
|
||||
if(u_error_code != U_ZERO_ERROR) imagesAreDifferent = true;
|
||||
state->left_row++;
|
||||
state->right_row++;
|
||||
}
|
||||
|
||||
strBuffer = malloc(65);
|
||||
// Helper to convert and print UTF-16 application name
|
||||
static void print_application_name(compare_state_t *state,
|
||||
const char *app1, const char *app2)
|
||||
{
|
||||
char strBuffer[65];
|
||||
UErrorCode u_error_code = U_ZERO_ERROR;
|
||||
|
||||
// Left side
|
||||
memset(strBuffer, 0, 65);
|
||||
u_error_code = U_ZERO_ERROR; // Reset error code before conversion
|
||||
ucnv_convert(NULL, "UTF-16LE", strBuffer, 64, ctx1->header.application, 64, &u_error_code);
|
||||
ucnv_convert(NULL, "UTF-16LE", strBuffer, 64, app1, 64, &u_error_code);
|
||||
tb_printf(2, 3, TB_WHITE | TB_BOLD, TB_BLUE, "Application: ");
|
||||
if(u_error_code == U_ZERO_ERROR)
|
||||
{
|
||||
tb_printf(2, 3, TB_WHITE | TB_BOLD, TB_BLUE, "Application: ");
|
||||
tb_printf(15, 3, TB_WHITE, TB_BLUE, "%s", strBuffer);
|
||||
}
|
||||
tb_present(); // Render the buffer to the terminal
|
||||
|
||||
// Right side
|
||||
memset(strBuffer, 0, 65);
|
||||
u_error_code = U_ZERO_ERROR; // Reset error code before conversion
|
||||
ucnv_convert(NULL, "UTF-16LE", strBuffer, 64, ctx2->header.application, 64, &u_error_code);
|
||||
if(u_error_code == U_ZERO_ERROR)
|
||||
{
|
||||
tb_printf(mid_x + 2, 3, TB_WHITE | TB_BOLD, TB_BLUE, "Application: ");
|
||||
tb_printf(mid_x + 15, 3, TB_WHITE, TB_BLUE, "%s", strBuffer);
|
||||
}
|
||||
tb_present(); // Render the buffer to the terminal
|
||||
free(strBuffer);
|
||||
|
||||
// Compare header information
|
||||
if(ctx1->header.applicationMajorVersion != ctx2->header.applicationMajorVersion)
|
||||
{
|
||||
imagesAreDifferent = true;
|
||||
appVerColor = TB_RED;
|
||||
}
|
||||
|
||||
if(ctx1->header.applicationMinorVersion != ctx2->header.applicationMinorVersion)
|
||||
{
|
||||
imagesAreDifferent = true;
|
||||
appVerColor = TB_RED;
|
||||
}
|
||||
|
||||
if(ctx1->header.imageMajorVersion != ctx2->header.imageMajorVersion)
|
||||
{
|
||||
imagesAreDifferent = true;
|
||||
imageVerColor = TB_RED;
|
||||
}
|
||||
|
||||
if(ctx1->header.imageMinorVersion != ctx2->header.imageMinorVersion)
|
||||
{
|
||||
imagesAreDifferent = true;
|
||||
imageVerColor = TB_RED;
|
||||
}
|
||||
|
||||
if(ctx1->header.mediaType != ctx2->header.mediaType)
|
||||
{
|
||||
imagesAreDifferent = true;
|
||||
mediaTypeColor = TB_RED;
|
||||
}
|
||||
|
||||
if(ctx1->header.creationTime != ctx2->header.creationTime)
|
||||
{
|
||||
imagesAreDifferent = true;
|
||||
creationTimeColor = TB_RED;
|
||||
}
|
||||
|
||||
if(ctx1->header.lastWrittenTime != ctx2->header.lastWrittenTime)
|
||||
{
|
||||
imagesAreDifferent = true;
|
||||
lastWrittenTimeColor = TB_RED;
|
||||
}
|
||||
|
||||
// Print header information for the first image
|
||||
tb_printf(2, 4, TB_WHITE | TB_BOLD, TB_BLUE, "Application version: ");
|
||||
tb_printf(23, 4, appVerColor, TB_BLUE, "%d.%d", ctx1->header.applicationMajorVersion,
|
||||
ctx1->header.applicationMinorVersion);
|
||||
tb_printf(2, 5, TB_WHITE | TB_BOLD, TB_BLUE, "Image format version: ");
|
||||
tb_printf(24, 5, imageVerColor, TB_BLUE, "%d.%d", ctx1->header.imageMajorVersion, ctx1->header.imageMinorVersion);
|
||||
tb_printf(2, 6, TB_WHITE | TB_BOLD, TB_BLUE, "Media type: ");
|
||||
tb_printf(14, 6, mediaTypeColor, TB_BLUE, "%u", ctx1->header.mediaType);
|
||||
tb_printf(2, 7, TB_WHITE | TB_BOLD, TB_BLUE, "Creation time: ");
|
||||
tb_printf(17, 7, creationTimeColor, TB_BLUE, "%lld", ctx1->header.creationTime);
|
||||
tb_printf(2, 8, TB_WHITE | TB_BOLD, TB_BLUE, "Last written time: ");
|
||||
tb_printf(21, 8, lastWrittenTimeColor, TB_BLUE, "%lld", ctx1->header.lastWrittenTime);
|
||||
tb_present(); // Render the buffer to the terminal
|
||||
|
||||
// Print header information for the second image
|
||||
tb_printf(mid_x + 2, 4, TB_WHITE | TB_BOLD, TB_BLUE, "Application version: ");
|
||||
tb_printf(mid_x + 23, 4, appVerColor, TB_BLUE, "%d.%d", ctx2->header.applicationMajorVersion,
|
||||
ctx2->header.applicationMinorVersion);
|
||||
tb_printf(mid_x + 2, 5, TB_WHITE | TB_BOLD, TB_BLUE, "Image format version: ");
|
||||
tb_printf(mid_x + 24, 5, imageVerColor, TB_BLUE, "%d.%d", ctx2->header.imageMajorVersion,
|
||||
ctx2->header.imageMinorVersion);
|
||||
tb_printf(mid_x + 2, 6, TB_WHITE | TB_BOLD, TB_BLUE, "Media type: ");
|
||||
tb_printf(mid_x + 14, 6, mediaTypeColor, TB_BLUE, "%u", ctx2->header.mediaType);
|
||||
tb_printf(mid_x + 2, 7, TB_WHITE | TB_BOLD, TB_BLUE, "Creation time: ");
|
||||
tb_printf(mid_x + 17, 7, creationTimeColor, TB_BLUE, "%lld", ctx2->header.creationTime);
|
||||
tb_printf(mid_x + 2, 8, TB_WHITE | TB_BOLD, TB_BLUE, "Last written time: ");
|
||||
tb_printf(mid_x + 21, 8, lastWrittenTimeColor, TB_BLUE, "%lld", ctx2->header.lastWrittenTime);
|
||||
tb_present(); // Render the buffer to the terminal
|
||||
|
||||
// Compare ImageInfo
|
||||
u_error_code = U_ZERO_ERROR;
|
||||
u_error_code = u_strCompare((const UChar *)ctx1->image_info.Application, -1,
|
||||
(const UChar *)ctx2->image_info.Application, -1, false);
|
||||
if(u_error_code != U_ZERO_ERROR) imagesAreDifferent = true;
|
||||
ucnv_convert(NULL, "UTF-16LE", strBuffer, 64, app2, 64, &u_error_code);
|
||||
tb_printf(state->mid_x + 2, 3, TB_WHITE | TB_BOLD, TB_BLUE, "Application: ");
|
||||
if(u_error_code == U_ZERO_ERROR)
|
||||
tb_printf(state->mid_x + 15, 3, TB_WHITE, TB_BLUE, "%s", strBuffer);
|
||||
}
|
||||
|
||||
// Current left row
|
||||
lr = 9;
|
||||
// Current right row
|
||||
rr = 9;
|
||||
// Compare header information
|
||||
static void compare_headers(compare_state_t *state,
|
||||
aaruformat_context *ctx1, aaruformat_context *ctx2)
|
||||
{
|
||||
// Check application name difference
|
||||
UErrorCode u_err = u_strCompare((const UChar *)ctx1->header.application, -1,
|
||||
(const UChar *)ctx2->header.application, -1, false);
|
||||
if(u_err != U_ZERO_ERROR) state->has_differences = true;
|
||||
|
||||
if(ctx1->image_info.HasPartitions != ctx2->image_info.HasPartitions)
|
||||
{
|
||||
imagesAreDifferent = true;
|
||||
partitionsColor = TB_RED;
|
||||
}
|
||||
if(ctx1->image_info.HasSessions != ctx2->image_info.HasSessions)
|
||||
{
|
||||
imagesAreDifferent = true;
|
||||
sessionsColor = TB_RED;
|
||||
}
|
||||
if(ctx1->image_info.Sectors != ctx2->image_info.Sectors)
|
||||
{
|
||||
imagesAreDifferent = true;
|
||||
sectorsColor = TB_RED;
|
||||
}
|
||||
if(ctx1->image_info.SectorSize != ctx2->image_info.SectorSize)
|
||||
{
|
||||
imagesAreDifferent = true;
|
||||
sectorSizeColor = TB_RED;
|
||||
}
|
||||
if(ctx1->image_info.Version != ctx2->image_info.Version)
|
||||
{
|
||||
imagesAreDifferent = true;
|
||||
versionColor = TB_RED;
|
||||
}
|
||||
print_application_name(state, ctx1->header.application, ctx2->header.application);
|
||||
|
||||
// Compare version fields
|
||||
uintattr_t app_ver_color = (ctx1->header.applicationMajorVersion != ctx2->header.applicationMajorVersion ||
|
||||
ctx1->header.applicationMinorVersion != ctx2->header.applicationMinorVersion)
|
||||
? TB_RED : TB_WHITE;
|
||||
uintattr_t img_ver_color = (ctx1->header.imageMajorVersion != ctx2->header.imageMajorVersion ||
|
||||
ctx1->header.imageMinorVersion != ctx2->header.imageMinorVersion)
|
||||
? TB_RED : TB_WHITE;
|
||||
uintattr_t media_color = (ctx1->header.mediaType != ctx2->header.mediaType) ? TB_RED : TB_WHITE;
|
||||
uintattr_t create_color = (ctx1->header.creationTime != ctx2->header.creationTime) ? TB_RED : TB_WHITE;
|
||||
uintattr_t modified_color = (ctx1->header.lastWrittenTime != ctx2->header.lastWrittenTime) ? TB_RED : TB_WHITE;
|
||||
|
||||
if(app_ver_color == TB_RED || img_ver_color == TB_RED || media_color == TB_RED ||
|
||||
create_color == TB_RED || modified_color == TB_RED)
|
||||
state->has_differences = true;
|
||||
|
||||
// Print header fields
|
||||
tb_printf(2, 4, TB_WHITE | TB_BOLD, TB_BLUE, "Application version: ");
|
||||
tb_printf(23, 4, app_ver_color, TB_BLUE, "%d.%d",
|
||||
ctx1->header.applicationMajorVersion, ctx1->header.applicationMinorVersion);
|
||||
tb_printf(state->mid_x + 2, 4, TB_WHITE | TB_BOLD, TB_BLUE, "Application version: ");
|
||||
tb_printf(state->mid_x + 23, 4, app_ver_color, TB_BLUE, "%d.%d",
|
||||
ctx2->header.applicationMajorVersion, ctx2->header.applicationMinorVersion);
|
||||
|
||||
tb_printf(2, 5, TB_WHITE | TB_BOLD, TB_BLUE, "Image format version: ");
|
||||
tb_printf(24, 5, img_ver_color, TB_BLUE, "%d.%d",
|
||||
ctx1->header.imageMajorVersion, ctx1->header.imageMinorVersion);
|
||||
tb_printf(state->mid_x + 2, 5, TB_WHITE | TB_BOLD, TB_BLUE, "Image format version: ");
|
||||
tb_printf(state->mid_x + 24, 5, img_ver_color, TB_BLUE, "%d.%d",
|
||||
ctx2->header.imageMajorVersion, ctx2->header.imageMinorVersion);
|
||||
|
||||
tb_printf(2, 6, TB_WHITE | TB_BOLD, TB_BLUE, "Media type: ");
|
||||
tb_printf(14, 6, media_color, TB_BLUE, "%u", ctx1->header.mediaType);
|
||||
tb_printf(state->mid_x + 2, 6, TB_WHITE | TB_BOLD, TB_BLUE, "Media type: ");
|
||||
tb_printf(state->mid_x + 14, 6, media_color, TB_BLUE, "%u", ctx2->header.mediaType);
|
||||
|
||||
tb_printf(2, 7, TB_WHITE | TB_BOLD, TB_BLUE, "Creation time: ");
|
||||
tb_printf(17, 7, create_color, TB_BLUE, "%lld", ctx1->header.creationTime);
|
||||
tb_printf(state->mid_x + 2, 7, TB_WHITE | TB_BOLD, TB_BLUE, "Creation time: ");
|
||||
tb_printf(state->mid_x + 17, 7, create_color, TB_BLUE, "%lld", ctx2->header.creationTime);
|
||||
|
||||
tb_printf(2, 8, TB_WHITE | TB_BOLD, TB_BLUE, "Last written time: ");
|
||||
tb_printf(21, 8, modified_color, TB_BLUE, "%lld", ctx1->header.lastWrittenTime);
|
||||
tb_printf(state->mid_x + 2, 8, TB_WHITE | TB_BOLD, TB_BLUE, "Last written time: ");
|
||||
tb_printf(state->mid_x + 21, 8, modified_color, TB_BLUE, "%lld", ctx2->header.lastWrittenTime);
|
||||
|
||||
tb_printf(2, lr, TB_WHITE | TB_BOLD, TB_BLUE, "Has partitions?: ");
|
||||
tb_printf(19, lr++, partitionsColor, TB_BLUE, "%s", ctx1->image_info.HasPartitions ? "yes" : "no");
|
||||
tb_printf(2, lr, TB_WHITE | TB_BOLD, TB_BLUE, "Has sessions?: ");
|
||||
tb_printf(17, lr++, sessionsColor, TB_BLUE, "%s", ctx1->image_info.HasSessions ? "yes" : "no");
|
||||
tb_printf(2, lr, TB_WHITE | TB_BOLD, TB_BLUE, "Image size without headers: ");
|
||||
tb_printf(30, lr++, TB_WHITE, TB_BLUE, "%llu bytes", ctx1->image_info.ImageSize);
|
||||
tb_printf(2, lr, TB_WHITE | TB_BOLD, TB_BLUE, "Image contains: ");
|
||||
tb_printf(18, lr++, sectorsColor, TB_BLUE, "%llu sectors", ctx1->image_info.Sectors);
|
||||
tb_printf(2, lr, TB_WHITE | TB_BOLD, TB_BLUE, "Biggest sector is: ");
|
||||
tb_printf(21, lr++, sectorSizeColor, TB_BLUE, "%d bytes", ctx1->image_info.SectorSize);
|
||||
tb_printf(2, lr, TB_WHITE | TB_BOLD, TB_BLUE, "Image version: ");
|
||||
tb_printf(17, lr++, versionColor, TB_BLUE, "%s", ctx1->image_info.Version);
|
||||
tb_present();
|
||||
}
|
||||
|
||||
// Compare image info
|
||||
static void compare_image_info(compare_state_t *state,
|
||||
aaruformat_context *ctx1, aaruformat_context *ctx2)
|
||||
{
|
||||
compare_int_field(state, "Has partitions?: ", 19,
|
||||
ctx1->image_info.HasPartitions, ctx2->image_info.HasPartitions, "%s");
|
||||
state->left_row--;
|
||||
state->right_row--;
|
||||
tb_printf(19, state->left_row, (ctx1->image_info.HasPartitions != ctx2->image_info.HasPartitions) ? TB_RED : TB_WHITE,
|
||||
TB_BLUE, "%s", ctx1->image_info.HasPartitions ? "yes" : "no");
|
||||
tb_printf(state->mid_x + 19, state->right_row,
|
||||
(ctx1->image_info.HasPartitions != ctx2->image_info.HasPartitions) ? TB_RED : TB_WHITE,
|
||||
TB_BLUE, "%s", ctx2->image_info.HasPartitions ? "yes" : "no");
|
||||
state->left_row++;
|
||||
state->right_row++;
|
||||
|
||||
compare_int_field(state, "Has sessions?: ", 17,
|
||||
ctx1->image_info.HasSessions, ctx2->image_info.HasSessions, "%s");
|
||||
state->left_row--;
|
||||
state->right_row--;
|
||||
tb_printf(17, state->left_row, (ctx1->image_info.HasSessions != ctx2->image_info.HasSessions) ? TB_RED : TB_WHITE,
|
||||
TB_BLUE, "%s", ctx1->image_info.HasSessions ? "yes" : "no");
|
||||
tb_printf(state->mid_x + 17, state->right_row,
|
||||
(ctx1->image_info.HasSessions != ctx2->image_info.HasSessions) ? TB_RED : TB_WHITE,
|
||||
TB_BLUE, "%s", ctx2->image_info.HasSessions ? "yes" : "no");
|
||||
state->left_row++;
|
||||
state->right_row++;
|
||||
|
||||
tb_printf(2, state->left_row, TB_WHITE | TB_BOLD, TB_BLUE, "Image size without headers: ");
|
||||
tb_printf(30, state->left_row, TB_WHITE, TB_BLUE, "%llu bytes", ctx1->image_info.ImageSize);
|
||||
tb_printf(state->mid_x + 2, state->right_row, TB_WHITE | TB_BOLD, TB_BLUE, "Image size without headers: ");
|
||||
tb_printf(state->mid_x + 30, state->right_row, TB_WHITE, TB_BLUE, "%llu bytes", ctx2->image_info.ImageSize);
|
||||
state->left_row++;
|
||||
state->right_row++;
|
||||
|
||||
compare_int_field(state, "Image contains: ", 18,
|
||||
ctx1->image_info.Sectors, ctx2->image_info.Sectors, "%llu sectors");
|
||||
compare_int_field(state, "Biggest sector is: ", 21,
|
||||
ctx1->image_info.SectorSize, ctx2->image_info.SectorSize, "%d bytes");
|
||||
|
||||
uintattr_t ver_color = TB_WHITE;
|
||||
if(ctx1->image_info.Version && ctx2->image_info.Version &&
|
||||
strcmp(ctx1->image_info.Version, ctx2->image_info.Version) != 0) {
|
||||
ver_color = TB_RED;
|
||||
state->has_differences = true;
|
||||
}
|
||||
|
||||
tb_printf(2, state->left_row, TB_WHITE | TB_BOLD, TB_BLUE, "Image version: ");
|
||||
if(ctx1->image_info.Version) tb_printf(17, state->left_row, ver_color, TB_BLUE, "%s", ctx1->image_info.Version);
|
||||
tb_printf(state->mid_x + 2, state->right_row, TB_WHITE | TB_BOLD, TB_BLUE, "Image version: ");
|
||||
if(ctx2->image_info.Version) tb_printf(state->mid_x + 17, state->right_row, ver_color, TB_BLUE, "%s", ctx2->image_info.Version);
|
||||
state->left_row++;
|
||||
state->right_row++;
|
||||
|
||||
tb_printf(mid_x + 2, rr, TB_WHITE | TB_BOLD, TB_BLUE, "Has partitions?: ");
|
||||
tb_printf(mid_x + 19, rr++, partitionsColor, TB_BLUE, "%s", ctx2->image_info.HasPartitions ? "yes" : "no");
|
||||
tb_printf(mid_x + 2, rr, TB_WHITE | TB_BOLD, TB_BLUE, "Has sessions?: ");
|
||||
tb_printf(mid_x + 17, rr++, sessionsColor, TB_BLUE, "%s", ctx2->image_info.HasSessions ? "yes" : "no");
|
||||
tb_printf(mid_x + 2, rr, TB_WHITE | TB_BOLD, TB_BLUE, "Image size without headers: ");
|
||||
tb_printf(mid_x + 30, rr++, TB_WHITE, TB_BLUE, "%llu bytes", ctx2->image_info.ImageSize);
|
||||
tb_printf(mid_x + 2, rr, TB_WHITE | TB_BOLD, TB_BLUE, "Image contains: ");
|
||||
tb_printf(mid_x + 18, rr++, sectorsColor, TB_BLUE, "%llu sectors", ctx2->image_info.Sectors);
|
||||
tb_printf(mid_x + 2, rr, TB_WHITE | TB_BOLD, TB_BLUE, "Biggest sector is: ");
|
||||
tb_printf(mid_x + 21, rr++, sectorSizeColor, TB_BLUE, "%d bytes", ctx2->image_info.SectorSize);
|
||||
tb_printf(mid_x + 2, rr, TB_WHITE | TB_BOLD, TB_BLUE, "Image version: ");
|
||||
tb_printf(mid_x + 17, rr++, versionColor, TB_BLUE, "%s", ctx2->image_info.Version);
|
||||
tb_present();
|
||||
}
|
||||
|
||||
if(ctx1->image_info.Application != NULL || ctx2->image_info.Application != NULL)
|
||||
// Compare metadata fields
|
||||
static void compare_metadata(compare_state_t *state,
|
||||
aaruformat_context *ctx1, aaruformat_context *ctx2)
|
||||
{
|
||||
compare_string_field(state, "Application version: ", 23,
|
||||
ctx1->image_info.ApplicationVersion, ctx2->image_info.ApplicationVersion);
|
||||
compare_string_field(state, "Creator: ", 11, ctx1->creator, ctx2->creator);
|
||||
|
||||
compare_int_field(state, "Creation time: ", 17,
|
||||
ctx1->image_info.CreationTime, ctx2->image_info.CreationTime, "%lld");
|
||||
compare_int_field(state, "Last written time: ", 21,
|
||||
ctx1->image_info.LastModificationTime, ctx2->image_info.LastModificationTime, "%lld");
|
||||
|
||||
compare_string_field(state, "Comments: ", 12, ctx1->comments, ctx2->comments);
|
||||
compare_string_field(state, "Media title: ", 15, ctx1->media_title, ctx2->media_title);
|
||||
compare_string_field(state, "Media manufacturer: ", 22,
|
||||
ctx1->media_manufacturer, ctx2->media_manufacturer);
|
||||
compare_string_field(state, "Media serial number: ", 23,
|
||||
ctx1->media_serial_number, ctx2->media_serial_number);
|
||||
compare_string_field(state, "Media barcode: ", 17, ctx1->media_barcode, ctx2->media_barcode);
|
||||
compare_string_field(state, "Media part number: ", 21,
|
||||
ctx1->media_part_number, ctx2->media_part_number);
|
||||
|
||||
compare_int_field(state, "Media type: ", 14,
|
||||
ctx1->image_info.MediaType, ctx2->image_info.MediaType, "%u");
|
||||
|
||||
if(ctx1->media_sequence > 0 || ctx1->last_media_sequence > 0 ||
|
||||
ctx2->media_sequence > 0 || ctx2->last_media_sequence > 0)
|
||||
{
|
||||
strBuffer = malloc(65);
|
||||
memset(strBuffer, 0, 65);
|
||||
u_error_code = U_ZERO_ERROR; // Reset error code before conversion
|
||||
ucnv_convert(NULL, "UTF-16LE", strBuffer, 64, (const char *)ctx1->image_info.Application, 64, &u_error_code);
|
||||
tb_printf(2, lr, TB_WHITE | TB_BOLD, TB_BLUE, "Application: ");
|
||||
if(u_error_code == U_ZERO_ERROR) tb_printf(15, lr, TB_WHITE, TB_BLUE, "%s", strBuffer);
|
||||
lr++;
|
||||
|
||||
memset(strBuffer, 0, 65);
|
||||
u_error_code = U_ZERO_ERROR; // Reset error code before conversion
|
||||
ucnv_convert(NULL, "UTF-16LE", strBuffer, 64, (const char *)ctx2->image_info.Application, 64, &u_error_code);
|
||||
tb_printf(mid_x + 2, rr, TB_WHITE | TB_BOLD, TB_BLUE, "Application: ");
|
||||
if(u_error_code == U_ZERO_ERROR) tb_printf(mid_x + 15, rr, TB_WHITE, TB_BLUE, "%s", strBuffer);
|
||||
rr++;
|
||||
|
||||
free(strBuffer);
|
||||
tb_present();
|
||||
tb_printf(2, state->left_row, TB_WHITE | TB_BOLD, TB_BLUE,
|
||||
"Media is number %d in a set of %d media",
|
||||
ctx1->media_sequence, ctx1->last_media_sequence);
|
||||
tb_printf(state->mid_x + 2, state->right_row, TB_WHITE | TB_BOLD, TB_BLUE,
|
||||
"Media is number %d in a set of %d media",
|
||||
ctx2->media_sequence, ctx2->last_media_sequence);
|
||||
state->left_row++;
|
||||
state->right_row++;
|
||||
}
|
||||
|
||||
if(ctx1->image_info.ApplicationVersion != NULL || ctx2->image_info.ApplicationVersion != NULL)
|
||||
compare_string_field(state, "Drive manufacturer: ", 22,
|
||||
ctx1->drive_manufacturer, ctx2->drive_manufacturer);
|
||||
compare_string_field(state, "Drive model: ", 15, ctx1->drive_model, ctx2->drive_model);
|
||||
compare_string_field(state, "Drive serial number: ", 23,
|
||||
ctx1->drive_serial_number, ctx2->drive_serial_number);
|
||||
compare_string_field(state, "Drive firmware revision: ", 27,
|
||||
ctx1->drive_firmware_revision, ctx2->drive_firmware_revision);
|
||||
|
||||
compare_int_field(state, "XML media type: ", 18,
|
||||
ctx1->image_info.MetadataMediaType, ctx2->image_info.MetadataMediaType, "%d");
|
||||
|
||||
if(ctx1->cylinders > 0 || ctx1->heads > 0 || ctx1->sectors_per_track > 0 ||
|
||||
ctx2->cylinders > 0 || ctx2->heads > 0 || ctx2->sectors_per_track > 0)
|
||||
{
|
||||
tb_printf(2, lr, TB_WHITE | TB_BOLD, TB_BLUE, "Application version: ");
|
||||
tb_printf(23, lr++, TB_WHITE, TB_BLUE, "%s", ctx1->image_info.ApplicationVersion);
|
||||
|
||||
tb_printf(mid_x + 2, rr, TB_WHITE | TB_BOLD, TB_BLUE, "Application version: ");
|
||||
tb_printf(mid_x + 23, rr++, TB_WHITE, TB_BLUE, "%s", ctx2->image_info.ApplicationVersion);
|
||||
}
|
||||
if(ctx1->creator != NULL || ctx2->creator != NULL)
|
||||
{
|
||||
tb_printf(2, lr, TB_WHITE | TB_BOLD, TB_BLUE, "Creator: ");
|
||||
tb_printf(11, lr++, TB_WHITE, TB_BLUE, "%s", ctx1->creator);
|
||||
|
||||
tb_printf(mid_x + 2, rr, TB_WHITE | TB_BOLD, TB_BLUE, "Creator: ");
|
||||
tb_printf(mid_x + 11, rr++, TB_WHITE, TB_BLUE, "%s", ctx2->creator);
|
||||
}
|
||||
|
||||
tb_printf(2, lr, TB_WHITE | TB_BOLD, TB_BLUE, "Creation time: ");
|
||||
tb_printf(17, lr++, TB_WHITE, TB_BLUE, "%lld", ctx1->image_info.CreationTime);
|
||||
|
||||
tb_printf(mid_x + 2, rr, TB_WHITE | TB_BOLD, TB_BLUE, "Creation time: ");
|
||||
tb_printf(mid_x + 17, rr++, TB_WHITE, TB_BLUE, "%lld", ctx2->image_info.CreationTime);
|
||||
|
||||
tb_printf(2, lr, TB_WHITE | TB_BOLD, TB_BLUE, "Last written time: ");
|
||||
tb_printf(21, lr++, TB_WHITE, TB_BLUE, "%lld", ctx1->image_info.LastModificationTime);
|
||||
|
||||
tb_printf(mid_x + 2, rr, TB_WHITE | TB_BOLD, TB_BLUE, "Last written time: ");
|
||||
tb_printf(mid_x + 21, rr++, TB_WHITE, TB_BLUE, "%lld", ctx2->image_info.LastModificationTime);
|
||||
|
||||
if(ctx1->comments != NULL || ctx2->comments != NULL)
|
||||
{
|
||||
tb_printf(2, lr, TB_WHITE | TB_BOLD, TB_BLUE, "Comments: ");
|
||||
tb_printf(12, lr++, TB_WHITE, TB_BLUE, "%s", ctx1->comments);
|
||||
|
||||
tb_printf(mid_x + 2, rr, TB_WHITE | TB_BOLD, TB_BLUE, "Comments: ");
|
||||
tb_printf(mid_x + 12, rr++, TB_WHITE, TB_BLUE, "%s", ctx2->comments);
|
||||
}
|
||||
if(ctx1->media_title != NULL || ctx2->media_title != NULL)
|
||||
{
|
||||
tb_printf(2, lr, TB_WHITE | TB_BOLD, TB_BLUE, "Media title: ");
|
||||
tb_printf(15, lr++, TB_WHITE, TB_BLUE, "%s", ctx1->media_title);
|
||||
|
||||
tb_printf(mid_x + 2, rr, TB_WHITE | TB_BOLD, TB_BLUE, "Media title: ");
|
||||
tb_printf(mid_x + 15, rr++, TB_WHITE, TB_BLUE, "%s", ctx2->media_title);
|
||||
}
|
||||
if(ctx1->media_manufacturer != NULL || ctx2->media_manufacturer != NULL)
|
||||
{
|
||||
tb_printf(2, lr, TB_WHITE | TB_BOLD, TB_BLUE, "Media manufacturer: ");
|
||||
tb_printf(22, lr++, TB_WHITE, TB_BLUE, "%s", ctx1->media_manufacturer);
|
||||
|
||||
tb_printf(mid_x + 2, rr, TB_WHITE | TB_BOLD, TB_BLUE, "Media manufacturer: ");
|
||||
tb_printf(mid_x + 22, rr++, TB_WHITE, TB_BLUE, "%s", ctx2->media_manufacturer);
|
||||
}
|
||||
if(ctx1->media_serial_number != NULL || ctx2->media_serial_number != NULL)
|
||||
{
|
||||
tb_printf(2, lr, TB_WHITE | TB_BOLD, TB_BLUE, "Media serial number: ");
|
||||
tb_printf(23, lr++, TB_WHITE, TB_BLUE, "%s", ctx1->media_serial_number);
|
||||
|
||||
tb_printf(mid_x + 2, rr, TB_WHITE | TB_BOLD, TB_BLUE, "Media serial number: ");
|
||||
tb_printf(mid_x + 23, rr++, TB_WHITE, TB_BLUE, "%s", ctx2->media_serial_number);
|
||||
}
|
||||
if(ctx1->media_barcode != NULL || ctx2->media_barcode != NULL)
|
||||
{
|
||||
tb_printf(2, lr, TB_WHITE | TB_BOLD, TB_BLUE, "Media barcode: ");
|
||||
tb_printf(17, lr++, TB_WHITE, TB_BLUE, "%s", ctx1->media_barcode);
|
||||
|
||||
tb_printf(mid_x + 2, rr, TB_WHITE | TB_BOLD, TB_BLUE, "Media barcode: ");
|
||||
tb_printf(mid_x + 17, rr++, TB_WHITE, TB_BLUE, "%s", ctx2->media_barcode);
|
||||
}
|
||||
if(ctx1->media_part_number != NULL || ctx2->media_part_number != NULL)
|
||||
{
|
||||
tb_printf(2, lr, TB_WHITE | TB_BOLD, TB_BLUE, "Media part number: ");
|
||||
tb_printf(21, lr++, TB_WHITE, TB_BLUE, "%s", ctx1->media_part_number);
|
||||
|
||||
tb_printf(mid_x + 2, rr, TB_WHITE | TB_BOLD, TB_BLUE, "Media part number: ");
|
||||
tb_printf(mid_x + 21, rr++, TB_WHITE, TB_BLUE, "%s", ctx2->media_part_number);
|
||||
}
|
||||
tb_printf(2, lr, TB_WHITE | TB_BOLD, TB_BLUE, "Media type: ");
|
||||
tb_printf(14, lr++, TB_WHITE, TB_BLUE, "%u", ctx1->image_info.MediaType);
|
||||
|
||||
tb_printf(mid_x + 2, rr, TB_WHITE | TB_BOLD, TB_BLUE, "Media type: ");
|
||||
tb_printf(mid_x + 14, rr++, TB_WHITE, TB_BLUE, "%u", ctx2->image_info.MediaType);
|
||||
|
||||
if(ctx1->media_sequence > 0 || ctx1->last_media_sequence > 0 || ctx2->media_sequence > 0 ||
|
||||
ctx2->last_media_sequence > 0)
|
||||
{
|
||||
tb_printf(2, lr++, TB_WHITE | TB_BOLD, TB_BLUE, "Media is number %d in a set of %d media", ctx1->media_sequence,
|
||||
ctx1->last_media_sequence);
|
||||
|
||||
tb_printf(mid_x + 2, rr++, TB_WHITE | TB_BOLD, TB_BLUE, "Media is number %d in a set of %d media",
|
||||
ctx2->media_sequence, ctx2->last_media_sequence);
|
||||
}
|
||||
|
||||
if(ctx1->drive_manufacturer != NULL || ctx2->drive_manufacturer != NULL)
|
||||
{
|
||||
tb_printf(2, lr, TB_WHITE | TB_BOLD, TB_BLUE, "Drive manufacturer: ");
|
||||
tb_printf(22, lr++, TB_WHITE, TB_BLUE, "%s", ctx1->drive_manufacturer);
|
||||
|
||||
tb_printf(mid_x + 2, rr, TB_WHITE | TB_BOLD, TB_BLUE, "Drive manufacturer: ");
|
||||
tb_printf(mid_x + 22, rr++, TB_WHITE, TB_BLUE, "%s", ctx2->drive_manufacturer);
|
||||
}
|
||||
if(ctx1->drive_model != NULL || ctx2->drive_model != NULL)
|
||||
{
|
||||
tb_printf(2, lr, TB_WHITE | TB_BOLD, TB_BLUE, "Drive model: ");
|
||||
tb_printf(15, lr++, TB_WHITE, TB_BLUE, "%s", ctx1->drive_model);
|
||||
|
||||
tb_printf(mid_x + 2, rr, TB_WHITE | TB_BOLD, TB_BLUE, "Drive model: ");
|
||||
tb_printf(mid_x + 15, rr++, TB_WHITE, TB_BLUE, "%s", ctx2->drive_model);
|
||||
}
|
||||
if(ctx1->drive_serial_number != NULL || ctx2->drive_serial_number != NULL)
|
||||
{
|
||||
tb_printf(2, lr, TB_WHITE | TB_BOLD, TB_BLUE, "Drive serial number: ");
|
||||
tb_printf(23, lr++, TB_WHITE, TB_BLUE, "%s", ctx1->drive_serial_number);
|
||||
|
||||
tb_printf(mid_x + 2, rr, TB_WHITE | TB_BOLD, TB_BLUE, "Drive serial number: ");
|
||||
tb_printf(mid_x + 23, rr++, TB_WHITE, TB_BLUE, "%s", ctx2->drive_serial_number);
|
||||
}
|
||||
if(ctx1->drive_firmware_revision != NULL || ctx2->drive_firmware_revision != NULL)
|
||||
{
|
||||
tb_printf(2, lr, TB_WHITE | TB_BOLD, TB_BLUE, "Drive firmware revision: ");
|
||||
tb_printf(27, lr++, TB_WHITE, TB_BLUE, "%s", ctx1->drive_firmware_revision);
|
||||
|
||||
tb_printf(mid_x + 2, rr, TB_WHITE | TB_BOLD, TB_BLUE, "Drive firmware revision: ");
|
||||
tb_printf(mid_x + 27, rr++, TB_WHITE, TB_BLUE, "%s", ctx2->drive_firmware_revision);
|
||||
}
|
||||
tb_printf(2, lr, TB_WHITE | TB_BOLD, TB_BLUE, "XML media type: ");
|
||||
tb_printf(18, lr++, TB_WHITE, TB_BLUE, "%d", ctx1->image_info.MetadataMediaType);
|
||||
|
||||
tb_printf(mid_x + 2, rr, TB_WHITE | TB_BOLD, TB_BLUE, "XML media type: ");
|
||||
tb_printf(mid_x + 18, rr++, TB_WHITE, TB_BLUE, "%d", ctx2->image_info.MetadataMediaType);
|
||||
|
||||
if(ctx1->cylinders > 0 || ctx1->heads > 0 || ctx1->sectors_per_track > 0 || ctx2->cylinders > 0 ||
|
||||
ctx2->heads > 0 || ctx2->sectors_per_track > 0)
|
||||
{
|
||||
tb_printf(2, lr++, TB_WHITE | TB_BOLD, TB_BLUE, "Media has %d cylinders, %d heads and %d sectors per track",
|
||||
ctx1->cylinders, ctx1->heads, ctx1->sectors_per_track);
|
||||
|
||||
tb_printf(mid_x + 2, rr++, TB_WHITE | TB_BOLD, TB_BLUE,
|
||||
"Media has %d cylinders, %d heads and %d sectors per track", ctx2->cylinders, ctx2->heads,
|
||||
ctx2->sectors_per_track);
|
||||
tb_printf(2, state->left_row, TB_WHITE | TB_BOLD, TB_BLUE,
|
||||
"Media has %d cylinders, %d heads and %d sectors per track",
|
||||
ctx1->cylinders, ctx1->heads, ctx1->sectors_per_track);
|
||||
tb_printf(state->mid_x + 2, state->right_row, TB_WHITE | TB_BOLD, TB_BLUE,
|
||||
"Media has %d cylinders, %d heads and %d sectors per track",
|
||||
ctx2->cylinders, ctx2->heads, ctx2->sectors_per_track);
|
||||
state->left_row++;
|
||||
state->right_row++;
|
||||
}
|
||||
|
||||
tb_present();
|
||||
}
|
||||
|
||||
lr++;
|
||||
// Compare sector contents
|
||||
static int compare_sectors(compare_state_t *state,
|
||||
aaruformat_context *ctx1, aaruformat_context *ctx2)
|
||||
{
|
||||
uint64_t sectors = ctx1->image_info.Sectors;
|
||||
if(ctx2->image_info.Sectors < sectors) sectors = ctx2->image_info.Sectors;
|
||||
bool imageContentsAreDifferent = false;
|
||||
uint32_t sectorSize = ctx1->image_info.SectorSize;
|
||||
if(ctx2->image_info.SectorSize > sectorSize) sectorSize = ctx2->image_info.SectorSize;
|
||||
uint8_t *buffer1 = malloc(sectorSize);
|
||||
|
||||
uint32_t sectorSize = ctx1->image_info.SectorSize;
|
||||
if(ctx2->image_info.SectorSize > sectorSize) sectorSize = ctx2->image_info.SectorSize;
|
||||
|
||||
uint8_t *buffer1 = malloc(sectorSize);
|
||||
if(buffer1 == NULL)
|
||||
{
|
||||
tb_printf(2, lr, TB_RED | TB_BOLD, TB_BLUE, "Error allocating memory for buffer: %s", errno);
|
||||
tb_printf(2, state->left_row, TB_RED | TB_BOLD, TB_BLUE,
|
||||
"Error allocating memory for buffer");
|
||||
tb_present();
|
||||
ret = AARUF_ERROR_NOT_ENOUGH_MEMORY;
|
||||
goto finished;
|
||||
return AARUF_ERROR_NOT_ENOUGH_MEMORY;
|
||||
}
|
||||
|
||||
uint8_t *buffer2 = malloc(sectorSize);
|
||||
|
||||
if(buffer2 == NULL)
|
||||
{
|
||||
free(buffer1);
|
||||
tb_printf(2, lr, TB_RED | TB_BOLD, TB_BLUE, "Error allocating memory for buffer: %s", errno);
|
||||
tb_printf(2, state->left_row, TB_RED | TB_BOLD, TB_BLUE,
|
||||
"Error allocating memory for buffer");
|
||||
tb_present();
|
||||
ret = AARUF_ERROR_NOT_ENOUGH_MEMORY;
|
||||
goto finished;
|
||||
return AARUF_ERROR_NOT_ENOUGH_MEMORY;
|
||||
}
|
||||
|
||||
bool contents_differ = false;
|
||||
uint8_t sector_status1 = 0;
|
||||
uint8_t sector_status2 = 0;
|
||||
|
||||
for(uint64_t i = 0; i < sectors; i++)
|
||||
{
|
||||
tb_printf(2, height - 5, TB_WHITE | TB_BOLD, TB_BLUE, "Comparing sector %llu of %llu", i + 1, sectors);
|
||||
draw_progress_bar(height - 4, i * 100 / sectors);
|
||||
tb_printf(2, state->height - 5, TB_WHITE | TB_BOLD, TB_BLUE,
|
||||
"Comparing sector %llu of %llu", i + 1, sectors);
|
||||
draw_progress_bar(state->height - 4, i * 100 / sectors);
|
||||
|
||||
errno = aaruf_read_sector(ctx1, i, false, buffer1, §orSize, §or_status1);
|
||||
if(errno != AARUF_STATUS_OK && errno != AARUF_STATUS_SECTOR_NOT_DUMPED)
|
||||
int err1 = aaruf_read_sector(ctx1, i, false, buffer1, §orSize, §or_status1);
|
||||
int err2 = aaruf_read_sector(ctx2, i, false, buffer2, §orSize, §or_status2);
|
||||
|
||||
if(err1 != AARUF_STATUS_OK && err1 != AARUF_STATUS_SECTOR_NOT_DUMPED) continue;
|
||||
if(err2 != AARUF_STATUS_OK && err2 != AARUF_STATUS_SECTOR_NOT_DUMPED) continue;
|
||||
|
||||
if(memcmp(buffer1, buffer2, sectorSize) != 0)
|
||||
{
|
||||
tb_printf(2, lr++, TB_RED | TB_BOLD, TB_BLUE, "Error reading sector %llu: %s", i, errno);
|
||||
tb_present();
|
||||
continue;
|
||||
}
|
||||
|
||||
errno = aaruf_read_sector(ctx2, i, false, buffer2, §orSize, §or_status2);
|
||||
if(errno != AARUF_STATUS_OK && errno != AARUF_STATUS_SECTOR_NOT_DUMPED)
|
||||
{
|
||||
tb_printf(2, rr++, TB_RED | TB_BOLD, TB_BLUE, "Error reading sector %llu: %s", i, errno);
|
||||
tb_present();
|
||||
continue;
|
||||
}
|
||||
|
||||
for(uint32_t j = 0; j < sectorSize; j++)
|
||||
if(buffer1[j] != buffer2[j])
|
||||
contents_differ = true;
|
||||
if(state->left_row < state->height - 6)
|
||||
{
|
||||
imageContentsAreDifferent = true;
|
||||
tb_printf(2, lr++, TB_RED | TB_BOLD, TB_BLUE, "Sector %llu differs at byte %u", i, j);
|
||||
tb_printf(2, state->left_row++, TB_RED | TB_BOLD, TB_BLUE,
|
||||
"Sector %llu differs", i);
|
||||
tb_present();
|
||||
break; // Exit the loop on first difference
|
||||
}
|
||||
}
|
||||
}
|
||||
draw_progress_bar(height - 4, 100); // Fill the progress bar to 100%
|
||||
|
||||
draw_progress_bar(state->height - 4, 100);
|
||||
|
||||
free(buffer1);
|
||||
free(buffer2);
|
||||
|
||||
if(imagesAreDifferent)
|
||||
tb_printf(2, height - 3, TB_RED | TB_BOLD, TB_BLUE, "Images are different!");
|
||||
// Print final comparison results
|
||||
if(state->has_differences)
|
||||
tb_printf(2, state->height - 3, TB_RED | TB_BOLD, TB_BLUE, "Images are different!");
|
||||
else
|
||||
tb_printf(2, height - 3, TB_GREEN | TB_BOLD, TB_BLUE, "Images are identical!");
|
||||
if(imageContentsAreDifferent)
|
||||
tb_printf(2, height - 2, TB_RED | TB_BOLD, TB_BLUE, "Images contents are different!");
|
||||
tb_printf(2, state->height - 3, TB_GREEN | TB_BOLD, TB_BLUE, "Images are identical!");
|
||||
|
||||
if(contents_differ)
|
||||
tb_printf(2, state->height - 2, TB_RED | TB_BOLD, TB_BLUE, "Images contents are different!");
|
||||
else
|
||||
tb_printf(2, height - 2, TB_GREEN | TB_BOLD, TB_BLUE, "Images contents are identical!");
|
||||
tb_printf(2, state->height - 2, TB_GREEN | TB_BOLD, TB_BLUE, "Images contents are identical!");
|
||||
|
||||
return AARUF_STATUS_OK;
|
||||
}
|
||||
|
||||
int compare(const char *path1, const char *path2)
|
||||
{
|
||||
int ret = AARUF_STATUS_OK;
|
||||
aaruformat_context *ctx1 = NULL;
|
||||
aaruformat_context *ctx2 = NULL;
|
||||
compare_state_t state = {0};
|
||||
|
||||
if(tb_init() != 0) return 1;
|
||||
|
||||
setup_screen(&state);
|
||||
|
||||
// Print file paths
|
||||
tb_printf(2, 1, TB_WHITE | TB_BOLD, TB_BLUE, "%s", path1);
|
||||
tb_printf(state.mid_x + 2, 1, TB_WHITE | TB_BOLD, TB_BLUE, "%s", path2);
|
||||
tb_present();
|
||||
|
||||
// Open first image
|
||||
tb_printf(2, 2, TB_WHITE | TB_BOLD, TB_BLUE, "Opening image...");
|
||||
tb_present();
|
||||
ctx1 = aaruf_open(path1);
|
||||
if(ctx1 == NULL)
|
||||
{
|
||||
tb_printf(2, 3, TB_RED | TB_BOLD, TB_BLUE, "Error opening image");
|
||||
tb_present();
|
||||
ret = -1;
|
||||
goto finished;
|
||||
}
|
||||
tb_printf(2, 2, TB_WHITE | TB_BOLD, TB_BLUE, "Image opened successfully...");
|
||||
|
||||
// Open second image
|
||||
tb_printf(state.mid_x + 2, 2, TB_WHITE | TB_BOLD, TB_BLUE, "Opening image...");
|
||||
tb_present();
|
||||
ctx2 = aaruf_open(path2);
|
||||
if(ctx2 == NULL)
|
||||
{
|
||||
tb_printf(state.mid_x + 2, 3, TB_RED | TB_BOLD, TB_BLUE, "Error opening image");
|
||||
tb_present();
|
||||
ret = -1;
|
||||
goto finished;
|
||||
}
|
||||
tb_printf(state.mid_x + 2, 2, TB_WHITE | TB_BOLD, TB_BLUE, "Image opened successfully...");
|
||||
|
||||
// Perform comparisons
|
||||
compare_headers(&state, ctx1, ctx2);
|
||||
compare_image_info(&state, ctx1, ctx2);
|
||||
compare_metadata(&state, ctx1, ctx2);
|
||||
|
||||
state.left_row++;
|
||||
ret = compare_sectors(&state, ctx1, ctx2);
|
||||
|
||||
finished:
|
||||
tb_printf(2, height - 1, TB_WHITE | TB_BOLD, TB_BLUE, "Press any key to exit...");
|
||||
tb_present(); // Render the buffer to the terminal
|
||||
// Wait for a key press before exiting
|
||||
struct tb_event ev;
|
||||
tb_poll_event(&ev); // Block until user presses a key
|
||||
tb_printf(2, state.height - 1, TB_WHITE | TB_BOLD, TB_BLUE, "Press any key to exit...");
|
||||
tb_present();
|
||||
|
||||
struct tb_event ev;
|
||||
tb_poll_event(&ev);
|
||||
|
||||
if(ctx1) aaruf_close(ctx1);
|
||||
if(ctx2) aaruf_close(ctx2);
|
||||
|
||||
// Restore terminal and exit
|
||||
tb_shutdown();
|
||||
return ret;
|
||||
}
|
||||
Reference in New Issue
Block a user