openexr_context.h 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541
  1. /*
  2. ** SPDX-License-Identifier: BSD-3-Clause
  3. ** Copyright Contributors to the OpenEXR Project.
  4. */
  5. #ifndef OPENEXR_CONTEXT_H
  6. #define OPENEXR_CONTEXT_H
  7. #include "openexr_errors.h"
  8. #include "openexr_base.h"
  9. #include <stddef.h>
  10. #include <stdint.h>
  11. #ifdef __cplusplus
  12. extern "C" {
  13. #endif
  14. /** @file */
  15. /**
  16. * @defgroup Context Context related definitions
  17. *
  18. * A context is a single instance of an OpenEXR file or stream. Beyond
  19. * a particular file or stream handle, it also has separate controls
  20. * for error handling and memory allocation. This is done to enable
  21. * encoding or decoding on mixed hardware.
  22. *
  23. * @{
  24. */
  25. /** Opaque context handle
  26. *
  27. * The implementation of this is partly opaque to provide better
  28. * version portability, and all accesses to relevant data should
  29. * happen using provided functions. This handle serves as a container
  30. * and identifier for all the metadata and parts associated with a
  31. * file and/or stream.
  32. */
  33. typedef struct _priv_exr_context_t* exr_context_t;
  34. typedef const struct _priv_exr_context_t* exr_const_context_t;
  35. /**
  36. * @defgroup ContextFunctions OpenEXR Context Stream/File Functions
  37. *
  38. * @brief These are a group of function interfaces used to customize
  39. * the error handling, memory allocations, or I/O behavior of an
  40. * OpenEXR context.
  41. *
  42. * @{
  43. */
  44. /** @brief Stream error notifier
  45. *
  46. * This function pointer is provided to the stream functions by the
  47. * library such that they can provide a nice error message to the
  48. * user during stream operations.
  49. */
  50. typedef exr_result_t (*exr_stream_error_func_ptr_t) (
  51. exr_const_context_t ctxt, exr_result_t code, const char* fmt, ...)
  52. EXR_PRINTF_FUNC_ATTRIBUTE;
  53. /** @brief Error callback function
  54. *
  55. * Because a file can be read from using many threads at once, it is
  56. * difficult to store an error message for later retrieval. As such,
  57. * when a file is constructed, a callback function can be provided
  58. * which delivers an error message for the calling application to
  59. * handle. This will then be delivered on the same thread causing the
  60. * error.
  61. */
  62. typedef void (*exr_error_handler_cb_t) (
  63. exr_const_context_t ctxt, exr_result_t code, const char* msg);
  64. /** Destroy custom stream function pointer
  65. *
  66. * Generic callback to clean up user data for custom streams.
  67. * This is called when the file is closed and expected not to
  68. * error.
  69. *
  70. * @param failed Indicates the write operation failed, the
  71. * implementor may wish to cleanup temporary files
  72. * @param ctxt The context
  73. * @param userdata The userdata
  74. */
  75. typedef void (*exr_destroy_stream_func_ptr_t) (
  76. exr_const_context_t ctxt, void* userdata, int failed);
  77. /** Query stream size function pointer
  78. *
  79. * Used to query the size of the file, or amount of data representing
  80. * the openexr file in the data stream.
  81. *
  82. * This is used to validate requests against the file. If the size is
  83. * unavailable, return -1, which will disable these validation steps
  84. * for this file, although appropriate memory safeguards must be in
  85. * place in the calling application.
  86. */
  87. typedef int64_t (*exr_query_size_func_ptr_t) (
  88. exr_const_context_t ctxt, void* userdata);
  89. /** @brief Read custom function pointer
  90. *
  91. * Used to read data from a custom output. Expects similar semantics to
  92. * pread or ReadFile with overlapped data under win32.
  93. *
  94. * It is required that this provides thread-safe concurrent access to
  95. * the same file. If the stream/input layer you are providing does
  96. * not have this guarantee, your are responsible for providing
  97. * appropriate serialization of requests.
  98. *
  99. * A file should be expected to be accessed in the following pattern:
  100. * - upon open, the header and part information attributes will be read
  101. * - upon the first image read request, the offset tables will be read
  102. * multiple threads accessing this concurrently may actually read
  103. * these values at the same time
  104. * - chunks can then be read in any order as preferred by the
  105. * application
  106. *
  107. * While this should mean that the header will be read in 'stream'
  108. * order (no seeks required), no guarantee is made beyond that to
  109. * retrieve image/deep data in order. So if the backing file is
  110. * truly a stream, it is up to the provider to implement appropriate
  111. * caching of data to give the appearance of being able to seek/read
  112. * atomically.
  113. */
  114. typedef int64_t (*exr_read_func_ptr_t) (
  115. exr_const_context_t ctxt,
  116. void* userdata,
  117. void* buffer,
  118. uint64_t sz,
  119. uint64_t offset,
  120. exr_stream_error_func_ptr_t error_cb);
  121. /** Write custom function pointer
  122. *
  123. * Used to write data to a custom output. Expects similar semantics to
  124. * pwrite or WriteFile with overlapped data under win32.
  125. *
  126. * It is required that this provides thread-safe concurrent access to
  127. * the same file. While it is unlikely that multiple threads will
  128. * be used to write data for compressed forms, it is possible.
  129. *
  130. * A file should be expected to be accessed in the following pattern:
  131. * - upon open, the header and part information attributes is constructed.
  132. *
  133. * - when the write_header routine is called, the header becomes immutable
  134. * and is written to the file. This computes the space to store the chunk
  135. * offsets, but does not yet write the values.
  136. *
  137. * - Image chunks are written to the file, and appear in the order
  138. * they are written, not in the ordering that is required by the
  139. * chunk offset table (unless written in that order). This may vary
  140. * slightly if the size of the chunks is not directly known and
  141. * tight packing of data is necessary.
  142. *
  143. * - at file close, the chunk offset tables are written to the file.
  144. */
  145. typedef int64_t (*exr_write_func_ptr_t) (
  146. exr_const_context_t ctxt,
  147. void* userdata,
  148. const void* buffer,
  149. uint64_t sz,
  150. uint64_t offset,
  151. exr_stream_error_func_ptr_t error_cb);
  152. /** @brief Struct used to pass function pointers into the context
  153. * initialization routines.
  154. *
  155. * This partly exists to avoid the chicken and egg issue around
  156. * creating the storage needed for the context on systems which want
  157. * to override the malloc/free routines.
  158. *
  159. * However, it also serves to make a tidier/simpler set of functions
  160. * to create and start processing exr files.
  161. *
  162. * The size member is required for version portability.
  163. *
  164. * It can be initialized using \c EXR_DEFAULT_CONTEXT_INITIALIZER.
  165. *
  166. * \code{.c}
  167. * exr_context_initializer_t myctxtinit = DEFAULT_CONTEXT_INITIALIZER;
  168. * myctxtinit.error_cb = &my_super_cool_error_callback_function;
  169. * ...
  170. * \endcode
  171. *
  172. */
  173. typedef struct _exr_context_initializer_v3
  174. {
  175. /** @brief Size member to tag initializer for version stability.
  176. *
  177. * This should be initialized to the size of the current
  178. * structure. This allows EXR to add functions or other
  179. * initializers in the future, and retain version compatibility
  180. */
  181. size_t size;
  182. /** @brief Error callback function pointer
  183. *
  184. * The error callback is allowed to be `NULL`, and will use a
  185. * default print which outputs to \c stderr.
  186. *
  187. * @sa exr_error_handler_cb_t
  188. */
  189. exr_error_handler_cb_t error_handler_fn;
  190. /** Custom allocator, if `NULL`, will use malloc. @sa exr_memory_allocation_func_t */
  191. exr_memory_allocation_func_t alloc_fn;
  192. /** Custom deallocator, if `NULL`, will use free. @sa exr_memory_free_func_t */
  193. exr_memory_free_func_t free_fn;
  194. /** Blind data passed to custom read, size, write, destroy
  195. * functions below. Up to user to manage this pointer.
  196. */
  197. void* user_data;
  198. /** @brief Custom read routine.
  199. *
  200. * This is only used during read or update contexts. If this is
  201. * provided, it is expected that the caller has previously made
  202. * the stream available, and placed whatever stream/file data
  203. * into \c user_data above.
  204. *
  205. * If this is `NULL`, and the context requested is for reading an
  206. * exr file, an internal implementation is provided for reading
  207. * from normal filesystem files, and the filename provided is
  208. * attempted to be opened as such.
  209. *
  210. * Expected to be `NULL` for a write-only operation, but is ignored
  211. * if it is provided.
  212. *
  213. * For update contexts, both read and write functions must be
  214. * provided if either is.
  215. *
  216. * @sa exr_read_func_ptr_t
  217. */
  218. exr_read_func_ptr_t read_fn;
  219. /** @brief Custom size query routine.
  220. *
  221. * Used to provide validation when reading header values. If this
  222. * is not provided, but a custom read routine is provided, this
  223. * will disable some of the validation checks when parsing the
  224. * image header.
  225. *
  226. * Expected to be `NULL` for a write-only operation, but is ignored
  227. * if it is provided.
  228. *
  229. * @sa exr_query_size_func_ptr_t
  230. */
  231. exr_query_size_func_ptr_t size_fn;
  232. /** @brief Custom write routine.
  233. *
  234. * This is only used during write or update contexts. If this is
  235. * provided, it is expected that the caller has previously made
  236. * the stream available, and placed whatever stream/file data
  237. * into \c user_data above.
  238. *
  239. * If this is `NULL`, and the context requested is for writing an
  240. * exr file, an internal implementation is provided for reading
  241. * from normal filesystem files, and the filename provided is
  242. * attempted to be opened as such.
  243. *
  244. * For update contexts, both read and write functions must be
  245. * provided if either is.
  246. *
  247. * @sa exr_write_func_ptr_t
  248. */
  249. exr_write_func_ptr_t write_fn;
  250. /** @brief Optional function to destroy the user data block of a custom stream.
  251. *
  252. * Allows one to free any user allocated data, and close any handles.
  253. *
  254. * @sa exr_destroy_stream_func_ptr_t
  255. * */
  256. exr_destroy_stream_func_ptr_t destroy_fn;
  257. /** Initialize a field specifying what the maximum image width
  258. * allowed by the context is. See exr_set_default_maximum_image_size() to
  259. * understand how this interacts with global defaults.
  260. */
  261. int max_image_width;
  262. /** Initialize a field specifying what the maximum image height
  263. * allowed by the context is. See exr_set_default_maximum_image_size() to
  264. * understand how this interacts with global defaults.
  265. */
  266. int max_image_height;
  267. /** Initialize a field specifying what the maximum tile width
  268. * allowed by the context is. See exr_set_default_maximum_tile_size() to
  269. * understand how this interacts with global defaults.
  270. */
  271. int max_tile_width;
  272. /** Initialize a field specifying what the maximum tile height
  273. * allowed by the context is. See exr_set_default_maximum_tile_size() to
  274. * understand how this interacts with global defaults.
  275. */
  276. int max_tile_height;
  277. /** Initialize a field specifying what the default zip compression level should be
  278. * for this context. See exr_set_default_zip_compresion_level() to
  279. * set it for all contexts.
  280. */
  281. int zip_level;
  282. /** Initialize the default dwa compression quality. See
  283. * exr_set_default_dwa_compression_quality() to set the default
  284. * for all contexts.
  285. */
  286. float dwa_quality;
  287. /** Initialize with a bitwise or of the various context flags
  288. */
  289. int flags;
  290. uint8_t pad[4];
  291. } exr_context_initializer_t;
  292. /** @brief context flag which will enforce strict header validation
  293. * checks and may prevent reading of files which could otherwise be
  294. * processed.
  295. */
  296. #define EXR_CONTEXT_FLAG_STRICT_HEADER (1 << 0)
  297. /** @brief Disables error messages while parsing headers
  298. *
  299. * The return values will remain the same, but error reporting will be
  300. * skipped. This is only valid for reading contexts
  301. */
  302. #define EXR_CONTEXT_FLAG_SILENT_HEADER_PARSE (1 << 1)
  303. /** @brief Disables reconstruction logic upon corrupt / missing data chunks
  304. *
  305. * This will disable the reconstruction logic that searches through an
  306. * incomplete file, and will instead just return errors at read
  307. * time. This is only valid for reading contexts
  308. */
  309. #define EXR_CONTEXT_FLAG_DISABLE_CHUNK_RECONSTRUCTION (1 << 2)
  310. /** @brief Writes an old-style, sorted header with minimal information */
  311. #define EXR_CONTEXT_FLAG_WRITE_LEGACY_HEADER (1 << 3)
  312. /** @brief Simple macro to initialize the context initializer with default values. */
  313. #define EXR_DEFAULT_CONTEXT_INITIALIZER \
  314. { \
  315. sizeof (exr_context_initializer_t), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
  316. 0, -2, -1.f, 0, {0, 0, 0, 0} \
  317. }
  318. /** @} */ /* context function pointer declarations */
  319. /** @brief Check the magic number of the file and report
  320. * `EXR_ERR_SUCCESS` if the file appears to be a valid file (or at least
  321. * has the correct magic number and can be read).
  322. */
  323. EXR_EXPORT exr_result_t exr_test_file_header (
  324. const char* filename, const exr_context_initializer_t* ctxtdata);
  325. /** @brief Close and free any internally allocated memory,
  326. * calling any provided destroy function for custom streams.
  327. *
  328. * If the file was opened for write, first save the chunk offsets
  329. * or any other unwritten data.
  330. */
  331. EXR_EXPORT exr_result_t exr_finish (exr_context_t* ctxt);
  332. /** @brief Create and initialize a read-only exr read context.
  333. *
  334. * If a custom read function is provided, the filename is for
  335. * informational purposes only, the system assumes the user has
  336. * previously opened a stream, file, or whatever and placed relevant
  337. * data in userdata to access that.
  338. *
  339. * One notable attribute of the context is that once it has been
  340. * created and returned a successful code, it has parsed all the
  341. * header data. This is done as one step such that it is easier to
  342. * provide a safe context for multiple threads to request data from
  343. * the same context concurrently.
  344. *
  345. * Once finished reading data, use exr_finish() to clean up
  346. * the context.
  347. *
  348. * If you have custom I/O requirements, see the initializer context
  349. * documentation \ref exr_context_initializer_t. The @p ctxtdata parameter
  350. * is optional, if `NULL`, default values will be used.
  351. */
  352. EXR_EXPORT exr_result_t exr_start_read (
  353. exr_context_t* ctxt,
  354. const char* filename,
  355. const exr_context_initializer_t* ctxtdata);
  356. /** @brief Enum describing how default files are handled during write. */
  357. typedef enum exr_default_write_mode
  358. {
  359. EXR_WRITE_FILE_DIRECTLY =
  360. 0, /**< Overwrite filename provided directly, deleted upon error. */
  361. EXR_INTERMEDIATE_TEMP_FILE =
  362. 1 /**< Create a temporary file, renaming it upon successful write, leaving original upon error */
  363. } exr_default_write_mode_t;
  364. /** @brief Create and initialize a write-only context.
  365. *
  366. * If a custom write function is provided, the filename is for
  367. * informational purposes only, and the @p default_mode parameter will be
  368. * ignored. As such, the system assumes the user has previously opened
  369. * a stream, file, or whatever and placed relevant data in userdata to
  370. * access that.
  371. *
  372. * Multi-Threading: To avoid issues with creating multi-part EXR
  373. * files, the library approaches writing as a multi-step process, so
  374. * the same concurrent guarantees can not be made for writing a
  375. * file. The steps are:
  376. *
  377. * 1. Context creation (this function)
  378. *
  379. * 2. Part definition (required attributes and additional metadata)
  380. *
  381. * 3. Transition to writing data (this "commits" the part definitions,
  382. * any changes requested after will result in an error)
  383. *
  384. * 4. Write part data in sequential order of parts (part<sub>0</sub>
  385. * -> part<sub>N-1</sub>).
  386. *
  387. * 5. Within each part, multiple threads can be encoding and writing
  388. * data concurrently. For some EXR part definitions, this may be able
  389. * to write data concurrently when it can predict the chunk sizes, or
  390. * data is allowed to be padded. For others, it may need to
  391. * temporarily cache chunks until the data is received to flush in
  392. * order. The concurrency around this is handled by the library
  393. *
  394. * 6. Once finished writing data, use exr_finish() to clean
  395. * up the context, which will flush any unwritten data such as the
  396. * final chunk offset tables, and handle the temporary file flags.
  397. *
  398. * If you have custom I/O requirements, see the initializer context
  399. * documentation \ref exr_context_initializer_t. The @p ctxtdata
  400. * parameter is optional, if `NULL`, default values will be used.
  401. */
  402. EXR_EXPORT exr_result_t exr_start_write (
  403. exr_context_t* ctxt,
  404. const char* filename,
  405. exr_default_write_mode_t default_mode,
  406. const exr_context_initializer_t* ctxtdata);
  407. /** @brief Create a new context for updating an exr file in place.
  408. *
  409. * This is a custom mode that allows one to modify the value of a
  410. * metadata entry, although not to change the size of the header, or
  411. * any of the image data.
  412. *
  413. * If you have custom I/O requirements, see the initializer context
  414. * documentation \ref exr_context_initializer_t. The @p ctxtdata parameter
  415. * is optional, if `NULL`, default values will be used.
  416. */
  417. EXR_EXPORT exr_result_t exr_start_inplace_header_update (
  418. exr_context_t* ctxt,
  419. const char* filename,
  420. const exr_context_initializer_t* ctxtdata);
  421. /** @brief Retrieve the file name the context is for as provided
  422. * during the start routine.
  423. *
  424. * Do not free the resulting string.
  425. */
  426. EXR_EXPORT exr_result_t
  427. exr_get_file_name (exr_const_context_t ctxt, const char** name);
  428. /** @brief Query the user data the context was constructed with. This
  429. * is perhaps useful in the error handler callback to jump back into
  430. * an object the user controls.
  431. */
  432. EXR_EXPORT exr_result_t
  433. exr_get_user_data (exr_const_context_t ctxt, void** userdata);
  434. /** Any opaque attribute data entry of the specified type is tagged
  435. * with these functions enabling downstream users to unpack (or pack)
  436. * the data.
  437. *
  438. * The library handles the memory packed data internally, but the
  439. * handler is expected to allocate and manage memory for the
  440. * *unpacked* buffer (the library will call the destroy function).
  441. *
  442. * NB: the pack function will be called twice (unless there is a
  443. * memory failure), the first with a `NULL` buffer, requesting the
  444. * maximum size (or exact size if known) for the packed buffer, then
  445. * the second to fill the output packed buffer, at which point the
  446. * size can be re-updated to have the final, precise size to put into
  447. * the file.
  448. */
  449. EXR_EXPORT exr_result_t exr_register_attr_type_handler (
  450. exr_context_t ctxt,
  451. const char* type,
  452. exr_result_t (*unpack_func_ptr) (
  453. exr_context_t ctxt,
  454. const void* data,
  455. int32_t attrsize,
  456. int32_t* outsize,
  457. void** outbuffer),
  458. exr_result_t (*pack_func_ptr) (
  459. exr_context_t ctxt,
  460. const void* data,
  461. int32_t datasize,
  462. int32_t* outsize,
  463. void* outbuffer),
  464. void (*destroy_unpacked_func_ptr) (
  465. exr_context_t ctxt, void* data, int32_t datasize));
  466. /** @brief Enable long name support in the output context */
  467. EXR_EXPORT exr_result_t
  468. exr_set_longname_support (exr_context_t ctxt, int onoff);
  469. /** @brief Write the header data.
  470. *
  471. * Opening a new output file has a small initialization state problem
  472. * compared to opening for read/update: we need to enable the user
  473. * to specify an arbitrary set of metadata across an arbitrary number
  474. * of parts. To avoid having to create the list of parts and entire
  475. * metadata up front, prior to calling the above exr_start_write(),
  476. * allow the data to be set, then once this is called, it switches
  477. * into a mode where the library assumes the data is now valid.
  478. *
  479. * It will recompute the number of chunks that will be written, and
  480. * reset the chunk offsets. If you modify file attributes or part
  481. * information after a call to this, it will error.
  482. */
  483. EXR_EXPORT exr_result_t exr_write_header (exr_context_t ctxt);
  484. /** @} */
  485. #ifdef __cplusplus
  486. } /* extern "C" */
  487. #endif
  488. #endif /* OPENEXR_CONTEXT_H */