1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
#ifndef __CHD_H__
#define __CHD_H__
#pragma once
#include <stdarg.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
/**
* Open a CHD for reading.
*/
#define CHD_OPEN_READ 1
/**
* Open a CHD for reading and writing. This mode is not supported and will always return an error
* when passed into a constructor function such as [`chd_open`](crate::chd_open).
*/
#define CHD_OPEN_READWRITE 2
/**
* The chunk size to read when pre-caching the underlying file stream into memory.
*/
#define PRECACHE_CHUNK_SIZE ((16 * 1024) * 1024)
#define CHD_MD5_BYTES 16
#define CHD_SHA1_BYTES 20
/**
* An opaque type for an opened CHD file.
*/
typedef struct chd_file chd_file;
/**
* libchdr-compatible CHD header struct.
* This struct is ABI-compatible with [chd.h](https://github.com/rtissera/libchdr/blob/cdcb714235b9ff7d207b703260706a364282b063/include/libchdr/chd.h#L302)
*/
typedef struct chd_header {
uint32_t length;
uint32_t version;
uint32_t flags;
uint32_t compression[4];
uint32_t hunkbytes;
uint32_t totalhunks;
uint64_t logicalbytes;
uint64_t metaoffset;
uint64_t mapoffset;
uint8_t md5[CHD_MD5_BYTES];
uint8_t parentmd5[CHD_MD5_BYTES];
uint8_t sha1[CHD_SHA1_BYTES];
uint8_t rawsha1[CHD_SHA1_BYTES];
uint8_t parentsha1[CHD_SHA1_BYTES];
uint32_t unitbytes;
uint64_t unitcount;
uint32_t hunkcount;
uint32_t mapentrybytes;
uint8_t *rawmap;
uint32_t obsolete_cylinders;
uint32_t obsolete_sectors;
uint32_t obsolete_heads;
uint32_t obsolete_hunksize;
} chd_header;
typedef void core_file;
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
/**
* Opens a CHD file by file name, with a layout-undefined backing file pointer owned by
* the library.
*
* The result of passing an object created by this function into [`chd_core_file`](crate::chd_core_file)
* is strictly undefined. Instead, all `chd_file*` pointers with provenance from `chd_open` should be
* closed with [`chd_close`](crate::chd_close).
*
* # Safety
* * `filename` is a valid, null-terminated **UTF-8** string.
* * `parent` is either `NULL` or a valid pointer to a `chd_file` obtained from [`chd_open`](crate::chd_open), [`chd_open_file`](crate::chd_open_file), or [`chd_open_core_file`](crate::chd_open_core_file).
* * `out` is aligned and can store a pointer to a `chd_file*`. On success, `out` will point to a valid `chd_file*`.
* * After this function returns, `parent` is invalid and must not be used, otherwise it will be undefined behaviour. There is no way to retake ownership of `parent`.
*/
chd_error chd_open(const char *filename,
int mode,
struct chd_file *parent,
struct chd_file **out);
/**
* Close a CHD file.
*
* # Safety
* * `chd` is either `NULL` or a valid pointer to a `chd_file` obtained from [`chd_open`](crate::chd_open), [`chd_open_file`](crate::chd_open_file), or [`chd_open_core_file`](crate::chd_open_core_file).
* * If `chd` is `NULL`, this does nothing.
*/
void chd_close(struct chd_file *chd);
/**
* Returns an error string for the corresponding CHD error.
*
* # Safety
* The returned string is leaked and the memory **should not and can not ever** be validly freed.
* Attempting to free the returned pointer with `free` is **undefined behaviour**.
*/
const char *chd_error_string(chd_error err);
/**
* Returns a pointer to the extracted CHD header data.
* # Safety
* * `chd` is either `NULL` or a valid pointer to a `chd_file` obtained from [`chd_open`](crate::chd_open), [`chd_open_file`](crate::chd_open_file), or [`chd_open_core_file`](crate::chd_open_core_file).
* * If `chd` is `NULL`, returns `NULL`.
* * The returned pointer is leaked and the memory **should not and can not ever** be validly freed. Attempting to free the returned pointer with `free` is **undefined behaviour**. A non-leaking variant is provided in [`chd_read_header`](crate::chd_read_header).
*/
const struct chd_header *chd_get_header(const struct chd_file *chd);
/**
* Read a single hunk from the CHD file.
*
* # Safety
* * `chd` is either `NULL` or a valid pointer to a `chd_file` obtained from [`chd_open`](crate::chd_open), [`chd_open_file`](crate::chd_open_file), or [`chd_open_core_file`](crate::chd_open_core_file).
* * `buffer` must an aligned pointer to a block of initialized memory of exactly the hunk size for the input `chd_file*` that is valid for both reads and writes. This size can be found with [`chd_get_header`](crate::chd_get_header).
* * If `chd` is `NULL`, returns `CHDERR_INVALID_PARAMETER`.
*/
chd_error chd_read(struct chd_file *chd,
uint32_t hunknum,
void *buffer);
/**
* Get indexed metadata of the given search tag and index.
*
* # Safety
* * `chd` is either `NULL` or a valid pointer to a `chd_file` obtained from [`chd_open`](crate::chd_open), [`chd_open_file`](crate::chd_open_file), or [`chd_open_core_file`](crate::chd_open_core_file).
* * `output` must be an aligned pointer to a block of initialized memory of size exactly `output_len` that is valid for writes.
* * `result_len` must be either NULL or an aligned pointer to a `uint32_t` that is valid for writes.
* * `result_tag` must be either NULL or an aligned pointer to a `uint32_t` that is valid for writes.
* * `result_flags` must be either NULL or an aligned pointer to a `uint8_t` that is valid for writes.
* * If `chd` is `NULL`, returns `CHDERR_INVALID_PARAMETER`.
*/
chd_error chd_get_metadata(struct chd_file *chd,
uint32_t searchtag,
uint32_t searchindex,
void *output,
uint32_t output_len,
uint32_t *result_len,
uint32_t *result_tag,
uint8_t *result_flags);
/**
* Set codec internal parameters.
*
* This function is not supported and always returns `CHDERR_INVALID_PARAMETER`.
*/
chd_error chd_codec_config(const struct chd_file *_chd, int32_t _param, void *_config);
/**
* Read CHD header data from the file into the pointed struct.
*
* # Safety
* * `filename` is a valid, null-terminated **UTF-8** string.
* * `header` is either `NULL`, or an aligned pointer to a possibly uninitialized `chd_header` struct.
* * If `header` is `NULL`, returns `CHDERR_INVALID_PARAMETER`
*/
chd_error chd_read_header(const char *filename,
struct chd_header *header);
/**
* Returns the associated `core_file*`.
*
* This method has different semantics than `chd_core_file` in libchdr.
*
* The input `chd_file*` will be dropped, and all prior references to
* to the input `chd_file*` are rendered invalid, with the same semantics as `chd_close`.
*
* The provenance of the `chd_file*` is important to keep in mind.
*
* If the input `chd_file*` was opened with [`chd_open`](crate::chd_open), the input `chd_file*` will be closed,
* and the return value should be considered undefined. For now it is `NULL`, but relying on this
* behaviour is unstable and may change in the future.
*
* If the input `chd_file*` was opened with `chd_open_file` and the `chd_core_file` crate feature
* is enabled, this method will return the same pointer as passed to `chd_input_file`, which may
* be possible to cast to `FILE*` depending on the implementation of `libchdcorefile` that was
* linked.
*
* # Safety
* * `chd` is either `NULL` or a valid pointer to a `chd_file` obtained from [`chd_open`](crate::chd_open), [`chd_open_file`](crate::chd_open_file), or [`chd_open_core_file`](crate::chd_open_core_file).
* * If `chd` is `NULL`, returns `NULL`.
* * If `chd` has provenance from [`chd_open`](crate::chd_open), the returned pointer is undefined and must not be used.
* * `chd` is **no longer valid** upon return of this function, and subsequent reuse of the `chd_file*` pointer is **undefined behaviour**.
*/
core_file *chd_core_file(struct chd_file *chd);
/**
* Open an existing CHD file from an opened `core_file` object.
*
* Ownership is taken of the `core_file*` object and should not be modified until
* `chd_core_file` is called to retake ownership of the `core_file*`.
*
* # Safety
* * `file` is a valid pointer to a `core_file` with respect to the implementation of libchdcorefile that was linked.
* * `parent` is either `NULL` or a valid pointer to a `chd_file` obtained from [`chd_open`](crate::chd_open), [`chd_open_file`](crate::chd_open_file), or [`chd_open_core_file`](crate::chd_open_core_file).
* * `out` is aligned and can store a pointer to a `chd_file*`. On success, `out` will point to a valid `chd_file*`.
* * Until the returned `chd_file*` in `out` is closed with [`chd_close`](crate::chd_close) or [`chd_core_file`](crate::chd_core_file), external mutation of `file` will result in undefined behaviour.
* * After this function returns, `parent` is invalid and must not be used, otherwise it will be undefined behaviour. There is no way to retake ownership of `parent`.
*/
chd_error chd_open_file(core_file *file,
int mode,
struct chd_file *parent,
struct chd_file **out);
/**
* Open an existing CHD file from an opened `core_file` object.
*
* Ownership is taken of the `core_file*` object and should not be modified until
* `chd_core_file` is called to retake ownership of the `core_file*`.
*
* # Safety
* * `file` is a valid pointer to a `core_file` with respect to the implementation of libchdcorefile that was linked.
* * `parent` is either `NULL` or a valid pointer to a `chd_file` obtained from [`chd_open`](crate::chd_open), [`chd_open_file`](crate::chd_open_file), or [`chd_open_core_file`](crate::chd_open_core_file).
* * `out` is aligned and can store a pointer to a `chd_file*`. On success, `out` will point to a valid `chd_file*`.
* * Until the returned `chd_file*` in `out` is closed with [`chd_close`](crate::chd_close) or [`chd_core_file`](crate::chd_core_file), external mutation of `file` will result in undefined behaviour.
* * After this function returns, `parent` is invalid and must not be used, otherwise it will be undefined behaviour. There is no way to retake ownership of `parent`.
*/
chd_error chd_open_core_file(core_file *file,
int mode,
struct chd_file *parent,
struct chd_file **out);
/**
* Get the name of a particular codec.
*
* This method always returns the string "Unknown"
*/
const char *chd_get_codec_name(uint32_t _codec);
/**
* Precache the underlying file into memory with an optional callback to report progress.
*
* The underlying stream of the input `chd_file` is swapped with a layout-undefined in-memory stream.
*
* If the provenance of the original `chd_file` is from [`chd_open`](crate::chd_open), then the underlying
* stream is safely dropped.
*
* If instead the underlying stream is a `core_file` opened from [`chd_open_file`](crate::chd_open_file),
* or [`chd_open_core_file`](crate::chd_open_core_file), then the same semantics of calling [`chd_core_file`](crate::chd_core_file)
* applies, and ownership of the underlying stream is released to the caller.
*
* After precaching, the input `chd_file` no longer returns a valid inner stream when passed to [`chd_core_file`](crate::chd_core_file),
* and should be treated as having the same provenance as being from [`chd_open`](crate::chd_open).
*
* # Safety
* * `chd` is either `NULL` or a valid pointer to a `chd_file` obtained from [`chd_open`](crate::chd_open), [`chd_open_file`](crate::chd_open_file), or [`chd_open_core_file`](crate::chd_open_core_file).
*/
chd_error chd_precache_progress(struct chd_file *chd,
void (*progress)(size_t pos, size_t total, void *param),
void *param);
/**
* Precache the underlying file into memory.
*
* The underlying stream of the input `chd_file` is swapped with a layout-undefined in-memory stream.
*
* If the provenance of the original `chd_file` is from [`chd_open`](crate::chd_open), then the underlying
* stream is safely dropped.
*
* If instead the underlying stream is a `core_file` opened from [`chd_open_file`](crate::chd_open_file),
* or [`chd_open_core_file`](crate::chd_open_core_file), then the same semantics of calling [`chd_core_file`](crate::chd_core_file)
* applies, and ownership of the underlying stream is released to the caller.
*
* After precaching, the input `chd_file` no longer returns a valid inner stream when passed to [`chd_core_file`](crate::chd_core_file),
* and should be treated as having the same provenance as being from [`chd_open`](crate::chd_open).
*
* # Safety
* * `chd` is either `NULL` or a valid pointer to a `chd_file` obtained from [`chd_open`](crate::chd_open), [`chd_open_file`](crate::chd_open_file), or [`chd_open_core_file`](crate::chd_open_core_file).
*/
chd_error chd_precache(struct chd_file *chd);
#ifdef __cplusplus
} // extern "C"
#endif // __cplusplus
#endif /* __CHD_H__ */