UNIX C解析特定二进制文件格式:验证限制并输出指定信息
Alright, let's build this custom binary file parser for UNIX environments. I'll walk you through a complete implementation that handles all the requirements, including validation checks and the specified output format.
Custom Binary File Parser (UNIX C Implementation)
Quick Spec Recap
First, let's restate the file format to keep things clear:
File Header (variable total size)
Magic: 1 byte (unique identifier for your file type)Header_size: 2 bytes (total size of the entire header, including section headers)Version: 1 byte (file format version)No_of_sections: 1 byte (number of sections in the file)Section_headers:No_of_sections × sizeof(section_header)bytes (array of section metadata)
Section Header (29 bytes each)
Sect_name: 17 bytes (null-terminated section name)Sect_type: 4 bytes (section type identifier)Sect_offset: 4 bytes (offset from start of file to section data)Sect_size: 4 bytes (size of the section data)
Complete Code Implementation
#include <stdio.h> #include <stdlib.h> #include <fcntl.h> #include <unistd.h> #include <stdint.h> #include <string.h> #include <arpa/inet.h> // Adjust this to match your file's actual magic number #define EXPECTED_MAGIC 0x42 typedef struct { char sect_name[17]; uint32_t sect_type; uint32_t sect_offset; uint32_t sect_size; } section_header_t; typedef struct { uint8_t magic; uint16_t header_size; uint8_t version; uint8_t no_of_sections; } file_header_t; int main(int argc, char *argv[]) { if (argc != 2) { fprintf(stderr, "Usage: %s <binary_file>\n", argv[0]); return EXIT_FAILURE; } int fd = open(argv[1], O_RDONLY); if (fd == -1) { perror("Failed to open file"); return EXIT_FAILURE; } // Get total file size to validate section bounds off_t file_size = lseek(fd, 0, SEEK_END); if (file_size == -1) { perror("Failed to get file size"); close(fd); return EXIT_FAILURE; } lseek(fd, 0, SEEK_SET); // Read main file header file_header_t header; ssize_t bytes_read = read(fd, &header, sizeof(file_header_t)); if (bytes_read != sizeof(file_header_t)) { perror("Failed to read file header"); close(fd); return EXIT_FAILURE; } // Convert network byte order to host byte order (critical for cross-UNIX compatibility) uint16_t declared_header_size = ntohs(header.header_size); // Validation 1: Check magic number if (header.magic != EXPECTED_MAGIC) { fprintf(stderr, "Error: Invalid magic number (got 0x%02x, expected 0x%02x)\n", header.magic, EXPECTED_MAGIC); close(fd); return EXIT_FAILURE; } // Validation 2: Calculate expected header size vs declared size uint16_t expected_header_size = sizeof(file_header_t) + header.no_of_sections * sizeof(section_header_t); if (declared_header_size != expected_header_size) { fprintf(stderr, "Error: Header size mismatch (declared %u, expected %u)\n", declared_header_size, expected_header_size); close(fd); return EXIT_FAILURE; } // Validation 3: Ensure header doesn't exceed file size if (declared_header_size > file_size) { fprintf(stderr, "Error: Header size (%u) exceeds total file size (%ld)\n", declared_header_size, file_size); close(fd); return EXIT_FAILURE; } // Allocate memory for section headers section_header_t *sections = malloc(header.no_of_sections * sizeof(section_header_t)); if (!sections) { perror("Failed to allocate memory for sections"); close(fd); return EXIT_FAILURE; } // Read section headers bytes_read = read(fd, sections, header.no_of_sections * sizeof(section_header_t)); if (bytes_read != header.no_of_sections * sizeof(section_header_t)) { perror("Failed to read section headers"); free(sections); close(fd); return EXIT_FAILURE; } // Prepare output string printf("version=%u nr_sections=%u", header.version, header.no_of_sections); for (int i = 0; i < header.no_of_sections; i++) { // Convert section fields from network byte order uint32_t type = ntohl(sections[i].sect_type); uint32_t size = ntohl(sections[i].sect_size); // Validation 4: Ensure section data fits within file bounds uint32_t offset = ntohl(sections[i].sect_offset); if (offset + size > file_size) { fprintf(stderr, "\nWarning: Section %d (%s) exceeds file bounds - skipping\n", i+1, sections[i].sect_name); continue; } printf(" section%d: %s %u %u", i+1, sections[i].sect_name, type, size); } printf("\n"); // Cleanup free(sections); close(fd); return EXIT_SUCCESS; }
Key Details & Validation Checks
Let's break down the critical parts of this implementation:
- Magic Number Validation: Ensures we're parsing the correct file type (update
EXPECTED_MAGICto match your actual file specification) - Header Size Mismatch Check: Confirms the declared header size matches the calculated size (based on section count), catching malformed files
- File Bound Checks: Prevents out-of-bounds reads by verifying section offsets + sizes don't exceed the total file size
- Byte Order Handling: Uses
ntohs()andntohl()to convert network byte order (standard for most binary formats) to the host system's byte order, ensuring compatibility across different UNIX-based systems - Error Handling: Properly checks for failures in file operations, memory allocation, and reads, with clear error messages
Compilation & Usage
- Save the code to a file (e.g.,
bin_parser.c) - Compile with GCC:
gcc -o bin_parser bin_parser.c - Run the parser on your binary file:
./bin_parser your_binary_file.bin
内容的提问来源于stack exchange,提问作者Siespi
相关产品推荐
相关产品推荐

