diff --git a/APP/main.c b/APP/main.c index 5998926..a726750 100644 --- a/APP/main.c +++ b/APP/main.c @@ -57,7 +57,11 @@ typedef struct { int write_crc; // Флаг: записывать CRC в файл int verify_crc; // Флаг: проверять CRC int show_only; // Флаг: только показать CRC без записи + int split; // Флаг: разрезать файл int verbose; // Флаг: подробный вывод + long split_offset; // Смещение для разрезания (в байтах) + char *output1; // Имя первого выходного файла + char *output2; // Имя второго выходного файла } 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); 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) для блока данных в памяти @@ -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) { FILE *file = NULL; long file_size; + long data_size; + int result = 0; file = fopen(filename, "rb+"); if (file == NULL) { @@ -237,6 +246,7 @@ int write_crc32_to_file(const char *filename, uint32_t crc_value, int verbose) { return -1; } + // Получаем размер файла if (fseek(file, 0, SEEK_END) != 0) { perror("Failed to seek to end"); fclose(file); @@ -250,11 +260,70 @@ int write_crc32_to_file(const char *filename, uint32_t crc_value, int verbose) { 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) { perror("Failed to seek to CRC position"); - fclose(file); - return -1; + result = -1; + goto cleanup; } // Записываем 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); if (bytes_written != 4) { fprintf(stderr, "Failed to write CRC to file\n"); - fclose(file); - return -1; + result = -1; + goto cleanup; } - fclose(file); - if (verbose) { - printf("CRC32 value written: 0x%08X (%u)\n", crc_value, crc_value); - printf("Written to bytes: %ld-%ld\n", file_size - 4, file_size - 1); + printf("\nCRC32 value written: 0x%08X (%u)\n", crc_value, crc_value); + 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"); } - return 0; + cleanup: + fclose(file); + return result; } /** * @brief Проверяет CRC32, сравнивая вычисленное значение с сохраненным + * Также опционально проверяет сохраненный размер данных */ int verify_crc32(const char *filename, int verbose) { FILE *file = NULL; long file_size; + long stored_data_size = 0; uint32_t calculated_crc = 0; uint32_t stored_crc = 0; + int verify_size = 1; // Флаг проверки размера file = fopen(filename, "rb"); if (file == NULL) { @@ -314,7 +388,48 @@ int verify_crc32(const char *filename, int verbose) { 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) { perror("Failed to seek to stored CRC"); fclose(file); @@ -343,24 +458,224 @@ int verify_crc32(const char *filename, int verbose) { 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"); + long actual_data_size = file_size - 4; - if (calculated_crc == stored_crc) { - printf("\n✓ VERIFIED: CRC matches! File integrity check passed.\n"); + // Всегда выводим значения 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); + + 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; - } else { - printf("\n✗ MISMATCH: File is corrupted or CRC was not written correctly!\n"); + } else if (crc_valid && !size_valid) { + 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); 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 Выводит справку */ @@ -373,16 +688,26 @@ void print_usage(const char *program_name) { 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 Split file into two parts at specified offset (bytes)\n"); + printf(" -1, --output1 Output filename for first part (with --split)\n"); + printf(" -2, --output2 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 -v -w firmware.bin # Write with verbose output\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 -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(" 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(" _part1.bin and _part2.bin\n"); printf("\n"); } @@ -394,17 +719,26 @@ int parse_arguments(int argc, char *argv[], ProgramOptions *options) { int c; static struct option long_options[] = { - {"write", no_argument, 0, 'w'}, - {"check", no_argument, 0, 'c'}, - {"show-only", no_argument, 0, 's'}, - {"verbose", no_argument, 0, 'v'}, - {"help", no_argument, 0, 'h'}, + {"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)); - 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) { case 'w': options->write_crc = 1; @@ -421,6 +755,27 @@ int parse_arguments(int argc, char *argv[], ProgramOptions *options) { 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; } @@ -434,14 +789,37 @@ int parse_arguments(int argc, char *argv[], ProgramOptions *options) { 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; } - int mode_count = options->write_crc + options->verify_crc + options->show_only; - if (mode_count > 1) { - fprintf(stderr, "Error: Cannot use multiple modes\n"); - return -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; @@ -492,7 +870,7 @@ int main(int argc, char *argv[]) { printf("╚════════════════════════════════════════╝\n"); 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); @@ -515,6 +893,15 @@ int main(int argc, char *argv[]) { 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; } \ No newline at end of file