mirror of
https://github.com/aaru-dps/libaaruformat.git
synced 2025-12-16 11:14:39 +00:00
Add compare command to tool.
This commit is contained in:
@@ -6,9 +6,6 @@ find_package(Argtable3 CONFIG REQUIRED)
|
|||||||
include_directories(${ICU_INCLUDE_DIRS})
|
include_directories(${ICU_INCLUDE_DIRS})
|
||||||
|
|
||||||
add_executable(aaruformattool main.c version.h aaruformattool.h identify.c info.c helpers.c read.c printhex.c verify.c ecc_cd.c
|
add_executable(aaruformattool main.c version.h aaruformattool.h identify.c info.c helpers.c read.c printhex.c verify.c ecc_cd.c
|
||||||
commands.h
|
commands.h commands.c usage.h usage.c compare.c termbox2.h)
|
||||||
commands.c
|
|
||||||
usage.h
|
|
||||||
usage.c)
|
|
||||||
target_link_libraries(aaruformattool "aaruformat" argtable3::argtable3)
|
target_link_libraries(aaruformattool "aaruformat" argtable3::argtable3)
|
||||||
target_link_libraries(aaruformattool "aaruformat" ICU::uc)
|
target_link_libraries(aaruformattool "aaruformat" ICU::uc)
|
||||||
|
|||||||
@@ -33,5 +33,6 @@ int verify(char *path);
|
|||||||
int verify_sectors(char *path);
|
int verify_sectors(char *path);
|
||||||
bool check_cd_sector_channel(CdEccContext *context, uint8_t *sector, bool *unknown, bool *has_edc, bool *edc_correct,
|
bool check_cd_sector_channel(CdEccContext *context, uint8_t *sector, bool *unknown, bool *has_edc, bool *edc_correct,
|
||||||
bool *has_ecc_p, bool *ecc_p_correct, bool *has_ecc_q, bool *ecc_q_correct);
|
bool *has_ecc_p, bool *ecc_p_correct, bool *has_ecc_q, bool *ecc_q_correct);
|
||||||
|
int compare(char *path1, char *path2);
|
||||||
|
|
||||||
#endif // LIBAARUFORMAT_TOOL_AARUFORMATTOOL_H_
|
#endif // LIBAARUFORMAT_TOOL_AARUFORMATTOOL_H_
|
||||||
|
|||||||
@@ -63,6 +63,26 @@ int cmd_info(int argc, char *argv[])
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int cmd_compare(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
struct arg_str *filename1 = arg_str1(NULL, NULL, "<filename1>", "First image to compare");
|
||||||
|
struct arg_str *filename2 = arg_str1(NULL, NULL, "<filename2>", "Second image to compare");
|
||||||
|
struct arg_end *end = arg_end(10);
|
||||||
|
void *argtable[] = {filename1, filename2, end};
|
||||||
|
|
||||||
|
if(arg_parse(argc, argv, argtable) > 0)
|
||||||
|
{
|
||||||
|
arg_print_errors(stderr, end, "compare");
|
||||||
|
usage_compare();
|
||||||
|
arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int result = compare(filename1->sval[0], filename2->sval[0]);
|
||||||
|
arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
int cmd_read_common(int argc, char *argv[], bool long_mode)
|
int cmd_read_common(int argc, char *argv[], bool long_mode)
|
||||||
{
|
{
|
||||||
struct arg_int *sector = arg_int1(NULL, NULL, "<sector>", "Sector number");
|
struct arg_int *sector = arg_int1(NULL, NULL, "<sector>", "Sector number");
|
||||||
@@ -119,6 +139,7 @@ Command commands[] = {
|
|||||||
{ "read_long", cmd_read_long},
|
{ "read_long", cmd_read_long},
|
||||||
{ "verify", cmd_verify},
|
{ "verify", cmd_verify},
|
||||||
{"verify_sectors", cmd_verify_sectors},
|
{"verify_sectors", cmd_verify_sectors},
|
||||||
|
{ "compare", cmd_compare},
|
||||||
};
|
};
|
||||||
|
|
||||||
const size_t num_commands = sizeof(commands) / sizeof(commands[0]);
|
const size_t num_commands = sizeof(commands) / sizeof(commands[0]);
|
||||||
|
|||||||
@@ -38,5 +38,6 @@ int cmd_read(int argc, char *argv[]);
|
|||||||
int cmd_read_long(int argc, char *argv[]);
|
int cmd_read_long(int argc, char *argv[]);
|
||||||
int cmd_verify(int argc, char *argv[]);
|
int cmd_verify(int argc, char *argv[]);
|
||||||
int cmd_verify_sectors(int argc, char *argv[]);
|
int cmd_verify_sectors(int argc, char *argv[]);
|
||||||
|
int cmd_compare(int argc, char *argv[]);
|
||||||
|
|
||||||
#endif // LIBAARUFORMAT_COMMANDS_H
|
#endif // LIBAARUFORMAT_COMMANDS_H
|
||||||
|
|||||||
458
tool/compare.c
Normal file
458
tool/compare.c
Normal file
@@ -0,0 +1,458 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the Aaru Data Preservation Suite.
|
||||||
|
* Copyright (c) 2019-2025 Natalia Portillo.
|
||||||
|
*
|
||||||
|
* This program 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 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program 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 this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <aaruformat.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <unicode/ucnv.h>
|
||||||
|
#include <unicode/ustring.h>
|
||||||
|
|
||||||
|
#define TB_IMPL
|
||||||
|
|
||||||
|
#include "termbox2.h"
|
||||||
|
|
||||||
|
int compare(char *path1, char *path2)
|
||||||
|
{
|
||||||
|
int ret = AARUF_STATUS_OK;
|
||||||
|
aaruformatContext const *ctx1 = NULL;
|
||||||
|
aaruformatContext const *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;
|
||||||
|
|
||||||
|
// Initialize termbox2
|
||||||
|
if(tb_init() != 0) return 1;
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
|
||||||
|
tb_present(); // Render the buffer to the terminal
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
tb_printf(2, 2, TB_WHITE | TB_BOLD, TB_BLUE, "Image opened successfully...");
|
||||||
|
|
||||||
|
// 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(mid_x + 2, 2, TB_WHITE | TB_BOLD, TB_BLUE, "Image opened successfully...");
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
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, ctx1->header.application, 64, &u_error_code);
|
||||||
|
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
|
||||||
|
|
||||||
|
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->imageInfo.Application, -1,
|
||||||
|
(const UChar *)ctx2->imageInfo.Application, -1, false);
|
||||||
|
if(u_error_code != U_ZERO_ERROR) imagesAreDifferent = true;
|
||||||
|
|
||||||
|
// Current left row
|
||||||
|
lr = 9;
|
||||||
|
// Current right row
|
||||||
|
rr = 9;
|
||||||
|
|
||||||
|
if(ctx1->imageInfo.HasPartitions != ctx2->imageInfo.HasPartitions)
|
||||||
|
{
|
||||||
|
imagesAreDifferent = true;
|
||||||
|
partitionsColor = TB_RED;
|
||||||
|
}
|
||||||
|
if(ctx1->imageInfo.HasSessions != ctx2->imageInfo.HasSessions)
|
||||||
|
{
|
||||||
|
imagesAreDifferent = true;
|
||||||
|
sessionsColor = TB_RED;
|
||||||
|
}
|
||||||
|
if(ctx1->imageInfo.Sectors != ctx2->imageInfo.Sectors)
|
||||||
|
{
|
||||||
|
imagesAreDifferent = true;
|
||||||
|
sectorsColor = TB_RED;
|
||||||
|
}
|
||||||
|
if(ctx1->imageInfo.SectorSize != ctx2->imageInfo.SectorSize)
|
||||||
|
{
|
||||||
|
imagesAreDifferent = true;
|
||||||
|
sectorSizeColor = TB_RED;
|
||||||
|
}
|
||||||
|
if(ctx1->imageInfo.Version != ctx2->imageInfo.Version)
|
||||||
|
{
|
||||||
|
imagesAreDifferent = true;
|
||||||
|
versionColor = TB_RED;
|
||||||
|
}
|
||||||
|
|
||||||
|
tb_printf(2, lr, TB_WHITE | TB_BOLD, TB_BLUE, "Has partitions?: ");
|
||||||
|
tb_printf(19, lr++, partitionsColor, TB_BLUE, "%s", ctx1->imageInfo.HasPartitions ? "yes" : "no");
|
||||||
|
tb_printf(2, lr, TB_WHITE | TB_BOLD, TB_BLUE, "Has sessions?: ");
|
||||||
|
tb_printf(17, lr++, sessionsColor, TB_BLUE, "%s", ctx1->imageInfo.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->imageInfo.ImageSize);
|
||||||
|
tb_printf(2, lr, TB_WHITE | TB_BOLD, TB_BLUE, "Image contains: ");
|
||||||
|
tb_printf(18, lr++, sectorsColor, TB_BLUE, "%llu sectors", ctx1->imageInfo.Sectors);
|
||||||
|
tb_printf(2, lr, TB_WHITE | TB_BOLD, TB_BLUE, "Biggest sector is: ");
|
||||||
|
tb_printf(21, lr++, sectorSizeColor, TB_BLUE, "%d bytes", ctx1->imageInfo.SectorSize);
|
||||||
|
tb_printf(2, lr, TB_WHITE | TB_BOLD, TB_BLUE, "Image version: ");
|
||||||
|
tb_printf(17, lr++, versionColor, TB_BLUE, "%s", ctx1->imageInfo.Version);
|
||||||
|
tb_present();
|
||||||
|
|
||||||
|
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->imageInfo.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->imageInfo.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->imageInfo.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->imageInfo.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->imageInfo.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->imageInfo.Version);
|
||||||
|
tb_present();
|
||||||
|
|
||||||
|
if(ctx1->imageInfo.Application != NULL || ctx2->imageInfo.Application != NULL)
|
||||||
|
{
|
||||||
|
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->imageInfo.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->imageInfo.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();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ctx1->imageInfo.ApplicationVersion != NULL || ctx2->imageInfo.ApplicationVersion != NULL)
|
||||||
|
{
|
||||||
|
tb_printf(2, lr, TB_WHITE | TB_BOLD, TB_BLUE, "Application version: ");
|
||||||
|
tb_printf(23, lr++, TB_WHITE, TB_BLUE, "%s", ctx1->imageInfo.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->imageInfo.ApplicationVersion);
|
||||||
|
}
|
||||||
|
if(ctx1->imageInfo.Creator != NULL || ctx2->imageInfo.Creator != NULL)
|
||||||
|
{
|
||||||
|
tb_printf(2, lr, TB_WHITE | TB_BOLD, TB_BLUE, "Creator: ");
|
||||||
|
tb_printf(11, lr++, TB_WHITE, TB_BLUE, "%s", ctx1->imageInfo.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->imageInfo.Creator);
|
||||||
|
}
|
||||||
|
|
||||||
|
tb_printf(2, lr, TB_WHITE | TB_BOLD, TB_BLUE, "Creation time: ");
|
||||||
|
tb_printf(17, lr++, TB_WHITE, TB_BLUE, "%lld", ctx1->imageInfo.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->imageInfo.CreationTime);
|
||||||
|
|
||||||
|
tb_printf(2, lr, TB_WHITE | TB_BOLD, TB_BLUE, "Last written time: ");
|
||||||
|
tb_printf(21, lr++, TB_WHITE, TB_BLUE, "%lld", ctx1->imageInfo.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->imageInfo.LastModificationTime);
|
||||||
|
|
||||||
|
if(ctx1->imageInfo.Comments != NULL || ctx2->imageInfo.Comments != NULL)
|
||||||
|
{
|
||||||
|
tb_printf(2, lr, TB_WHITE | TB_BOLD, TB_BLUE, "Comments: ");
|
||||||
|
tb_printf(12, lr++, TB_WHITE, TB_BLUE, "%s", ctx1->imageInfo.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->imageInfo.Comments);
|
||||||
|
}
|
||||||
|
if(ctx1->imageInfo.MediaTitle != NULL || ctx2->imageInfo.MediaTitle != NULL)
|
||||||
|
{
|
||||||
|
tb_printf(2, lr, TB_WHITE | TB_BOLD, TB_BLUE, "Media title: ");
|
||||||
|
tb_printf(15, lr++, TB_WHITE, TB_BLUE, "%s", ctx1->imageInfo.MediaTitle);
|
||||||
|
|
||||||
|
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->imageInfo.MediaTitle);
|
||||||
|
}
|
||||||
|
if(ctx1->imageInfo.MediaManufacturer != NULL || ctx2->imageInfo.MediaManufacturer != NULL)
|
||||||
|
{
|
||||||
|
tb_printf(2, lr, TB_WHITE | TB_BOLD, TB_BLUE, "Media manufacturer: ");
|
||||||
|
tb_printf(22, lr++, TB_WHITE, TB_BLUE, "%s", ctx1->imageInfo.MediaManufacturer);
|
||||||
|
|
||||||
|
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->imageInfo.MediaManufacturer);
|
||||||
|
}
|
||||||
|
if(ctx1->imageInfo.MediaSerialNumber != NULL || ctx2->imageInfo.MediaSerialNumber != NULL)
|
||||||
|
{
|
||||||
|
tb_printf(2, lr, TB_WHITE | TB_BOLD, TB_BLUE, "Media serial number: ");
|
||||||
|
tb_printf(23, lr++, TB_WHITE, TB_BLUE, "%s", ctx1->imageInfo.MediaSerialNumber);
|
||||||
|
|
||||||
|
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->imageInfo.MediaSerialNumber);
|
||||||
|
}
|
||||||
|
if(ctx1->imageInfo.MediaBarcode != NULL || ctx2->imageInfo.MediaBarcode != NULL)
|
||||||
|
{
|
||||||
|
tb_printf(2, lr, TB_WHITE | TB_BOLD, TB_BLUE, "Media barcode: ");
|
||||||
|
tb_printf(17, lr++, TB_WHITE, TB_BLUE, "%s", ctx1->imageInfo.MediaBarcode);
|
||||||
|
|
||||||
|
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->imageInfo.MediaBarcode);
|
||||||
|
}
|
||||||
|
if(ctx1->imageInfo.MediaPartNumber != NULL || ctx2->imageInfo.MediaPartNumber != NULL)
|
||||||
|
{
|
||||||
|
tb_printf(2, lr, TB_WHITE | TB_BOLD, TB_BLUE, "Media part number: ");
|
||||||
|
tb_printf(21, lr++, TB_WHITE, TB_BLUE, "%s", ctx1->imageInfo.MediaPartNumber);
|
||||||
|
|
||||||
|
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->imageInfo.MediaPartNumber);
|
||||||
|
}
|
||||||
|
tb_printf(2, lr, TB_WHITE | TB_BOLD, TB_BLUE, "Media type: ");
|
||||||
|
tb_printf(14, lr++, TB_WHITE, TB_BLUE, "%u", ctx1->imageInfo.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->imageInfo.MediaType);
|
||||||
|
|
||||||
|
if(ctx1->imageInfo.MediaSequence > 0 || ctx1->imageInfo.LastMediaSequence > 0 ||
|
||||||
|
ctx2->imageInfo.MediaSequence > 0 || ctx2->imageInfo.LastMediaSequence > 0)
|
||||||
|
{
|
||||||
|
tb_printf(2, lr++, TB_WHITE | TB_BOLD, TB_BLUE, "Media is number %d in a set of %d media",
|
||||||
|
ctx1->imageInfo.MediaSequence, ctx1->imageInfo.LastMediaSequence);
|
||||||
|
|
||||||
|
tb_printf(mid_x + 2, rr++, TB_WHITE | TB_BOLD, TB_BLUE, "Media is number %d in a set of %d media",
|
||||||
|
ctx2->imageInfo.MediaSequence, ctx2->imageInfo.LastMediaSequence);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ctx1->imageInfo.DriveManufacturer != NULL || ctx2->imageInfo.DriveManufacturer != NULL)
|
||||||
|
{
|
||||||
|
tb_printf(2, lr, TB_WHITE | TB_BOLD, TB_BLUE, "Drive manufacturer: ");
|
||||||
|
tb_printf(22, lr++, TB_WHITE, TB_BLUE, "%s", ctx1->imageInfo.DriveManufacturer);
|
||||||
|
|
||||||
|
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->imageInfo.DriveManufacturer);
|
||||||
|
}
|
||||||
|
if(ctx1->imageInfo.DriveModel != NULL || ctx2->imageInfo.DriveModel != NULL)
|
||||||
|
{
|
||||||
|
tb_printf(2, lr, TB_WHITE | TB_BOLD, TB_BLUE, "Drive model: ");
|
||||||
|
tb_printf(15, lr++, TB_WHITE, TB_BLUE, "%s", ctx1->imageInfo.DriveModel);
|
||||||
|
|
||||||
|
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->imageInfo.DriveModel);
|
||||||
|
}
|
||||||
|
if(ctx1->imageInfo.DriveSerialNumber != NULL || ctx2->imageInfo.DriveSerialNumber != NULL)
|
||||||
|
{
|
||||||
|
tb_printf(2, lr, TB_WHITE | TB_BOLD, TB_BLUE, "Drive serial number: ");
|
||||||
|
tb_printf(23, lr++, TB_WHITE, TB_BLUE, "%s", ctx1->imageInfo.DriveSerialNumber);
|
||||||
|
|
||||||
|
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->imageInfo.DriveSerialNumber);
|
||||||
|
}
|
||||||
|
if(ctx1->imageInfo.DriveFirmwareRevision != NULL || ctx2->imageInfo.DriveFirmwareRevision != NULL)
|
||||||
|
{
|
||||||
|
tb_printf(2, lr, TB_WHITE | TB_BOLD, TB_BLUE, "Drive firmware revision: ");
|
||||||
|
tb_printf(27, lr++, TB_WHITE, TB_BLUE, "%s", ctx1->imageInfo.DriveFirmwareRevision);
|
||||||
|
|
||||||
|
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->imageInfo.DriveFirmwareRevision);
|
||||||
|
}
|
||||||
|
tb_printf(2, lr, TB_WHITE | TB_BOLD, TB_BLUE, "XML media type: ");
|
||||||
|
tb_printf(18, lr++, TB_WHITE, TB_BLUE, "%d", ctx1->imageInfo.XmlMediaType);
|
||||||
|
|
||||||
|
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->imageInfo.XmlMediaType);
|
||||||
|
|
||||||
|
if(ctx1->imageInfo.Cylinders > 0 || ctx1->imageInfo.Heads > 0 || ctx1->imageInfo.SectorsPerTrack > 0 ||
|
||||||
|
ctx2->imageInfo.Cylinders > 0 || ctx2->imageInfo.Heads > 0 || ctx2->imageInfo.SectorsPerTrack > 0)
|
||||||
|
{
|
||||||
|
tb_printf(2, lr++, TB_WHITE | TB_BOLD, TB_BLUE, "Media has %d cylinders, %d heads and %d sectors per track",
|
||||||
|
ctx1->imageInfo.Cylinders, ctx1->imageInfo.Heads, ctx1->imageInfo.SectorsPerTrack);
|
||||||
|
|
||||||
|
tb_printf(mid_x + 2, rr++, TB_WHITE | TB_BOLD, TB_BLUE,
|
||||||
|
"Media has %d cylinders, %d heads and %d sectors per track", ctx2->imageInfo.Cylinders,
|
||||||
|
ctx2->imageInfo.Heads, ctx2->imageInfo.SectorsPerTrack);
|
||||||
|
}
|
||||||
|
|
||||||
|
tb_present();
|
||||||
|
|
||||||
|
finished:
|
||||||
|
if(imagesAreDifferent)
|
||||||
|
tb_printf(2, height - 2, TB_RED | TB_BOLD, TB_BLUE, "Images are different!");
|
||||||
|
else
|
||||||
|
tb_printf(2, height - 2, TB_GREEN | TB_BOLD, TB_BLUE, "Images are identical!");
|
||||||
|
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
|
||||||
|
|
||||||
|
// Restore terminal and exit
|
||||||
|
tb_shutdown();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
4297
tool/termbox2.h
Normal file
4297
tool/termbox2.h
Normal file
File diff suppressed because it is too large
Load Diff
10
tool/usage.c
10
tool/usage.c
@@ -99,3 +99,13 @@ void usage_verify_sectors()
|
|||||||
printf("Arguments:\n");
|
printf("Arguments:\n");
|
||||||
printf(" <filename> Path to image file.\n");
|
printf(" <filename> Path to image file.\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void usage_compare()
|
||||||
|
{
|
||||||
|
printf("\nUsage:\n");
|
||||||
|
printf(" aaruformattool compare <filename1> <filename2>\n\n");
|
||||||
|
printf("Compares two AaruFormat images.\n");
|
||||||
|
printf("Arguments:\n");
|
||||||
|
printf(" <filename1> Path to first image file.\n");
|
||||||
|
printf(" <filename2> Path to second image file.\n");
|
||||||
|
}
|
||||||
|
|||||||
@@ -28,5 +28,6 @@ void usage_read();
|
|||||||
void usage_read_long();
|
void usage_read_long();
|
||||||
void usage_verify();
|
void usage_verify();
|
||||||
void usage_verify_sectors();
|
void usage_verify_sectors();
|
||||||
|
void usage_compare();
|
||||||
|
|
||||||
#endif // LIBAARUFORMAT_USAGE_H
|
#endif // LIBAARUFORMAT_USAGE_H
|
||||||
|
|||||||
Reference in New Issue
Block a user