Init
This commit is contained in:
parent
eb375c52c5
commit
f161bcdfab
465
APP/main.c
465
APP/main.c
|
|
@ -57,7 +57,11 @@ typedef struct {
|
||||||
int write_crc; // Флаг: записывать CRC в файл
|
int write_crc; // Флаг: записывать CRC в файл
|
||||||
int verify_crc; // Флаг: проверять CRC
|
int verify_crc; // Флаг: проверять CRC
|
||||||
int show_only; // Флаг: только показать CRC без записи
|
int show_only; // Флаг: только показать CRC без записи
|
||||||
|
int split; // Флаг: разрезать файл
|
||||||
int verbose; // Флаг: подробный вывод
|
int verbose; // Флаг: подробный вывод
|
||||||
|
long split_offset; // Смещение для разрезания (в байтах)
|
||||||
|
char *output1; // Имя первого выходного файла
|
||||||
|
char *output2; // Имя второго выходного файла
|
||||||
} ProgramOptions;
|
} ProgramOptions;
|
||||||
|
|
||||||
// Прототипы функций
|
// Прототипы функций
|
||||||
|
|
@ -68,6 +72,7 @@ uint32_t calculate_file_crc32_without_last4(const char *filename, int verbose);
|
||||||
uint32_t calculate_file_crc32_full(const char *filename, int verbose);
|
uint32_t calculate_file_crc32_full(const char *filename, int verbose);
|
||||||
int write_crc32_to_file(const char *filename, uint32_t crc_value, int verbose);
|
int write_crc32_to_file(const char *filename, uint32_t crc_value, int verbose);
|
||||||
int verify_crc32(const char *filename, int verbose);
|
int verify_crc32(const char *filename, int verbose);
|
||||||
|
int split_bin_file(const char *input_file, long offset, const char *output1, const char *output2, int verbose);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Вычисляет CRC32 (IEEE 802.3) для блока данных в памяти
|
* @brief Вычисляет CRC32 (IEEE 802.3) для блока данных в памяти
|
||||||
|
|
@ -225,11 +230,15 @@ uint32_t calculate_file_crc32_full(const char *filename, int verbose) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Записывает CRC32 в последние 4 байта файла
|
* @brief Записывает размер данных и CRC32 в файл
|
||||||
|
* Размер данных (file_size - 4) записывается по смещению 256 байт от конца файла
|
||||||
|
* CRC32 записывается в последние 4 байта файла
|
||||||
*/
|
*/
|
||||||
int write_crc32_to_file(const char *filename, uint32_t crc_value, int verbose) {
|
int write_crc32_to_file(const char *filename, uint32_t crc_value, int verbose) {
|
||||||
FILE *file = NULL;
|
FILE *file = NULL;
|
||||||
long file_size;
|
long file_size;
|
||||||
|
long data_size;
|
||||||
|
int result = 0;
|
||||||
|
|
||||||
file = fopen(filename, "rb+");
|
file = fopen(filename, "rb+");
|
||||||
if (file == NULL) {
|
if (file == NULL) {
|
||||||
|
|
@ -237,6 +246,7 @@ int write_crc32_to_file(const char *filename, uint32_t crc_value, int verbose) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Получаем размер файла
|
||||||
if (fseek(file, 0, SEEK_END) != 0) {
|
if (fseek(file, 0, SEEK_END) != 0) {
|
||||||
perror("Failed to seek to end");
|
perror("Failed to seek to end");
|
||||||
fclose(file);
|
fclose(file);
|
||||||
|
|
@ -250,11 +260,70 @@ int write_crc32_to_file(const char *filename, uint32_t crc_value, int verbose) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Перемещаемся на позицию последних 4 байт
|
data_size = file_size - 4; // Размер данных без CRC
|
||||||
|
|
||||||
|
if (verbose) {
|
||||||
|
printf("File size: %ld bytes\n", file_size);
|
||||||
|
printf("Data size (without CRC): %ld bytes (0x%lX)\n", data_size, data_size);
|
||||||
|
printf("CRC value: 0x%08X (%u)\n", crc_value, crc_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==============================================
|
||||||
|
// 1. Записываем размер данных по смещению 256 байт от конца файла
|
||||||
|
// ==============================================
|
||||||
|
long data_size_offset = file_size - 256; // Позиция для размера данных (ровно 256 байт от конца)
|
||||||
|
|
||||||
|
// Проверяем, что позиция не отрицательная и не перекрывается с CRC
|
||||||
|
if (data_size_offset < 0) {
|
||||||
|
fprintf(stderr, "Warning: File too small, cannot write data size at offset 256 from end\n");
|
||||||
|
fprintf(stderr, "File size: %ld bytes, need at least 256 bytes\n", file_size);
|
||||||
|
if (verbose) {
|
||||||
|
printf("Skipping data size write (file too small)\n");
|
||||||
|
}
|
||||||
|
} else if (data_size_offset + 4 > file_size - 4) {
|
||||||
|
fprintf(stderr, "Warning: Data size position overlaps with CRC area\n");
|
||||||
|
fprintf(stderr, "Data size would be at %ld, CRC at %ld\n", data_size_offset, file_size - 4);
|
||||||
|
if (verbose) {
|
||||||
|
printf("Skipping data size write (overlap detected)\n");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Перемещаемся на позицию для записи размера данных
|
||||||
|
if (fseek(file, data_size_offset, SEEK_SET) != 0) {
|
||||||
|
perror("Failed to seek to data size position");
|
||||||
|
result = -1;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Записываем размер данных в little-endian порядке (4 байта для 32-битного размера)
|
||||||
|
uint8_t size_bytes[4];
|
||||||
|
size_bytes[0] = (data_size >> 0) & 0xFF;
|
||||||
|
size_bytes[1] = (data_size >> 8) & 0xFF;
|
||||||
|
size_bytes[2] = (data_size >> 16) & 0xFF;
|
||||||
|
size_bytes[3] = (data_size >> 24) & 0xFF;
|
||||||
|
|
||||||
|
size_t bytes_written = fwrite(size_bytes, 1, 4, file);
|
||||||
|
if (bytes_written != 4) {
|
||||||
|
fprintf(stderr, "Failed to write data size to file\n");
|
||||||
|
result = -1;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (verbose) {
|
||||||
|
printf("\nData size written: %ld bytes (0x%lX)\n", data_size, data_size);
|
||||||
|
printf(" Position: %ld (0x%lX) bytes from start\n", data_size_offset, data_size_offset);
|
||||||
|
printf(" Distance from end: %ld bytes (exactly 256 bytes)\n", file_size - data_size_offset);
|
||||||
|
printf(" Bytes written (LE 32-bit): %02X %02X %02X %02X\n",
|
||||||
|
size_bytes[0], size_bytes[1], size_bytes[2], size_bytes[3]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==============================================
|
||||||
|
// 2. Записываем CRC в последние 4 байта файла
|
||||||
|
// ==============================================
|
||||||
if (fseek(file, file_size - 4, SEEK_SET) != 0) {
|
if (fseek(file, file_size - 4, SEEK_SET) != 0) {
|
||||||
perror("Failed to seek to CRC position");
|
perror("Failed to seek to CRC position");
|
||||||
fclose(file);
|
result = -1;
|
||||||
return -1;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Записываем CRC в little-endian порядке
|
// Записываем CRC в little-endian порядке
|
||||||
|
|
@ -267,29 +336,34 @@ int write_crc32_to_file(const char *filename, uint32_t crc_value, int verbose) {
|
||||||
size_t bytes_written = fwrite(crc_bytes, 1, 4, file);
|
size_t bytes_written = fwrite(crc_bytes, 1, 4, file);
|
||||||
if (bytes_written != 4) {
|
if (bytes_written != 4) {
|
||||||
fprintf(stderr, "Failed to write CRC to file\n");
|
fprintf(stderr, "Failed to write CRC to file\n");
|
||||||
fclose(file);
|
result = -1;
|
||||||
return -1;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
fclose(file);
|
|
||||||
|
|
||||||
if (verbose) {
|
if (verbose) {
|
||||||
printf("CRC32 value written: 0x%08X (%u)\n", crc_value, crc_value);
|
printf("\nCRC32 value written: 0x%08X (%u)\n", crc_value, crc_value);
|
||||||
printf("Written to bytes: %ld-%ld\n", file_size - 4, file_size - 1);
|
printf(" Position: %ld-%ld (last 4 bytes)\n", file_size - 4, file_size - 1);
|
||||||
|
printf(" Bytes written (LE): %02X %02X %02X %02X\n",
|
||||||
|
crc_bytes[0], crc_bytes[1], crc_bytes[2], crc_bytes[3]);
|
||||||
printf("Byte order: little-endian (LSB first)\n");
|
printf("Byte order: little-endian (LSB first)\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
cleanup:
|
||||||
|
fclose(file);
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Проверяет CRC32, сравнивая вычисленное значение с сохраненным
|
* @brief Проверяет CRC32, сравнивая вычисленное значение с сохраненным
|
||||||
|
* Также опционально проверяет сохраненный размер данных
|
||||||
*/
|
*/
|
||||||
int verify_crc32(const char *filename, int verbose) {
|
int verify_crc32(const char *filename, int verbose) {
|
||||||
FILE *file = NULL;
|
FILE *file = NULL;
|
||||||
long file_size;
|
long file_size;
|
||||||
|
long stored_data_size = 0;
|
||||||
uint32_t calculated_crc = 0;
|
uint32_t calculated_crc = 0;
|
||||||
uint32_t stored_crc = 0;
|
uint32_t stored_crc = 0;
|
||||||
|
int verify_size = 1; // Флаг проверки размера
|
||||||
|
|
||||||
file = fopen(filename, "rb");
|
file = fopen(filename, "rb");
|
||||||
if (file == NULL) {
|
if (file == NULL) {
|
||||||
|
|
@ -314,7 +388,48 @@ int verify_crc32(const char *filename, int verbose) {
|
||||||
printf("File size: %ld bytes\n", file_size);
|
printf("File size: %ld bytes\n", file_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Читаем сохраненный CRC из последних 4 байт
|
// ==============================================
|
||||||
|
// 1. Читаем сохраненный размер данных (опционально)
|
||||||
|
// ==============================================
|
||||||
|
long data_size_offset = file_size - 256; // Позиция размера данных (256 байт от конца)
|
||||||
|
if (data_size_offset >= 0 && data_size_offset + 4 <= file_size - 4) {
|
||||||
|
if (fseek(file, data_size_offset, SEEK_SET) != 0) {
|
||||||
|
perror("Failed to seek to stored data size");
|
||||||
|
verify_size = 0;
|
||||||
|
} else {
|
||||||
|
uint8_t size_bytes[4];
|
||||||
|
size_t bytes_read = fread(size_bytes, 1, 4, file);
|
||||||
|
if (bytes_read == 4) {
|
||||||
|
stored_data_size = (long)size_bytes[0] << 0 |
|
||||||
|
(long)size_bytes[1] << 8 |
|
||||||
|
(long)size_bytes[2] << 16 |
|
||||||
|
(long)size_bytes[3] << 24;
|
||||||
|
|
||||||
|
if (verbose) {
|
||||||
|
printf("\nStored data size: %ld bytes (0x%lX) at offset %ld\n",
|
||||||
|
stored_data_size, stored_data_size, data_size_offset);
|
||||||
|
printf(" Distance from end: %ld bytes (exactly 256 bytes)\n", file_size - data_size_offset);
|
||||||
|
printf(" Bytes read (LE 32-bit): %02X %02X %02X %02X\n",
|
||||||
|
size_bytes[0], size_bytes[1], size_bytes[2], size_bytes[3]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
verify_size = 0;
|
||||||
|
if (verbose) {
|
||||||
|
printf("Failed to read stored data size (expected 4 bytes, got %zu)\n", bytes_read);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
verify_size = 0;
|
||||||
|
if (verbose) {
|
||||||
|
printf("\nNo valid data size stored at offset 256 bytes from end\n");
|
||||||
|
printf(" File size: %ld, would need at least %ld bytes\n", file_size, 256 + 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==============================================
|
||||||
|
// 2. Читаем сохраненный CRC из последних 4 байт
|
||||||
|
// ==============================================
|
||||||
if (fseek(file, file_size - 4, SEEK_SET) != 0) {
|
if (fseek(file, file_size - 4, SEEK_SET) != 0) {
|
||||||
perror("Failed to seek to stored CRC");
|
perror("Failed to seek to stored CRC");
|
||||||
fclose(file);
|
fclose(file);
|
||||||
|
|
@ -343,24 +458,224 @@ int verify_crc32(const char *filename, int verbose) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Всегда выводим значения CRC при проверке
|
long actual_data_size = file_size - 4;
|
||||||
printf("\n╔════════════════════════════════════════╗\n");
|
|
||||||
printf("║ CRC32 Verification ║\n");
|
|
||||||
printf("╠════════════════════════════════════════╣\n");
|
|
||||||
printf("║ Stored CRC : 0x%08X (%10u) ║\n", stored_crc, stored_crc);
|
|
||||||
printf("║ Calculated CRC : 0x%08X (%10u) ║\n", calculated_crc, calculated_crc);
|
|
||||||
printf("╚════════════════════════════════════════╝\n");
|
|
||||||
|
|
||||||
if (calculated_crc == stored_crc) {
|
// Всегда выводим значения CRC при проверке
|
||||||
printf("\n✓ VERIFIED: CRC matches! File integrity check passed.\n");
|
printf("\n╔════════════════════════════════════════════════════════════╗\n");
|
||||||
|
printf("║ CRC32 Verification ║\n");
|
||||||
|
printf("╠════════════════════════════════════════════════════════════╣\n");
|
||||||
|
printf("║ Stored CRC : 0x%08X (%10u) ║\n", stored_crc, stored_crc);
|
||||||
|
printf("║ Calculated CRC : 0x%08X (%10u) ║\n", calculated_crc, calculated_crc);
|
||||||
|
|
||||||
|
if (verify_size && stored_data_size > 0) {
|
||||||
|
printf("╠════════════════════════════════════════════════════════════╣\n");
|
||||||
|
printf("║ Stored data size : %12ld bytes (0x%lX) ║\n", stored_data_size, stored_data_size);
|
||||||
|
printf("║ Actual data size : %12ld bytes (0x%lX) ║\n", actual_data_size, actual_data_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("╚════════════════════════════════════════════════════════════╝\n");
|
||||||
|
|
||||||
|
int crc_valid = (calculated_crc == stored_crc);
|
||||||
|
int size_valid = 1;
|
||||||
|
|
||||||
|
if (verify_size && stored_data_size > 0) {
|
||||||
|
size_valid = (actual_data_size == stored_data_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (crc_valid && size_valid) {
|
||||||
|
printf("\n✓ VERIFIED: CRC matches and data size is correct! File integrity check passed.\n");
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else if (crc_valid && !size_valid) {
|
||||||
printf("\n✗ MISMATCH: File is corrupted or CRC was not written correctly!\n");
|
printf("\n⚠ WARNING: CRC matches but data size mismatch!\n");
|
||||||
|
printf(" Stored size: %ld, Actual size: %ld, Difference: %ld\n",
|
||||||
|
stored_data_size, actual_data_size, actual_data_size - stored_data_size);
|
||||||
|
return 1;
|
||||||
|
} else if (!crc_valid && size_valid) {
|
||||||
|
printf("\n✗ MISMATCH: File is corrupted! CRC does not match (data size OK).\n");
|
||||||
printf(" Difference: 0x%08X\n", calculated_crc ^ stored_crc);
|
printf(" Difference: 0x%08X\n", calculated_crc ^ stored_crc);
|
||||||
return 1;
|
return 1;
|
||||||
|
} else {
|
||||||
|
printf("\n✗ MISMATCH: File is corrupted! Both CRC and data size are incorrect!\n");
|
||||||
|
printf(" CRC difference: 0x%08X\n", calculated_crc ^ stored_crc);
|
||||||
|
if (verify_size && stored_data_size > 0) {
|
||||||
|
printf(" Size difference: %ld bytes\n", actual_data_size - stored_data_size);
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Разрезает BIN файл на два файла по указанному смещению
|
||||||
|
*/
|
||||||
|
int split_bin_file(const char *input_file, long offset, const char *output1, const char *output2, int verbose) {
|
||||||
|
FILE *fin = NULL;
|
||||||
|
FILE *fout1 = NULL;
|
||||||
|
FILE *fout2 = NULL;
|
||||||
|
uint8_t *buffer = NULL;
|
||||||
|
long file_size = 0;
|
||||||
|
long bytes_to_copy1 = 0;
|
||||||
|
long bytes_to_copy2 = 0;
|
||||||
|
size_t bytes_read, bytes_written;
|
||||||
|
int result = 0;
|
||||||
|
|
||||||
|
// Открываем входной файл
|
||||||
|
fin = fopen(input_file, "rb");
|
||||||
|
if (fin == NULL) {
|
||||||
|
perror("Failed to open input file");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Получаем размер файла
|
||||||
|
if (fseek(fin, 0, SEEK_END) != 0) {
|
||||||
|
perror("Failed to seek to end");
|
||||||
|
fclose(fin);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
file_size = ftell(fin);
|
||||||
|
rewind(fin);
|
||||||
|
|
||||||
|
printf("\n--- Splitting file ---\n");
|
||||||
|
printf("Input file: %s\n", input_file);
|
||||||
|
printf("File size: %ld bytes (0x%lX)\n", file_size, file_size);
|
||||||
|
printf("Split offset: %ld bytes (0x%lX)\n", offset, offset);
|
||||||
|
|
||||||
|
// Проверяем смещение
|
||||||
|
if (offset <= 0) {
|
||||||
|
fprintf(stderr, "Error: Split offset must be positive (got %ld)\n", offset);
|
||||||
|
fclose(fin);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (offset >= file_size) {
|
||||||
|
fprintf(stderr, "Error: Split offset (%ld) is greater than or equal to file size (%ld)\n",
|
||||||
|
offset, file_size);
|
||||||
|
fclose(fin);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bytes_to_copy1 = offset;
|
||||||
|
bytes_to_copy2 = file_size - offset;
|
||||||
|
|
||||||
|
printf("First part size: %ld bytes (0x%lX)\n", bytes_to_copy1, bytes_to_copy1);
|
||||||
|
printf("Second part size: %ld bytes (0x%lX)\n", bytes_to_copy2, bytes_to_copy2);
|
||||||
|
printf("Output file 1: %s\n", output1);
|
||||||
|
printf("Output file 2: %s\n", output2);
|
||||||
|
|
||||||
|
// Открываем выходные файлы
|
||||||
|
fout1 = fopen(output1, "wb");
|
||||||
|
if (fout1 == NULL) {
|
||||||
|
perror("Failed to create output file 1");
|
||||||
|
fclose(fin);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fout2 = fopen(output2, "wb");
|
||||||
|
if (fout2 == NULL) {
|
||||||
|
perror("Failed to create output file 2");
|
||||||
|
fclose(fin);
|
||||||
|
fclose(fout1);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Выделяем буфер для чтения/записи (1 МБ)
|
||||||
|
const size_t buffer_size = 1024 * 1024;
|
||||||
|
buffer = (uint8_t*)malloc(buffer_size);
|
||||||
|
if (buffer == NULL) {
|
||||||
|
perror("Failed to allocate buffer");
|
||||||
|
fclose(fin);
|
||||||
|
fclose(fout1);
|
||||||
|
fclose(fout2);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Копируем первую часть
|
||||||
|
if (verbose) {
|
||||||
|
printf("\nCopying first part (%ld bytes)...\n", bytes_to_copy1);
|
||||||
|
}
|
||||||
|
|
||||||
|
long remaining = bytes_to_copy1;
|
||||||
|
long progress_step = bytes_to_copy1 / 10;
|
||||||
|
long next_progress = progress_step;
|
||||||
|
|
||||||
|
while (remaining > 0) {
|
||||||
|
size_t to_read = (remaining < buffer_size) ? remaining : buffer_size;
|
||||||
|
bytes_read = fread(buffer, 1, to_read, fin);
|
||||||
|
if (bytes_read != to_read) {
|
||||||
|
fprintf(stderr, "Error reading input file (first part)\n");
|
||||||
|
result = -1;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
bytes_written = fwrite(buffer, 1, bytes_read, fout1);
|
||||||
|
if (bytes_written != bytes_read) {
|
||||||
|
fprintf(stderr, "Error writing to output file 1\n");
|
||||||
|
result = -1;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
remaining -= bytes_read;
|
||||||
|
|
||||||
|
if (verbose && progress_step > 0 && remaining <= next_progress) {
|
||||||
|
int percent = (int)((bytes_to_copy1 - remaining) * 100 / bytes_to_copy1);
|
||||||
|
printf(" Progress: %d%% (%ld bytes remaining)...\n", percent, remaining);
|
||||||
|
next_progress -= progress_step;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Копируем вторую часть
|
||||||
|
if (verbose) {
|
||||||
|
printf("Copying second part (%ld bytes)...\n", bytes_to_copy2);
|
||||||
|
}
|
||||||
|
|
||||||
|
remaining = bytes_to_copy2;
|
||||||
|
progress_step = bytes_to_copy2 / 10;
|
||||||
|
next_progress = bytes_to_copy2 - progress_step;
|
||||||
|
|
||||||
|
while (remaining > 0) {
|
||||||
|
size_t to_read = (remaining < buffer_size) ? remaining : buffer_size;
|
||||||
|
bytes_read = fread(buffer, 1, to_read, fin);
|
||||||
|
if (bytes_read != to_read) {
|
||||||
|
fprintf(stderr, "Error reading input file (second part)\n");
|
||||||
|
result = -1;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
bytes_written = fwrite(buffer, 1, bytes_read, fout2);
|
||||||
|
if (bytes_written != bytes_read) {
|
||||||
|
fprintf(stderr, "Error writing to output file 2\n");
|
||||||
|
result = -1;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
remaining -= bytes_read;
|
||||||
|
|
||||||
|
if (verbose && progress_step > 0 && remaining <= next_progress) {
|
||||||
|
int percent = (int)((bytes_to_copy2 - remaining) * 100 / bytes_to_copy2);
|
||||||
|
printf(" Progress: %d%% (%ld bytes remaining)...\n", percent, remaining);
|
||||||
|
next_progress -= progress_step;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("\n✓ File split successfully!\n");
|
||||||
|
printf(" Part 1: %s (%ld bytes)\n", output1, bytes_to_copy1);
|
||||||
|
printf(" Part 2: %s (%ld bytes)\n", output2, bytes_to_copy2);
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
free(buffer);
|
||||||
|
fclose(fin);
|
||||||
|
fclose(fout1);
|
||||||
|
fclose(fout2);
|
||||||
|
|
||||||
|
// Если произошла ошибка, удаляем созданные файлы
|
||||||
|
if (result != 0) {
|
||||||
|
printf("\nError occurred, removing output files...\n");
|
||||||
|
remove(output1);
|
||||||
|
remove(output2);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Выводит справку
|
* @brief Выводит справку
|
||||||
*/
|
*/
|
||||||
|
|
@ -373,16 +688,26 @@ void print_usage(const char *program_name) {
|
||||||
printf(" and write it to last 4 bytes\n");
|
printf(" and write it to last 4 bytes\n");
|
||||||
printf(" -c, --check Verify CRC32 by comparing with stored value\n");
|
printf(" -c, --check Verify CRC32 by comparing with stored value\n");
|
||||||
printf(" -s, --show-only Calculate and display CRC32 of entire file\n");
|
printf(" -s, --show-only Calculate and display CRC32 of entire file\n");
|
||||||
|
printf(" --split <offset> Split file into two parts at specified offset (bytes)\n");
|
||||||
|
printf(" -1, --output1 <file> Output filename for first part (with --split)\n");
|
||||||
|
printf(" -2, --output2 <file> Output filename for second part (with --split)\n");
|
||||||
printf(" -v, --verbose Show detailed information\n");
|
printf(" -v, --verbose Show detailed information\n");
|
||||||
printf(" -h, --help Show this help\n");
|
printf(" -h, --help Show this help\n");
|
||||||
printf("\nExamples:\n");
|
printf("\nExamples:\n");
|
||||||
printf(" %s -s firmware.bin # Show CRC32 of entire file\n", program_name);
|
printf(" %s -s firmware.bin # Show CRC32 of entire file\n", program_name);
|
||||||
printf(" %s -w firmware.bin # Write CRC32 to last 4 bytes\n", program_name);
|
printf(" %s -w firmware.bin # Write CRC32 to last 4 bytes\n", program_name);
|
||||||
printf(" %s -c firmware.bin # Verify CRC32\n", program_name);
|
printf(" %s -c firmware.bin # Verify CRC32\n", program_name);
|
||||||
printf(" %s -v -w firmware.bin # Write with verbose output\n", program_name);
|
printf(" %s --split 4096 firmware.bin # Split at offset 4096 bytes\n", program_name);
|
||||||
|
printf(" %s --split 0x1000 firmware.bin # Split at offset 0x1000 (hex)\n", program_name);
|
||||||
|
printf(" %s --split 8192 -1 part1.bin -2 part2.bin firmware.bin\n", program_name);
|
||||||
|
printf(" %s -v --split 1024 firmware.bin # Split with verbose output\n", program_name);
|
||||||
printf("\nNote:\n");
|
printf("\nNote:\n");
|
||||||
printf(" For -w and -c operations, CRC is calculated from the first\n");
|
printf(" For -w and -c operations, CRC is calculated from the first\n");
|
||||||
printf(" (file_size - 4) bytes, ignoring the last 4 bytes.\n");
|
printf(" (file_size - 4) bytes, ignoring the last 4 bytes.\n");
|
||||||
|
printf(" Data size (file_size - 4) is written at offset 256 bytes from end.\n");
|
||||||
|
printf(" For split operation, offset can be specified in decimal or hex (0x prefix).\n");
|
||||||
|
printf(" If output filenames are not specified, default names will be used:\n");
|
||||||
|
printf(" <input>_part1.bin and <input>_part2.bin\n");
|
||||||
printf("\n");
|
printf("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -394,17 +719,26 @@ int parse_arguments(int argc, char *argv[], ProgramOptions *options) {
|
||||||
int c;
|
int c;
|
||||||
|
|
||||||
static struct option long_options[] = {
|
static struct option long_options[] = {
|
||||||
{"write", no_argument, 0, 'w'},
|
{"write", no_argument, 0, 'w'},
|
||||||
{"check", no_argument, 0, 'c'},
|
{"check", no_argument, 0, 'c'},
|
||||||
{"show-only", no_argument, 0, 's'},
|
{"show-only", no_argument, 0, 's'},
|
||||||
{"verbose", no_argument, 0, 'v'},
|
{"split", required_argument, 0, 1000},
|
||||||
{"help", no_argument, 0, 'h'},
|
{"output1", required_argument, 0, 1001},
|
||||||
|
{"output2", required_argument, 0, 1002},
|
||||||
|
{"verbose", no_argument, 0, 'v'},
|
||||||
|
{"help", no_argument, 0, 'h'},
|
||||||
{0, 0, 0, 0}
|
{0, 0, 0, 0}
|
||||||
};
|
};
|
||||||
|
|
||||||
memset(options, 0, sizeof(ProgramOptions));
|
memset(options, 0, sizeof(ProgramOptions));
|
||||||
|
|
||||||
while ((c = getopt_long(argc, argv, "wcsvh", long_options, &option_index)) != -1) {
|
// Инициализация имен выходных файлов
|
||||||
|
options->output1 = NULL;
|
||||||
|
options->output2 = NULL;
|
||||||
|
options->split_offset = 0;
|
||||||
|
|
||||||
|
// Поддержка коротких опций: -1 и -2 для output1/output2
|
||||||
|
while ((c = getopt_long(argc, argv, "wcsvh1:2:", long_options, &option_index)) != -1) {
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case 'w':
|
case 'w':
|
||||||
options->write_crc = 1;
|
options->write_crc = 1;
|
||||||
|
|
@ -421,6 +755,27 @@ int parse_arguments(int argc, char *argv[], ProgramOptions *options) {
|
||||||
case 'h':
|
case 'h':
|
||||||
print_usage(argv[0]);
|
print_usage(argv[0]);
|
||||||
return -1;
|
return -1;
|
||||||
|
case '1': // Короткая опция -1 для output1
|
||||||
|
options->output1 = strdup(optarg);
|
||||||
|
break;
|
||||||
|
case '2': // Короткая опция -2 для output2
|
||||||
|
options->output2 = strdup(optarg);
|
||||||
|
break;
|
||||||
|
case 1000: // --split
|
||||||
|
options->split = 1;
|
||||||
|
// Поддержка шестнадцатеричных чисел
|
||||||
|
if (optarg[0] == '0' && (optarg[1] == 'x' || optarg[1] == 'X')) {
|
||||||
|
options->split_offset = strtol(optarg, NULL, 16);
|
||||||
|
} else {
|
||||||
|
options->split_offset = strtol(optarg, NULL, 10);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 1001: // --output1
|
||||||
|
options->output1 = strdup(optarg);
|
||||||
|
break;
|
||||||
|
case 1002: // --output2
|
||||||
|
options->output2 = strdup(optarg);
|
||||||
|
break;
|
||||||
case '?':
|
case '?':
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
@ -434,14 +789,37 @@ int parse_arguments(int argc, char *argv[], ProgramOptions *options) {
|
||||||
|
|
||||||
options->filename = argv[optind];
|
options->filename = argv[optind];
|
||||||
|
|
||||||
if (!options->write_crc && !options->verify_crc && !options->show_only) {
|
// Подсчет количества выбранных режимов
|
||||||
|
int mode_count = options->write_crc + options->verify_crc + options->show_only + options->split;
|
||||||
|
if (mode_count > 1) {
|
||||||
|
fprintf(stderr, "Error: Cannot use multiple modes simultaneously\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Если режим не выбран, по умолчанию show-only
|
||||||
|
if (mode_count == 0) {
|
||||||
options->show_only = 1;
|
options->show_only = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int mode_count = options->write_crc + options->verify_crc + options->show_only;
|
// Проверка параметров для split
|
||||||
if (mode_count > 1) {
|
if (options->split) {
|
||||||
fprintf(stderr, "Error: Cannot use multiple modes\n");
|
if (options->split_offset <= 0) {
|
||||||
return -1;
|
fprintf(stderr, "Error: Invalid split offset (must be > 0)\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Генерация имен выходных файлов, если не указаны
|
||||||
|
if (options->output1 == NULL) {
|
||||||
|
char *default_name = malloc(strlen(options->filename) + 10);
|
||||||
|
sprintf(default_name, "%s_part1.bin", options->filename);
|
||||||
|
options->output1 = default_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options->output2 == NULL) {
|
||||||
|
char *default_name = malloc(strlen(options->filename) + 10);
|
||||||
|
sprintf(default_name, "%s_part2.bin", options->filename);
|
||||||
|
options->output2 = default_name;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -492,7 +870,7 @@ int main(int argc, char *argv[]) {
|
||||||
printf("╚════════════════════════════════════════╝\n");
|
printf("╚════════════════════════════════════════╝\n");
|
||||||
|
|
||||||
if (options.verbose) {
|
if (options.verbose) {
|
||||||
printf("\nStep 2: Writing to last 4 bytes...\n");
|
printf("\nStep 2: Writing CRC and data size to file...\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
result = write_crc32_to_file(options.filename, crc_value, options.verbose);
|
result = write_crc32_to_file(options.filename, crc_value, options.verbose);
|
||||||
|
|
@ -515,6 +893,15 @@ int main(int argc, char *argv[]) {
|
||||||
printf("\n--- Verifying CRC32 for %s ---\n", options.filename);
|
printf("\n--- Verifying CRC32 for %s ---\n", options.filename);
|
||||||
result = verify_crc32(options.filename, options.verbose);
|
result = verify_crc32(options.filename, options.verbose);
|
||||||
}
|
}
|
||||||
|
else if (options.split) {
|
||||||
|
// Разрезать файл
|
||||||
|
result = split_bin_file(options.filename, options.split_offset,
|
||||||
|
options.output1, options.output2, options.verbose);
|
||||||
|
|
||||||
|
// Освобождаем память для имен выходных файлов
|
||||||
|
if (options.output1 != NULL) free(options.output1);
|
||||||
|
if (options.output2 != NULL) free(options.output2);
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
Loading…
Reference in New Issue