### Benchmark CHD File Reading in C Source: https://context7.com/rtissera/libchdr/llms.txt This example demonstrates how to open, read, and benchmark a CHD file using libchdr. It includes error handling for file operations and memory allocation. Ensure you have a CHD file to test with. ```c #include #include #include #include int main(int argc, char** argv) { chd_error err; chd_file* file; const chd_header* header; void* buffer; unsigned int i; unsigned int totalbytes; clock_t start, end; double time_taken; if (argc < 2) { printf("Usage: %s \n", argv[0]); return 1; } printf("\nlibchdr benchmark tool....\n"); /* Record starting time */ start = clock(); /* Open the CHD file */ err = chd_open(argv[1], CHD_OPEN_READ, NULL, &file); if (err != CHDERR_NONE) { printf("chd_open() error: %s\n", chd_error_string(err)); return 1; } /* Get header information */ header = chd_get_header(file); totalbytes = header->hunkbytes * header->totalhunks; printf("CHD Version: %u\n", header->version); printf("Hunk size: %u bytes\n", header->hunkbytes); printf("Total hunks: %u\n", header->totalhunks); printf("Total size: %u bytes\n", totalbytes); /* Allocate buffer for reading */ buffer = malloc(header->hunkbytes); if (!buffer) { printf("Out of memory!\n"); chd_close(file); return 1; } /* Read all hunks sequentially */ printf("Reading all hunks...\n"); for (i = 0; i < header->totalhunks; i++) { err = chd_read(file, i, buffer); if (err != CHDERR_NONE) { printf("chd_read() error at hunk %u: %s\n", i, chd_error_string(err)); break; } } /* Clean up */ free(buffer); chd_close(file); /* Calculate and print results */ end = clock(); time_taken = ((double)(end - start)) / ((double)CLOCKS_PER_SEC); printf("\nResults:\n"); printf(" Read %u bytes in %lf seconds\n", totalbytes, time_taken); printf(" Rate: %lf MB/s\n", (((double)totalbytes)/(1024*1024)) / time_taken); return 0; } ``` -------------------------------- ### Add Static Library and Set Properties Source: https://github.com/rtissera/libchdr/blob/master/deps/lzma-25.01/CMakeLists.txt Defines the static library 'chdr-lzma' and sets its position-independent code property. This is a common setup for libraries intended for dynamic loading or use in shared environments. ```cmake add_library(chdr-lzma STATIC include/LzmaDec.h src/LzmaDec.c ) set_target_properties(chdr-lzma PROPERTIES POSITION_INDEPENDENT_CODE ON) ``` -------------------------------- ### Open CHD with Custom I/O Callbacks Source: https://context7.com/rtissera/libchdr/llms.txt Provides flexibility for custom I/O implementations like memory-mapped files or virtual filesystems by defining core_file_callbacks. ```c #include #include #include /* Custom file context */ typedef struct { uint8_t *data; size_t size; size_t pos; } memory_file; static uint64_t mem_fsize(void *file) { memory_file *mf = (memory_file *)file; return mf->size; } static size_t mem_fread(void *ptr, size_t size, size_t nmemb, void *file) { memory_file *mf = (memory_file *)file; size_t bytes = size * nmemb; if (mf->pos + bytes > mf->size) bytes = mf->size - mf->pos; memcpy(ptr, mf->data + mf->pos, bytes); mf->pos += bytes; return bytes / size; } static int mem_fseek(void *file, int64_t offset, int whence) { memory_file *mf = (memory_file *)file; switch (whence) { case SEEK_SET: mf->pos = offset; break; case SEEK_CUR: mf->pos += offset; break; case SEEK_END: mf->pos = mf->size + offset; break; } return 0; } static int mem_fclose(void *file) { return 0; } int main(void) { /* Set up custom callbacks */ core_file_callbacks callbacks = { .fsize = mem_fsize, .fread = mem_fread, .fseek = mem_fseek, .fclose = mem_fclose }; /* Load CHD into memory (example) */ memory_file mf = { /* ... load data ... */ }; chd_file *chd = NULL; chd_error err = chd_open_core_file_callbacks(&callbacks, &mf, CHD_OPEN_READ, NULL, &chd); if (err == CHDERR_NONE) { /* Process the CHD... */ chd_close(chd); } return 0; } ``` -------------------------------- ### Open a CHD File by Filename Source: https://context7.com/rtissera/libchdr/llms.txt Opens a CHD file using a filesystem path. This method handles header validation and codec initialization automatically. ```c #include #include #include int main(int argc, char** argv) { chd_file *chd = NULL; chd_error err; /* Open the CHD file in read-only mode */ err = chd_open("game.chd", CHD_OPEN_READ, NULL, &chd); if (err != CHDERR_NONE) { printf("Error opening CHD: %s\n", chd_error_string(err)); return 1; } printf("CHD file opened successfully!\n"); /* Always close when done */ chd_close(chd); return 0; } ``` -------------------------------- ### Convert CD-ROM MSF to LBA Source: https://context7.com/rtissera/libchdr/llms.txt Use msf_to_lba and lba_to_msf to convert between CD-ROM MSF (Minutes:Seconds:Frames) and LBA (Logical Block Address) formats. ```c #include #include void convert_cd_addresses(void) { /* MSF is packed as: MM:SS:FF in format 0x00MMSSFF */ uint32_t msf = 0x00020015; /* 02:00:21 (2 minutes, 0 seconds, 21 frames) */ uint32_t lba = msf_to_lba(msf); printf("MSF %02x:%02x:%02x = LBA %u\n", (msf >> 16) & 0xff, (msf >> 8) & 0xff, msf & 0xff, lba); /* Convert back */ uint32_t msf_back = lba_to_msf(lba); printf("LBA %u = MSF %02x:%02x:%02x\n", lba, (msf_back >> 16) & 0xff, (msf_back >> 8) & 0xff, msf_back & 0xff); } ``` -------------------------------- ### Open CHD File with Parent Reference Source: https://context7.com/rtissera/libchdr/llms.txt Open a child CHD file by first opening its parent and passing the parent handle to chd_open. The parent file must remain open while the child is in use. ```c #include #include int open_chd_with_parent(const char *child_file, const char *parent_file) { chd_file *parent = NULL; chd_file *child = NULL; chd_error err; /* First, open the parent CHD */ err = chd_open(parent_file, CHD_OPEN_READ, NULL, &parent); if (err != CHDERR_NONE) { printf("Failed to open parent: %s\n", chd_error_string(err)); return -1; } /* Now open the child CHD with the parent reference */ err = chd_open(child_file, CHD_OPEN_READ, parent, &child); if (err != CHDERR_NONE) { printf("Failed to open child: %s\n", chd_error_string(err)); chd_close(parent); return -1; } const chd_header *header = chd_get_header(child); printf("Child CHD opened successfully!\n"); printf(" Version: %u\n", header->version); printf(" Total hunks: %u\n", header->totalhunks); /* When reading hunks, parent data is automatically used where needed */ uint8_t *buffer = malloc(header->hunkbytes); for (uint32_t i = 0; i < header->totalhunks; i++) { err = chd_read(child, i, buffer); if (err != CHDERR_NONE) { printf("Read error: %s\n", chd_error_string(err)); break; } } free(buffer); /* Close child first, then parent */ chd_close(child); /* This also closes parent automatically */ return 0; } ``` -------------------------------- ### Open a CHD from an Existing FILE Pointer Source: https://context7.com/rtissera/libchdr/llms.txt Opens a CHD file using an existing FILE pointer. The library does not take ownership of the pointer, so it must be closed manually after chd_close is called. ```c #include #include int main(void) { FILE *fp = fopen("disc.chd", "rb"); if (!fp) { printf("Failed to open file\n"); return 1; } chd_file *chd = NULL; chd_error err = chd_open_file(fp, CHD_OPEN_READ, NULL, &chd); if (err != CHDERR_NONE) { printf("CHD error: %s\n", chd_error_string(err)); fclose(fp); return 1; } /* Use the CHD file... */ const chd_header *header = chd_get_header(chd); printf("CHD version: %u\n", header->version); printf("Logical bytes: %llu\n", (unsigned long long)header->logicalbytes); chd_close(chd); fclose(fp); /* Must close FILE manually */ return 0; } ``` -------------------------------- ### Configure Benchmark and Fuzzing Targets Source: https://github.com/rtissera/libchdr/blob/master/tests/CMakeLists.txt Defines the chdr-benchmark executable and an optional chdr-fuzz target with address and fuzzer sanitizers enabled. ```cmake add_executable(chdr-benchmark benchmark.c) target_link_libraries(chdr-benchmark PRIVATE chdr-static) # fuzzing if(BUILD_FUZZER) add_executable(chdr-fuzz fuzz.c) target_link_options(chdr-fuzz PRIVATE "-fsanitize=address,fuzzer") target_link_libraries(chdr-fuzz PRIVATE chdr-static) add_custom_target(fuzz COMMAND "$" "-max_len=131072" DEPENDS chdr-fuzz) endif() ``` -------------------------------- ### Configure libchdr Library with CMake Source: https://github.com/rtissera/libchdr/blob/master/deps/miniz-3.1.1/CMakeLists.txt Defines the miniz static library and sets its properties. Conditional compilation definitions are added based on the enabled options. ```cmake option(MINIZ_ARCHIVE_APIS "Enable miniz's ZIP file API" OFF) option(MINIZ_DEFLATE_APIS "Enable miniz's compression API" OFF) option(MINIZ_STDIO "Enable miniz's usage of file IO APIs" OFF) option(MINIZ_TIME "Enable miniz's usage of time APIs" OFF) add_library(miniz STATIC miniz.c miniz.h ) set_target_properties(miniz PROPERTIES POSITION_INDEPENDENT_CODE ON) if(NOT MINIZ_ARCHIVE_APIS) target_compile_definitions(miniz PUBLIC MINIZ_NO_ARCHIVE_APIS) endif() if(NOT MINIZ_DEFLATE_APIS) target_compile_definitions(miniz PUBLIC MINIZ_NO_DEFLATE_APIS) endif() if(NOT MINIZ_STDIO) target_compile_definitions(miniz PUBLIC MINIZ_NO_STDIO) endif() if(NOT MINIZ_TIME) target_compile_definitions(miniz PUBLIC MINIZ_NO_TIME) endif() ``` -------------------------------- ### chd_open_core_file_callbacks - Open CHD with Custom I/O Callbacks Source: https://context7.com/rtissera/libchdr/llms.txt Opens a CHD file using custom file I/O callbacks. This is the most flexible method, allowing integration with virtual filesystems, memory-mapped files, or platform-specific file APIs. ```APIDOC ## chd_open_core_file_callbacks ### Description Opens a CHD file using custom file I/O callbacks. This is the most flexible method, allowing integration with virtual filesystems, memory-mapped files, or platform-specific file APIs. ### Method `chd_open_core_file_callbacks` ### Parameters #### Path Parameters - **callbacks** (core_file_callbacks *) - Required - A pointer to a structure containing custom file I/O function pointers. - **file** (void *) - Required - A pointer to user-defined data that will be passed to the callback functions. - **mode** (int) - Required - The mode to open the file in (e.g., `CHD_OPEN_READ`). - **parent** (chd_file *) - Optional - Pointer to a parent CHD file if this is a child file. - **chd** (chd_file **) - Output - Pointer to a `chd_file` structure that will be populated upon success. ### Request Example ```c #include #include #include /* Custom file context */ typedef struct { uint8_t *data; size_t size; size_t pos; } memory_file; static uint64_t mem_fsize(void *file) { memory_file *mf = (memory_file *)file; return mf->size; } static size_t mem_fread(void *ptr, size_t size, size_t nmemb, void *file) { memory_file *mf = (memory_file *)file; size_t bytes = size * nmemb; if (mf->pos + bytes > mf->size) bytes = mf->size - mf->pos; memcpy(ptr, mf->data + mf->pos, bytes); mf->pos += bytes; return bytes / size; } static int mem_fseek(void *file, int64_t offset, int whence) { memory_file *mf = (memory_file *)file; switch (whence) { case SEEK_SET: mf->pos = offset; break; case SEEK_CUR: mf->pos += offset; break; case SEEK_END: mf->pos = mf->size + offset; break; } return 0; } static int mem_fclose(void *file) { return 0; } /* No-op for memory file */ int main(void) { /* Set up custom callbacks */ core_file_callbacks callbacks = { .fsize = mem_fsize, .fread = mem_fread, .fseek = mem_fseek, .fclose = mem_fclose }; /* Example: Load CHD into memory (replace with actual loading logic) */ memory_file mf = { .data = NULL, .size = 0, .pos = 0 }; /* Assume mf.data and mf.size are populated here */ chd_file *chd = NULL; chd_error err = chd_open_core_file_callbacks(&callbacks, &mf, CHD_OPEN_READ, NULL, &chd); if (err == CHDERR_NONE) { printf("CHD opened successfully with custom callbacks!\n"); /* Process the CHD... */ chd_close(chd); } else { printf("Error opening CHD with custom callbacks: %s\n", chd_error_string(err)); } /* Free memory if allocated */ // free(mf.data); return 0; } ``` ### Response #### Success Response (CHDERR_NONE) - **chd** (chd_file *) - A pointer to the opened CHD file structure. #### Response Example ``` CHD opened successfully with custom callbacks! ``` ``` -------------------------------- ### chd_open - Open a CHD File by Filename Source: https://context7.com/rtissera/libchdr/llms.txt Opens a CHD file for reading using its filesystem path. This function validates the header, initializes decompression codecs, and prepares the file for reading. ```APIDOC ## chd_open ### Description Opens a CHD file for reading using the filesystem path. This is the simplest way to access a CHD file. The function validates the CHD header, initializes decompression codecs, and prepares the file for hunk-by-hunk reading. ### Method `chd_open` ### Parameters #### Path Parameters - **filename** (string) - Required - The path to the CHD file. - **mode** (int) - Required - The mode to open the file in (e.g., `CHD_OPEN_READ`). - **parent** (chd_file *) - Optional - Pointer to a parent CHD file if this is a child file. - **chd** (chd_file **) - Output - Pointer to a `chd_file` structure that will be populated upon success. ### Request Example ```c #include #include #include int main(int argc, char** argv) { chd_file *chd = NULL; chd_error err; /* Open the CHD file in read-only mode */ err = chd_open("game.chd", CHD_OPEN_READ, NULL, &chd); if (err != CHDERR_NONE) { printf("Error opening CHD: %s\n", chd_error_string(err)); return 1; } printf("CHD file opened successfully!\n"); /* Always close when done */ chd_close(chd); return 0; } ``` ### Response #### Success Response (CHDERR_NONE) - **chd** (chd_file *) - A pointer to the opened CHD file structure. #### Error Responses - **CHDERR_OPEN_FAILED**: Failed to open the specified file. - **CHDERR_HEADER_INVALID**: The CHD header is invalid or corrupted. - **CHDERR_UNSUPPORTED_CODEC**: The CHD file uses a compression codec not supported by the library. - **CHDERR_VERSION_UNSUPPORTED**: The CHD file version is not supported. #### Response Example ``` CHD file opened successfully! ``` ``` -------------------------------- ### chd_open_file - Open a CHD from an Existing FILE Pointer Source: https://context7.com/rtissera/libchdr/llms.txt Opens a CHD file using an already-opened FILE pointer. This allows integration with existing file handling code. The library does not take ownership of the FILE handle. ```APIDOC ## chd_open_file ### Description Opens a CHD file using an already-opened FILE pointer. This allows integration with existing file handling code. The library does not take ownership of the FILE handle and will not close it when chd_close is called. ### Method `chd_open_file` ### Parameters #### Path Parameters - **fp** (FILE *) - Required - A pointer to an already opened FILE stream. - **mode** (int) - Required - The mode to open the file in (e.g., `CHD_OPEN_READ`). - **parent** (chd_file *) - Optional - Pointer to a parent CHD file if this is a child file. - **chd** (chd_file **) - Output - Pointer to a `chd_file` structure that will be populated upon success. ### Request Example ```c #include #include int main(void) { FILE *fp = fopen("disc.chd", "rb"); if (!fp) { printf("Failed to open file\n"); return 1; } chd_file *chd = NULL; chd_error err = chd_open_file(fp, CHD_OPEN_READ, NULL, &chd); if (err != CHDERR_NONE) { printf("CHD error: %s\n", chd_error_string(err)); fclose(fp); return 1; } /* Use the CHD file... */ const chd_header *header = chd_get_header(chd); printf("CHD version: %u\n", header->version); printf("Logical bytes: %llu\n", (unsigned long long)header->logicalbytes); chd_close(chd); fclose(fp); /* Must close FILE manually */ return 0; } ``` ### Response #### Success Response (CHDERR_NONE) - **chd** (chd_file *) - A pointer to the opened CHD file structure. #### Response Example ``` CHD version: 5 Logical bytes: 734003200 ``` ``` -------------------------------- ### Enable LZMA Assembly Optimization for x64 Windows Source: https://github.com/rtissera/libchdr/blob/master/deps/lzma-25.01/CMakeLists.txt Conditionally enables MASM assembly language for x64 architecture on Windows if WITH_LZMA_ASM is ON. It checks for the _M_AMD64 symbol and adds an optimized assembly source file. ```cmake elseif(WIN32) include(CheckSymbolExists) check_symbol_exists("_M_AMD64" "" CPU_X64) if(CPU_X64) enable_language(ASM_MASM) set_source_files_properties(src/LzmaDec.c PROPERTIES COMPILE_DEFINITIONS Z7_LZMA_DEC_OPT) target_sources(chdr-lzma PRIVATE Asm/x86/LzmaDecOpt.asm) set_source_files_properties(Asm/x86/LzmaDecOpt.asm PROPERTIES LANGUAGE ASM_MASM) endif() endif() endif() ``` -------------------------------- ### Enable LZMA Assembly Optimization for ARM64 Linux Source: https://github.com/rtissera/libchdr/blob/master/deps/lzma-25.01/CMakeLists.txt Conditionally enables assembly language for ARM64 architecture on Linux if WITH_LZMA_ASM is ON. It checks for the __aarch64__ symbol and adds an optimized assembly source file. ```cmake option(WITH_LZMA_ASM "Use lzma asm" ON) if(WITH_LZMA_ASM) if(CMAKE_SYSTEM_NAME STREQUAL "Linux") include(CheckSymbolExists) check_symbol_exists("__aarch64__" "" CPU_ARM64) if(CPU_ARM64) enable_language(ASM) set_source_files_properties(src/LzmaDec.c PROPERTIES COMPILE_DEFINITIONS Z7_LZMA_DEC_OPT) target_sources(chdr-lzma PRIVATE Asm/arm64/LzmaDecOpt.S) set_source_files_properties(Asm/arm64/LzmaDecOpt.S PROPERTIES LANGUAGE ASM) endif() endif() endif() ``` -------------------------------- ### Retrieve CHD Header Information Source: https://context7.com/rtissera/libchdr/llms.txt Use chd_get_header to access metadata from an opened CHD file. Requires a valid chd_file pointer obtained via chd_open. ```c #include #include void print_chd_info(const char *filename) { chd_file *chd = NULL; chd_error err = chd_open(filename, CHD_OPEN_READ, NULL, &chd); if (err != CHDERR_NONE) { printf("Error: %s\n", chd_error_string(err)); return; } const chd_header *header = chd_get_header(chd); printf("CHD File Information:\n"); printf(" Version: %u\n", header->version); printf(" Logical size: %llu bytes\n", (unsigned long long)header->logicalbytes); printf(" Hunk size: %u bytes\n", header->hunkbytes); printf(" Total hunks: %u\n", header->totalhunks); printf(" Unit size: %u bytes\n", header->unitbytes); printf(" Unit count: %llu\n", (unsigned long long)header->unitcount); /* Print compression info for V5 */ if (header->version >= 5) { printf(" Compressors: "); for (int i = 0; i < 4 && header->compression[i]; i++) { uint32_t c = header->compression[i]; printf("%c%c%c%c ", (c>>24)&0xff, (c>>16)&0xff, (c>>8)&0xff, c&0xff); } printf("\n"); } chd_close(chd); } ``` -------------------------------- ### Define Zstd Library and Properties in CMake Source: https://github.com/rtissera/libchdr/blob/master/deps/zstd-1.5.7/CMakeLists.txt Configures the Zstd library as a static target and enables position-independent code for the target. ```cmake add_library(zstd STATIC zstd.h zstd_errors.h zstddeclib.c ) set_target_properties(zstd PROPERTIES POSITION_INDEPENDENT_CODE ON) ``` -------------------------------- ### Precache CHD File in Memory Source: https://context7.com/rtissera/libchdr/llms.txt Loads the entire CHD file into memory for faster subsequent access. This trades memory usage for improved read performance, especially useful when repeatedly accessing the same CHD. Ensure necessary headers are included. ```c #include #include #include #include void benchmark_with_precache(const char *filename) { chd_file *chd = NULL; chd_error err = chd_open(filename, CHD_OPEN_READ, NULL, &chd); if (err != CHDERR_NONE) return; const chd_header *header = chd_get_header(chd); uint8_t *buffer = (uint8_t *)malloc(header->hunkbytes); /* Precache the file into memory */ printf("Precaching CHD file...\n"); err = chd_precache(chd); if (err != CHDERR_NONE) { printf("Precache failed: %s\n", chd_error_string(err)); /* Continue anyway - will fall back to normal reads */ } else { printf("File precached successfully!\n"); } /* Now reads will be much faster */ clock_t start = clock(); for (uint32_t i = 0; i < header->totalhunks; i++) { chd_read(chd, i, buffer); } clock_t end = clock(); double seconds = (double)(end - start) / CLOCKS_PER_SEC; double mb = (double)(header->hunkbytes * header->totalhunks) / (1024 * 1024); printf("Read %.2f MB in %.2f seconds (%.2f MB/s)\n", mb, seconds, mb/seconds); free(buffer); chd_close(chd); } ``` -------------------------------- ### chd_get_header Source: https://context7.com/rtissera/libchdr/llms.txt Retrieves the parsed CHD header structure from an already opened CHD file. ```APIDOC ## chd_get_header ### Description Returns a pointer to the parsed CHD header structure containing metadata about the file including version, compression type, hunk size, total size, and checksums. ### Parameters #### Path Parameters - **chd** (chd_file*) - Required - Pointer to an opened CHD file structure. ### Response - **chd_header*** - A pointer to the header structure containing file metadata. ``` -------------------------------- ### Read CHD Data Hunks Source: https://context7.com/rtissera/libchdr/llms.txt Use chd_read to extract and decompress individual hunks from a CHD file. The provided buffer must be at least the size of header->hunkbytes. ```c #include #include #include int read_all_hunks(const char *filename) { chd_file *chd = NULL; chd_error err = chd_open(filename, CHD_OPEN_READ, NULL, &chd); if (err != CHDERR_NONE) { printf("Open error: %s\n", chd_error_string(err)); return -1; } const chd_header *header = chd_get_header(chd); /* Allocate buffer for one hunk */ uint8_t *buffer = (uint8_t *)malloc(header->hunkbytes); if (!buffer) { chd_close(chd); return -1; } printf("Reading %u hunks of %u bytes each...\n", header->totalhunks, header->hunkbytes); uint64_t total_read = 0; for (uint32_t i = 0; i < header->totalhunks; i++) { err = chd_read(chd, i, buffer); if (err != CHDERR_NONE) { printf("Read error at hunk %u: %s\n", i, chd_error_string(err)); break; } total_read += header->hunkbytes; /* Process buffer data here... */ } printf("Successfully read %llu bytes\n", (unsigned long long)total_read); free(buffer); chd_close(chd); return 0; } ``` -------------------------------- ### chd_read_header Source: https://context7.com/rtissera/libchdr/llms.txt Reads the CHD header directly from a file path without requiring the file to be fully opened. ```APIDOC ## chd_read_header ### Description Reads just the CHD header from a file without fully opening it. Useful for quickly inspecting CHD files or validating them before processing. ### Parameters #### Path Parameters - **filename** (const char*) - Required - Path to the CHD file. - **header** (chd_header*) - Required - Pointer to a header structure to populate. ### Response - **chd_error** - Returns CHDERR_NONE on success, or an error code if the operation fails. ``` -------------------------------- ### Retrieve CHD Metadata Source: https://context7.com/rtissera/libchdr/llms.txt Retrieves metadata entries stored in the CHD file, such as hard disk geometry or CD-ROM track information. Ensure necessary headers are included. Handles different metadata tag versions and uses a wildcard for retrieving all entries. ```c #include #include #include void read_chd_metadata(const char *filename) { chd_file *chd = NULL; chd_error err = chd_open(filename, CHD_OPEN_READ, NULL, &chd); if (err != CHDERR_NONE) return; char metadata[256]; uint32_t resultlen, resulttag; uint8_t resultflags; /* Try to read hard disk metadata */ err = chd_get_metadata(chd, HARD_DISK_METADATA_TAG, 0, metadata, sizeof(metadata), &resultlen, &resulttag, &resultflags); if (err == CHDERR_NONE) { int cyls, heads, secs, bps; if (sscanf(metadata, "CYLS:%d,HEADS:%d,SECS:%d,BPS:%d", &cyls, &heads, &secs, &bps) == 4) { printf("Hard Disk Geometry:\n"); printf(" Cylinders: %d\n", cyls); printf(" Heads: %d\n", heads); printf(" Sectors: %d\n", secs); printf(" Bytes/Sec: %d\n", bps); } } /* Try to read CD-ROM track metadata */ for (int track = 0; track < 99; track++) { err = chd_get_metadata(chd, CDROM_TRACK_METADATA2_TAG, track, metadata, sizeof(metadata), &resultlen, &resulttag, &resultflags); if (err != CHDERR_NONE) { /* Try older format */ err = chd_get_metadata(chd, CDROM_TRACK_METADATA_TAG, track, metadata, sizeof(metadata), &resultlen, &resulttag, &resultflags); } if (err == CHDERR_NONE) { printf("Track %d: %s\n", track + 1, metadata); } else { break; /* No more tracks */ } } /* Read all metadata using wildcard */ printf("\nAll metadata entries:\n"); for (int i = 0; ; i++) { err = chd_get_metadata(chd, CHDMETATAG_WILDCARD, i, metadata, sizeof(metadata), &resultlen, &resulttag, &resultflags); if (err != CHDERR_NONE) break; printf(" Tag: %c%c%c%c, Length: %u, Flags: 0x%02x\n", (resulttag>>24)&0xff, (resulttag>>16)&0xff, (resulttag>>8)&0xff, resulttag&0xff, resultlen, resultflags); } chd_close(chd); } ``` -------------------------------- ### Read CHD Header Without Opening Source: https://context7.com/rtissera/libchdr/llms.txt Use chd_read_header to inspect a CHD file's header without the overhead of opening the full file. This is useful for validation or quick metadata checks. ```c #include #include int validate_chd_files(const char **filenames, int count) { chd_header header; int valid_count = 0; for (int i = 0; i < count; i++) { chd_error err = chd_read_header(filenames[i], &header); if (err == CHDERR_NONE) { printf("[OK] %s - v%u, %llu bytes\n", filenames[i], header.version, (unsigned long long)header.logicalbytes); valid_count++; } else { printf("[FAIL] %s - %s\n", filenames[i], chd_error_string(err)); } } return valid_count; } ``` -------------------------------- ### chd_read Source: https://context7.com/rtissera/libchdr/llms.txt Reads and decompresses a specific hunk of data from an opened CHD file. ```APIDOC ## chd_read ### Description Reads and decompresses a single hunk of data from the CHD file. The provided buffer must be at least header->hunkbytes in size. ### Parameters #### Path Parameters - **chd** (chd_file*) - Required - Pointer to an opened CHD file structure. - **hunknum** (uint32_t) - Required - The index of the hunk to read. - **buffer** (void*) - Required - Destination buffer for the decompressed data. ### Response - **chd_error** - Returns CHDERR_NONE on success, or an error code if the read fails. ``` -------------------------------- ### Convert CHD Error Codes to Strings Source: https://context7.com/rtissera/libchdr/llms.txt Use chd_error_string to translate internal CHD error codes into human-readable messages for logging or debugging. ```c #include #include void demonstrate_error_handling(void) { chd_file *chd = NULL; chd_error err; /* Demonstrate various error conditions */ const char *test_files[] = { "nonexistent.chd", "/dev/null", "corrupted.chd" }; for (int i = 0; i < 3; i++) { err = chd_open(test_files[i], CHD_OPEN_READ, NULL, &chd); printf("Opening '%s': %s (code %d)\n", test_files[i], chd_error_string(err), err); if (err == CHDERR_NONE) chd_close(chd); } /* List of possible errors */ printf("\nCHD Error Codes:\n"); chd_error errors[] = { CHDERR_NONE, CHDERR_NO_INTERFACE, CHDERR_OUT_OF_MEMORY, CHDERR_INVALID_FILE, CHDERR_INVALID_PARAMETER, CHDERR_INVALID_DATA, CHDERR_FILE_NOT_FOUND, CHDERR_REQUIRES_PARENT, CHDERR_FILE_NOT_WRITEABLE, CHDERR_READ_ERROR, CHDERR_CODEC_ERROR, CHDERR_INVALID_PARENT, CHDERR_HUNK_OUT_OF_RANGE, CHDERR_DECOMPRESSION_ERROR, CHDERR_UNSUPPORTED_VERSION, CHDERR_METADATA_NOT_FOUND }; for (int i = 0; i < sizeof(errors)/sizeof(errors[0]); i++) { printf(" %2d: %s\n", errors[i], chd_error_string(errors[i])); } } ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.