FC_BIN_HVAC/APP/main.c

768 lines
28 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <getopt.h>
// Таблица CRC32 для полинома 0xEDB88320 (IEEE 802.3)
static const uint32_t crc32_table[256] = {
0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F,
0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2,
0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9,
0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C,
0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423,
0xCFBA9599, 0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 0x76DC4190, 0x01DB7106,
0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D,
0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950,
0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7,
0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA,
0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81,
0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, 0xE3630B12, 0x94643B84,
0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB,
0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E,
0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55,
0x316E8EEF, 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28,
0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F,
0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242,
0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69,
0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC,
0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693,
0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
};
// Структура для параметров командной строки
typedef struct {
char *filename;
int write_crc; // Флаг: записывать CRC в файл
int verify_crc; // Флаг: проверять CRC
int show_only; // Флаг: только показать CRC без записи
int split; // Флаг: разрезать файл
int verbose; // Флаг: подробный вывод
long split_offset; // Смещение для разрезания (в байтах)
char *output1; // Имя первого выходного файла
char *output2; // Имя второго выходного файла
} ProgramOptions;
// Прототипы функций
void print_usage(const char *program_name);
int parse_arguments(int argc, char *argv[], ProgramOptions *options);
uint32_t calculate_crc32(const uint8_t *data, uint32_t len);
uint32_t calculate_file_crc32_without_last4(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 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) для блока данных в памяти
*/
uint32_t calculate_crc32(const uint8_t *data, uint32_t len) {
uint32_t crc = 0xFFFFFFFF;
for (uint32_t i = 0; i < len; i++) {
crc = (crc >> 8) ^ crc32_table[(crc ^ data[i]) & 0xFF];
}
return crc ^ 0xFFFFFFFF;
}
/**
* @brief Вычисляет CRC32 для файла, исключая последние 4 байта
* Используется для записи и проверки CRC
*/
uint32_t calculate_file_crc32_without_last4(const char *filename, int verbose) {
FILE *file = NULL;
uint8_t *buffer = NULL;
long file_size = 0;
uint32_t crc = 0;
file = fopen(filename, "rb");
if (file == NULL) {
perror("Failed to open file");
return 0;
}
// Получаем размер файла
if (fseek(file, 0, SEEK_END) != 0) {
perror("Failed to seek to end");
fclose(file);
return 0;
}
file_size = ftell(file);
if (file_size < 4) {
fprintf(stderr, "File size (%ld bytes) is less than 4 bytes\n", file_size);
fclose(file);
return 0;
}
long data_size = file_size - 4; // Размер данных без последних 4 байт
if (verbose) {
printf("File size: %ld bytes\n", file_size);
printf("Data size for CRC calculation (without last 4 bytes): %ld bytes\n", data_size);
}
// Выделяем память под данные
buffer = (uint8_t*)malloc(data_size);
if (buffer == NULL && data_size > 0) {
perror("Failed to allocate memory");
fclose(file);
return 0;
}
// Возвращаемся в начало
if (fseek(file, 0, SEEK_SET) != 0) {
perror("Failed to seek to beginning");
free(buffer);
fclose(file);
return 0;
}
// Читаем данные (все, кроме последних 4 байт)
if (data_size > 0) {
size_t bytes_read = fread(buffer, 1, data_size, file);
if (bytes_read != data_size) {
fprintf(stderr, "Failed to read file data. Read %zu bytes, expected %ld bytes\n",
bytes_read, data_size);
free(buffer);
fclose(file);
return 0;
}
}
// Вычисляем CRC
if (data_size > 0) {
crc = calculate_crc32(buffer, data_size);
} else {
crc = calculate_crc32(NULL, 0);
}
free(buffer);
fclose(file);
return crc;
}
/**
* @brief Вычисляет CRC32 для всего файла (включая последние 4 байта)
* Используется только для показа CRC
*/
uint32_t calculate_file_crc32_full(const char *filename, int verbose) {
FILE *file = NULL;
uint8_t *buffer = NULL;
long file_size = 0;
uint32_t crc = 0;
file = fopen(filename, "rb");
if (file == NULL) {
perror("Failed to open file");
return 0;
}
if (fseek(file, 0, SEEK_END) != 0) {
perror("Failed to seek to end");
fclose(file);
return 0;
}
file_size = ftell(file);
if (verbose) {
printf("File size: %ld bytes\n", file_size);
}
if (file_size <= 0) {
fprintf(stderr, "File is empty\n");
fclose(file);
return 0;
}
buffer = (uint8_t*)malloc(file_size);
if (buffer == NULL) {
perror("Failed to allocate memory");
fclose(file);
return 0;
}
if (fseek(file, 0, SEEK_SET) != 0) {
perror("Failed to seek to beginning");
free(buffer);
fclose(file);
return 0;
}
size_t bytes_read = fread(buffer, 1, file_size, file);
if (bytes_read != file_size) {
fprintf(stderr, "Failed to read entire file\n");
free(buffer);
fclose(file);
return 0;
}
crc = calculate_crc32(buffer, file_size);
free(buffer);
fclose(file);
return crc;
}
/**
* @brief Записывает CRC32 в последние 4 байта файла
*/
int write_crc32_to_file(const char *filename, uint32_t crc_value, int verbose) {
FILE *file = NULL;
long file_size;
file = fopen(filename, "rb+");
if (file == NULL) {
perror("Failed to open file for writing");
return -1;
}
if (fseek(file, 0, SEEK_END) != 0) {
perror("Failed to seek to end");
fclose(file);
return -1;
}
file_size = ftell(file);
if (file_size < 4) {
fprintf(stderr, "File size (%ld bytes) is less than 4 bytes\n", file_size);
fclose(file);
return -1;
}
// Перемещаемся на позицию последних 4 байт
if (fseek(file, file_size - 4, SEEK_SET) != 0) {
perror("Failed to seek to CRC position");
fclose(file);
return -1;
}
// Записываем CRC в little-endian порядке
uint8_t crc_bytes[4];
crc_bytes[0] = (crc_value >> 0) & 0xFF;
crc_bytes[1] = (crc_value >> 8) & 0xFF;
crc_bytes[2] = (crc_value >> 16) & 0xFF;
crc_bytes[3] = (crc_value >> 24) & 0xFF;
size_t bytes_written = fwrite(crc_bytes, 1, 4, file);
if (bytes_written != 4) {
fprintf(stderr, "Failed to write CRC to file\n");
fclose(file);
return -1;
}
fclose(file);
if (verbose) {
printf("CRC32 value written: 0x%08X (%u)\n", crc_value, crc_value);
printf("Written to bytes: %ld-%ld (last 4 bytes)\n", file_size - 4, file_size - 1);
printf("Byte order: little-endian (LSB first)\n");
}
return 0;
}
/**
* @brief Проверяет CRC32, сравнивая вычисленное значение с сохраненным
*/
int verify_crc32(const char *filename, int verbose) {
FILE *file = NULL;
long file_size;
uint32_t calculated_crc = 0;
uint32_t stored_crc = 0;
file = fopen(filename, "rb");
if (file == NULL) {
perror("Failed to open file");
return -1;
}
if (fseek(file, 0, SEEK_END) != 0) {
perror("Failed to seek to end");
fclose(file);
return -1;
}
file_size = ftell(file);
if (file_size < 4) {
fprintf(stderr, "File size (%ld bytes) is less than 4 bytes\n", file_size);
fclose(file);
return -1;
}
if (verbose) {
printf("File size: %ld bytes\n", file_size);
}
// Читаем сохраненный CRC из последних 4 байт
if (fseek(file, file_size - 4, SEEK_SET) != 0) {
perror("Failed to seek to stored CRC");
fclose(file);
return -1;
}
uint8_t crc_bytes[4];
size_t bytes_read = fread(crc_bytes, 1, 4, file);
if (bytes_read != 4) {
fprintf(stderr, "Failed to read stored CRC\n");
fclose(file);
return -1;
}
stored_crc = (uint32_t)crc_bytes[0] << 0 |
(uint32_t)crc_bytes[1] << 8 |
(uint32_t)crc_bytes[2] << 16 |
(uint32_t)crc_bytes[3] << 24;
fclose(file);
// Вычисляем CRC для данных (без последних 4 байт)
calculated_crc = calculate_file_crc32_without_last4(filename, verbose);
if (calculated_crc == 0) {
fprintf(stderr, "Failed to calculate CRC\n");
return -1;
}
// Всегда выводим значения CRC при проверке
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) {
printf("\n✓ VERIFIED: CRC matches! File integrity check passed.\n");
return 0;
} else {
printf("\n✗ MISMATCH: File is corrupted or CRC was not written correctly!\n");
printf(" Difference: 0x%08X\n", calculated_crc ^ stored_crc);
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 Выводит справку
*/
void print_usage(const char *program_name) {
printf("\nCRC32 Tool for BIN files\n");
printf("========================\n\n");
printf("Usage: %s [OPTIONS] <filename>\n\n", program_name);
printf("Options:\n");
printf(" -w, --write Calculate CRC32 from all except 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(" -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(" -h, --help Show this help\n");
printf("\nExamples:\n");
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 -c firmware.bin # Verify CRC32\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(" For -w and -c operations, CRC is calculated from the first\n");
printf(" (file_size - 4) bytes, ignoring the last 4 bytes.\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");
}
/**
* @brief Разбирает аргументы командной строки
*/
int parse_arguments(int argc, char *argv[], ProgramOptions *options) {
int option_index = 0;
int c;
static struct option long_options[] = {
{"write", no_argument, 0, 'w'},
{"check", no_argument, 0, 'c'},
{"show-only", no_argument, 0, 's'},
{"split", required_argument, 0, 1000},
{"output1", required_argument, 0, 1001},
{"output2", required_argument, 0, 1002},
{"verbose", no_argument, 0, 'v'},
{"help", no_argument, 0, 'h'},
{0, 0, 0, 0}
};
memset(options, 0, sizeof(ProgramOptions));
// Инициализация имен выходных файлов
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) {
case 'w':
options->write_crc = 1;
break;
case 'c':
options->verify_crc = 1;
break;
case 's':
options->show_only = 1;
break;
case 'v':
options->verbose = 1;
break;
case 'h':
print_usage(argv[0]);
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 '?':
return -1;
}
}
if (optind >= argc) {
fprintf(stderr, "Error: No filename specified.\n");
print_usage(argv[0]);
return -1;
}
options->filename = argv[optind];
// Подсчет количества выбранных режимов
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;
}
// Проверка параметров для split
if (options->split) {
if (options->split_offset <= 0) {
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;
}
/**
* @brief Главная функция
*/
int main(int argc, char *argv[]) {
ProgramOptions options;
uint32_t crc_value;
int result = 0;
if (parse_arguments(argc, argv, &options) != 0) {
return 1;
}
if (options.show_only) {
// Показать CRC всего файла
printf("\n--- CRC32 of %s ---\n", options.filename);
crc_value = calculate_file_crc32_full(options.filename, options.verbose);
if (crc_value == 0) {
fprintf(stderr, "Failed to calculate CRC32\n");
return 1;
}
printf("\nCRC32 (full file): 0x%08X (%u)\n", crc_value, crc_value);
}
else if (options.write_crc) {
// Записать CRC
printf("\n--- Writing CRC32 to %s ---\n", options.filename);
if (options.verbose) {
printf("\nStep 1: Calculating CRC32 from first (file_size - 4) bytes...\n");
}
crc_value = calculate_file_crc32_without_last4(options.filename, options.verbose);
if (crc_value == 0) {
fprintf(stderr, "Failed to calculate CRC32\n");
return 1;
}
// Всегда выводим вычисленное CRC при записи
printf("\n╔════════════════════════════════════════╗\n");
printf("║ CRC32 Calculation ║\n");
printf("╠════════════════════════════════════════╣\n");
printf("║ Calculated CRC : 0x%08X (%10u) ║\n", crc_value, crc_value);
printf("╚════════════════════════════════════════╝\n");
if (options.verbose) {
printf("\nStep 2: Writing CRC to last 4 bytes...\n");
}
result = write_crc32_to_file(options.filename, crc_value, options.verbose);
if (result != 0) {
fprintf(stderr, "Failed to write CRC32\n");
return 1;
}
printf("\n✓ CRC32 successfully written to file\n");
// Опционально: проверим сразу после записи
if (options.verbose) {
printf("\n--- Verifying after write ---\n");
verify_crc32(options.filename, 0);
}
}
else if (options.verify_crc) {
// Проверить CRC
printf("\n--- Verifying CRC32 for %s ---\n", options.filename);
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;
}