diff --git a/CMakeLists.txt b/CMakeLists.txt index 21498fb..a2b60ff 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,6 +8,7 @@ project(inflatelib # "Production" options option(INFLATELIB_BUILD_SHARED "Build inflatelib as a shared library" OFF) +option(INFLATELIB_API_DOC "Generate API documentation" OFF) # "Test" options option(INFLATELIB_TEST "Build tests for local development and CI validation" ON) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 2c42e11..ab05202 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,2 +1,33 @@ +include(GNUInstallDirs) add_subdirectory(lib) + +if (INFLATELIB_API_DOC) + find_package(Doxygen REQUIRED doxygen dot) + + set(DOXYGEN_PROJECT_NAME "InflateLib") + set(DOXYGEN_OPTIMIZE_OUTPUT_FOR_C YES) + set(DOXYGEN_ENABLE_PREPROCESSING YES) + set(DOXYGEN_MACRO_EXPANSION YES) + set(DOXYGEN_EXPAND_ONLY_PREDEF YES) + set(DOXYGEN_PREDEFINED "INFLATELIB_CALLCONV=" "INFLATELIB_EXPORT=") + + set(DOXYGEN_FULL_PATH_NAMES YES) + set(DOXYGEN_STRIP_FROM_PATH + "${PROJECT_SOURCE_DIR}/src" + "${PROJECT_SOURCE_DIR}/src/include" + ) + + doxygen_add_docs(inflatelib_api_docs + ./index.dox + ./include/inflatelib.h + ALL + USE_STAMP_FILE + ) + + install( + DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/html + DESTINATION ${CMAKE_INSTALL_DOCDIR} + COMPONENT doc + ) +endif() diff --git a/src/include/inflatelib.h b/src/include/inflatelib.h index 8513cdf..a147956 100644 --- a/src/include/inflatelib.h +++ b/src/include/inflatelib.h @@ -6,6 +6,75 @@ * TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * PARTICULAR PURPOSE AND NONINFRINGEMENT. */ + +/** @file inflatelib.h + * @brief InflateLib C API. + * + * This API can be used to decompress DEFLATE or DEFFLATE64 encoded + * data. + * + * Example decoding DEFLATE64 encoded data: + * \code + * #include + * #include + * #include + * + * #include + * + * int main () { + * // As an example, the input contains the DEFLATE/DEFLATE64 encoded string "Hello world\n". + * size_t inputSize = 14; + * const char *input = "\xf3\x48\xcd\xc9\xc9\x57\x28\xcf\x2f\xca\x49\xe1\x02\x00"; + * + * // Initialize outputBuffer + * size_t outputBufferSize = 4096; + * char *outputBuffer = malloc(outputBufferSize); + * if (outputBuffer == NULL) { + * printf("Memory allocation failed.\n"); + * return 1; + * } + * + * // Initialize stream. + * inflatelib_stream stream = { 0 }; + * if (inflatelib_init(&stream) != INFLATELIB_OK) { + * fwrite(stream.error_msg, 1, strlen(stream.error_msg), stdout); + * return 1; + * } + * + * // Setup stream to read from input. Assume the whole input + * // stream is in memory. Otherwise we need to update these values + * // and read new data as necessary inside a loop. + * stream.next_in = input; + * stream.avail_in = inputSize; + * + * // Decode the data from the input. + * int result = INFLATELIB_OK; + * while (result != INFLATELIB_EOF) { + * stream.next_out = outputBuffer; + * stream.avail_out = outputBufferSize; + * + * result = inflatelib_inflate64(&stream); + * if (result < INFLATELIB_OK) { + * fwrite(stream.error_msg, 1, strlen(stream.error_msg), stdout); + * inflatelib_destroy(&stream); + * return 1; + * } + * + * fwrite(outputBuffer, 1, outputBufferSize - stream.avail_out, stdout); + * + * } + * + * // Discard stream. + * inflatelib_destroy(&stream); + * + * // Discard outputBuffer + * free(outputBuffer); + * + * return 0; + * }; + * \endcode + */ + #ifndef INFLATELIB_H #define INFLATELIB_H @@ -18,7 +87,8 @@ #endif #endif -/* +/** @cond + * * INFLATELIB_BUILD_SHARED The library is being built as a shared library * INFLATELIB_CONSUME_SHARED The library is being consumed as a shared library * Otherwise... The library is either being built as a static library or it is being consumed in an @@ -37,166 +107,352 @@ #else #define INFLATELIB_EXPORT /* Not Windows and no visibility attribute... don't decorate function declarations */ #endif +/** @endcond */ +/** @cond */ #if defined(_WIN32) && defined(_MSC_VER) #define INFLATELIB_CALLCONV __cdecl #else #define INFLATELIB_CALLCONV #endif +/** @endcond */ #ifdef __cplusplus extern "C" { #endif +/** + * \brief The library version of the headers. + */ #define INFLATELIB_VERSION_STRING "0.3.0" + +/** + * \brief The major version number of the library headers. + */ #define INFLATELIB_VERSION_MAJOR 0 + +/** + * \brief The minor version number of the library headers. + */ #define INFLATELIB_VERSION_MINOR 3 + +/** + * \brief The patch version number of the library headers. + */ #define INFLATELIB_VERSION_PATCH 0 + /** + * @brief Function pointer type for a custom memory allocation callback. + * + * The allocation callback is used by InflateLib to request aligned memory blocks. + * + * @param[in,out] userData User-specified context pointer passed from the library host. + * @param[in] bytes The number of bytes to allocate. + * @param[in] alignment The required memory alignment boundary (in bytes). + * + * @return A pointer to the allocated memory block, or @c NULL if allocation fails. + */ typedef void* (*inflatelib_alloc)(void* userData, size_t bytes, size_t alignment); + + /** + * @brief Function pointer type for a custom memory deallocation callback. + * + * The deallocation callback is used by InflateLib to free memory blocks + * previously allocated by the corresponding allocation callback. + * + * @param[in,out] userData User-specified context pointer passed from the library host. + * @param[in] allocatedPtr Pointer to the memory block to be freed. If @c NULL, no action is taken. + * @param[in] bytes The size of the allocated block (must match the original allocation size). + * @param[in] alignment The alignment boundary of the allocated block (must match the original allocation alignment). + */ typedef void (*inflatelib_free)(void* userData, void* allocatedPtr, size_t bytes, size_t alignment); - struct inflatelib_state; /* Opaque to client applications */ - - /* - * This struct stores all data and state for decompressing Deflate/Deflate64 encoded data. With the exception of - * success/error codes, all input and output data is passed through this struct. Specifically, input and output - * buffers are set by the caller via 'next_in'/'avail_in' and 'next_out'/'avail_out' respectively. The "inflate" and - * "inflate64" functions communicate the amount of data consumed/written by updating these buffers and lengths. For - * example, you can determine the amount of data consumed/written by a call to 'inflatelib_inflate' or - * 'inflatelib_inflate64' by either subtracting 'next_in'/'next_out' after the call by their original pointers - * (interpreted as uintptr_t values) or by subtracting 'avail_in'/'avail_out' after the call from the sizes passed - * in. Alternatively, you can subtract 'total_in'/'total_out' after the call by their values before the call (or - * equivalently by setting them to zero before the call and reading their values after the call). - * - * Internally, these objects behave as a state machine. After being initialized, they transition to either "Deflate" - * or "Deflate64" decoding states via calls to 'inflatelib_inflate' and 'inflatelib_inflate64' respectively. When - * in these states, the only valid operations are to destroy the object, put the object back into the initialized - * state via 'inflatelib_reset', or to decompress more data using the function that corresponds to the current - * state: either 'inflatelib_inflate' for the "Deflate" state or 'inflatelib_inflate64' for the "Deflate64" state. - * If you attempt to call 'inflatelib_inflate64' when in the "Deflate" state or vice-versa, the call will fail. + /** + * Opaque to client applications + */ + struct inflatelib_state; + + /** + * @brief This struct stores all data and state for decompressing + * DEFLATE/DEFLATE64 encoded data. + * + * With the exception of success/error codes, all input and output data + * is passed through this struct. Specifically, input and output + * buffers are set by the caller via `next_in`/`avail_in` and + * `next_out`/`avail_out` respectively. The inflatelib_inflate() and + * inflatelib_inflate64() functions communicate the amount of data + * consumed/written by updating these buffers and lengths. + * + * For example, you can determine the amount of data consumed/written by + * a call to inflatelib_inflate() or inflatelib_inflate64() by either + * subtracting `next_in`/`next_out` after the call by their original pointers + * (interpreted as @c uintptr_t values) or by subtracting + * `avail_in`/`avail_out` after the call from the sizes passed in. + * Alternatively, you can subtract `total_in`/`total_out` after the call by + * their values before the call (or equivalently by setting them to zero + * before the call and reading their values after the call). + * + * Internally, these objects behave as a state machine. After being + * initialized, they transition to either "Deflate" or "Deflate64" + * decoding states via calls to inflatelib_inflate() and + * inflatelib_inflate64() respectively. When in these states, the only + * valid operations are to destroy the object, put the object back into + * the initialized state via inflatelib_reset(), or to decompress more + * data using the function that corresponds to the current state: + * either inflatelib_inflate() for the "Deflate" state or + * inflatelib_inflate64() for the "Deflate64" state. If you attempt to + * call inflatelib_inflate64() when in the "Deflate" state or vice-versa, + * the call will fail. */ typedef struct inflatelib_stream { - /* - * Pointer to the next byte of input. This pointer is set by the caller and updated by the library based on the + /** + * @brief Pointer to the next byte of input. + * + * This pointer is set by the caller and updated by the library based on the * number of bytes consumed. */ const void* next_in; - /* - * The number of valid bytes available for read in 'next_in'. This value is set by the caller and updated by the + + /** + * @brief The number of valid bytes available for read in 'next_in'. + * + * This value is set by the caller and updated by the * library based on the number of bytes consumed. */ size_t avail_in; - /* - * Total number of bytes read by the library so far. This value is never consumed by the library; it is only + + /** + * @brief Total number of bytes read by the library so far. + * + * This value is never consumed by the library; it is only * ever incremented. */ uintmax_t total_in; - /* - * Pointer to the next byte of output data written by the library. This pointer is set by the caller and updated - * by the library based on the number of bytes written so that this points one byte past the last byte of output - * written. + /** + * @brief Pointer to the next byte of output data written by the library. + * + * This pointer is set by the caller and updated by the library based + * on the number of bytes written so that this points one byte past + * the last byte of output written. */ void* next_out; - /* - * The number of bytes, starting at 'next_out', that can be written to. This value is set by the caller and - * updated by the library based on the number of bytes written. + + /** + * @brief The number of bytes, starting at 'next_out', that can be written to. + * + * This value is set by the caller and updated by the library based + * on the number of bytes written. */ + size_t avail_out; - /* - * Total number of bytes written by the library so far. This value is never consumed by the library; it is only - * ever incremented. + /** + * @brief Total number of bytes written by the library so far. + * + * This value is never consumed by the library; it is only ever + * incremented. */ uintmax_t total_out; - /* - * Optional user data passed to any callback functions (such as alloc/free below) + /** + * @brief Optional user data. + * + * Passed to any callback functions (such as alloc/free below). */ void* user_data; - /* - * Custom memory allocation functions. Set to null to get malloc/free respectively + /** + * @brief Custom memory allocation function. + * + * Set to @c null to get @c malloc. */ + inflatelib_alloc alloc; + /** + * @brief Custom memory deallocation function. + * + * Set to @c null to get @c free. + */ inflatelib_free free; - /* - * A string describing the last error encountered. This pointer is only valid if a library function returned - * failure + /** + * @brief A string describing the last error encountered. + * + * This pointer is only valid if a library function returned failure. */ const char* error_msg; - /* - * Internal state used by the library + /** + * @brief Internal state used by the library. */ struct inflatelib_state* internal; } inflatelib_stream; -/* - * Return values. Non-negative values indicate success while negative values indicate some sort of error. When a - * negative value is returned, the 'error_msg' member of the 'inflatelib_stream' will be set. Otherwise, the 'error_msg' +/** + * @defgroup RETURN_VALUES_GROUP Return values + * @brief Return values for inflatelib_init(), inflatelib_inflate(), inflatelib_inflate64(), inflatelib_reset() and inflatelib_destroy(). + * + * Non-negative values indicate success while negative values indicate some sort of error. When a + * negative value is returned, the `error_msg` member of the #inflatelib_stream will be set. Otherwise, the `error_msg` * will remain unchanged. A positive return value indicates an "interesting" change in state that is not considered a * failure, while a return value of zero indicates generic success. + * + * @{ + */ + +/** + * @brief No error occured. */ -#define INFLATELIB_OK 0 /* No error occurred */ -#define INFLATELIB_EOF 1 /* No error occurred; reached the end of the stream */ -#define INFLATELIB_ERROR_ARG -1 /* Invalid argument */ -#define INFLATELIB_ERROR_DATA -2 /* Error in the input data */ -#define INFLATELIB_ERROR_OOM -3 /* Failed to allocate data */ -#define INFLATELIB_ERROR_VERSION -4 /* The major version of this header and the compiled library differ */ - - /* - * Returns the version of the compiled library as a string in the form 'X.Y.Z'. The implementation just returns - * 'INFLATELIB_VERSION_STRING', however this may differ when linking, statically or dynamically, against a pre-built - * library. The major version of 'INFLATELIB_VERSION_STRING' must match the major version returned by this function, - * otherwise the two are incompatible (struct size, arrangement, etc. may differ). The 'inflatelib_init' macro does - * this for you by passing 'INFLATELIB_VERSION_STRING' to 'inflatelib_init_'. +#define INFLATELIB_OK 0 + +/** + * @brief No error occurred; reached the end of the stream. + */ +#define INFLATELIB_EOF 1 + +/** + * @brief Invalid argument error. + */ +#define INFLATELIB_ERROR_ARG -1 + +/** + * @brief Error in the input data. + */ +#define INFLATELIB_ERROR_DATA -2 + +/** + * @brief Failed to allocate memory. + */ +#define INFLATELIB_ERROR_OOM -3 + +/** + * @brief The linked library has an incompatible (major) version. + */ +#define INFLATELIB_ERROR_VERSION -4 + +/** + * @} + */ // End of RETURN_VALUES_GROUP + + /** + * @brief Returns the version of the linked InflateLib library. + * + * The implementation just returns #INFLATELIB_VERSION_STRING, however + * this may differ when linking, statically or dynamically, against a + * pre-built library. + * + * The major version of #INFLATELIB_VERSION_STRING must match the + * major version returned by this function, otherwise the two are + * incompatible (struct size, arrangement, etc. may differ). + * + * The inflatelib_init() macro does this for you by passing + * #INFLATELIB_VERSION_STRING to inflatelib_init_(). + * + * @return The version of the linked InflateLib library as a string in the form 'X.Y.Z'. */ INFLATELIB_EXPORT const char* INFLATELIB_CALLCONV inflatelib_version(void); -/* - * Initializes the stream. The 'user_data', 'alloc', and 'free' members MUST be set prior to the init call and MUST NOT - * be changed after the init call completes. This function returns one of the status values specified above. +/** + * @brief Verifies library version and initializes the stream. + * + * Verifies that the (major) version of the linked InflateLib library + * matches the (major) version of these library headers and initializes + * the \p stream. + * + * The `user_data`, `alloc` and `free` members of \p stream MUST be set prior + * to the inflatelib_init() call and MUST NOT be changed after the + * inflatelib_init() call completes. + * + * @param[in,out] stream A pointer to an #inflatelib_stream. + * + * @retval #INFLATELIB_OK On success. + * @retval #INFLATELIB_ERROR_VERSION When the linked library has an incompatible (major) version. + * @retval #INFLATELIB_ERROR_OOM When it fails allocating memory. */ #define inflatelib_init(stream) inflatelib_init_(stream, INFLATELIB_VERSION_STRING) - /* - * Backing implementation of 'inflatelib_init' that verififes the major version of this header matches the major - * version the library was compiled with. + /** + * @brief Verifies required library version and initializes the stream. + * + * Verifies that the (major) version of the linked InflateLib library + * matches the required version and initializes the \p stream. + * + * The `user_data`, `alloc`, and `free` members of \p stream MUST be set + * prior to the inflatelib_init_() call and MUST NOT be changed after the + * inflatelib_init_() call completes. + * + * @param[in,out] stream A pointer to an #inflatelib_stream. + * @param[in] version The required library version. + * + * @retval #INFLATELIB_OK On success. + * @retval #INFLATELIB_ERROR_VERSION When the linked library is incompatible with the requested version. + * @retval #INFLATELIB_ERROR_OOM When it fails allocating memory. + * */ INFLATELIB_EXPORT int INFLATELIB_CALLCONV inflatelib_init_(inflatelib_stream* stream, const char* version); - /* - * Resets the stream's state back to its initialized state. This allows the stream to be reused for multiple inflate - * calls without having to destroy and reinitialize it. Typically, this is used to reset the stream after an inflate - * call returns EOF, however it can also be used to reset the stream after an error or even during the middle of - * inflating a stream. This function also allows the caller to switch between Deflate and Deflate64. + /** + * @brief Resets the stream's state back to its initialized state. + * + * This allows the stream to be reused for multiple inflate + * calls without having to destroy and reinitialize it. Typically, this + * is used to reset the stream after an inflatelib_inflate() or an + * inflatelib_inflate64() call returns #INFLATELIB_EOF, however it can also be used + * to reset the stream after an error or even during the middle of + * inflating a stream. + * + * This function also allows the caller to switch between Deflate and Deflate64. + * + * @param[in,out] stream A pointer to an #inflatelib_stream previously initialized by inflatelib_init(). + * + * @retval #INFLATELIB_OK On success. + * @retval #INFLATELIB_ERROR_ARG When \p stream is not initialized correctly. */ INFLATELIB_EXPORT int INFLATELIB_CALLCONV inflatelib_reset(inflatelib_stream* stream); - /* - * Cleans up any data allocated/initialized by the library. This function must be called if 'inflatelib_init' - * returns success. After this function is called, the 'inflatelib_stream' cannot be used for any function call - * unless 'inflatelib_init' is called again. This function can only return success. + /** + * @brief Cleans up any data allocated/initialized by the library. + * + * This function must be called if inflatelib_init() returns success. After this function + * is called, the @p stream cannot be used for any function call + * unless inflatelib_init() is called again. + * + * @param[in,out] stream A pointer to an #inflatelib_stream previously initialized by inflatelib_init(). + * + * @retval #INFLATELIB_OK On success. + * @retval #INFLATELIB_ERROR_ARG When \p stream is not initialized correctly. */ INFLATELIB_EXPORT int INFLATELIB_CALLCONV inflatelib_destroy(inflatelib_stream* stream); - /* - * "Inflates" the Deflate encoded data from next_in/avail_in, writing the decoded data to next_out/avail_out. The - * 'stream' MUST be in either the "initialized" state or the "Deflate" state. This function returns one of the - * status values defined above, notably it returns 'INFLATELIB_EOF' when the last block of data has been fully - * processed. + /** + * @brief Inflates DEFLATE encoded data. + * + * Reads a block of DEFLATE encoded data from `stream.next_in`/`stream.avail_in` and + * writes decoded data to `stream.next_out`/`stream.avail_out`. + * + * @param[in,out] stream A pointer to an #inflatelib_stream either in the "initialized" or "Deflate" state. + * + * @retval #INFLATELIB_OK When there is still unprocessed input data left. + * @retval #INFLATELIB_EOF When the last block of data has been fully processed. + * @retval #INFLATELIB_ERROR_ARG When \p stream is not initialized correctly. + * @retval #INFLATELIB_ERROR_DATA When there is an error in the input data. */ INFLATELIB_EXPORT int INFLATELIB_CALLCONV inflatelib_inflate(inflatelib_stream* stream); - /* - * "Inflates" the Deflate64 encoded data from next_in/avail_in, writing the decoded data to next_out/avail_out. The - * 'stream' MUST be in either the "initialized" state or the "Deflate64" state. This function returns one of the - * status values defined above, notably it returns 'INFLATELIB_EOF' when the last block of data has been fully - * processed. + /** + * @brief Inflates DEFLATE64 encoded data. + * + * Reads a block of DEFLATE64 encoded data from `stream.next_in`/`stream.avail_in` and + * writes decoded data to `stream.next_out`/`stream.avail_out`. + * + * @param[in,out] stream A pointer to an #inflatelib_stream either in the "initialized" or "Deflate64" state. + * + * @retval #INFLATELIB_OK When there is still unprocessed input data left. + * @retval #INFLATELIB_EOF When the last block of data has been fully processed. + * @retval #INFLATELIB_ERROR_ARG When \p stream is not initialized correctly. + * @retval #INFLATELIB_ERROR_DATA When there is an error in the input data. */ INFLATELIB_EXPORT int INFLATELIB_CALLCONV inflatelib_inflate64(inflatelib_stream* stream); diff --git a/src/index.dox b/src/index.dox new file mode 100644 index 0000000..86e9973 --- /dev/null +++ b/src/index.dox @@ -0,0 +1,6 @@ +/** \mainpage + +The InflateLib library can be used to decompress DEFLATE or DEFFLATE64 encoded data. + +- The C API is documented in inflatelib.h. +*/