2
Fork 0
This repository has been archived on 2022-11-09. You can view files and clone it, but cannot push or open issues or pull requests.
oodle-cli/oodle2.h
Lucas Schwiderski 36edf93538
feat: Implement Oodle logging
The `verbosity` parameter hadn't worked before because there is
a callback that needs to be set. Since the tool runs under Wine,
the Windows default behaviour applied, which logged to the
Event Viewer.
To get output to stdout/stderr, a custom logging handler needs
to be provided.
2022-10-20 17:45:45 +02:00

287 lines
No EOL
16 KiB
C

#pragma once
#include <stdint.h>
#include <stdlib.h>
// header version :
// the DLL is incompatible when MAJOR is bumped
// MINOR is for internal revs and bug fixes that don't affect API compatibility
// TODO: Check if the DLL gives a minor version
#define OODLE2_VERSION_MAJOR 8
#define OODLE2_VERSION_MINOR 14
// OodleVersion string is 1 . MAJOR . MINOR
#define OodleVersion "2.8.14"
// Default verbosity selection of 0 will not even log when it sees corruption
// Verbosity of LZ functions
typedef enum OodleLZ_Verbosity {
OodleLZ_Verbosity_None = 0,
OodleLZ_Verbosity_Minimal = 1,
OodleLZ_Verbosity_Some = 2,
OodleLZ_Verbosity_Lots = 3,
OodleLZ_Verbosity_Force32 = 0x40000000
} OodleLZ_Verbosity;
typedef enum OodleLZ_Compressor {
OodleLZ_Compressor_Invalid = -1,
OodleLZ_Compressor_None = 3, // None = memcpy, pass through uncompressed bytes
// NEW COMPRESSORS :
OodleLZ_Compressor_Kraken = 8, // Fast decompression and high compression ratios, amazing!
OodleLZ_Compressor_Leviathan = 13,// Leviathan = Kraken's big brother with higher compression, slightly slower decompression.
OodleLZ_Compressor_Mermaid = 9, // Mermaid is between Kraken & Selkie - crazy fast, still decent compression.
OodleLZ_Compressor_Selkie = 11, // Selkie is a super-fast relative of Mermaid. For maximum decode speed.
OodleLZ_Compressor_Hydra = 12, // Hydra, the many-headed beast = Leviathan, Kraken, Mermaid, or Selkie (see $OodleLZ_About_Hydra)
OodleLZ_Compressor_BitKnit = 10,
OodleLZ_Compressor_LZB16 = 4, // DEPRECATED but still supported
OodleLZ_Compressor_LZNA = 7,
OodleLZ_Compressor_LZH = 0,
OodleLZ_Compressor_LZHLW = 1,
OodleLZ_Compressor_LZNIB = 2,
OodleLZ_Compressor_LZBLW = 5,
OodleLZ_Compressor_LZA = 6,
OodleLZ_Compressor_Count = 14,
OodleLZ_Compressor_Force32 = 0x40000000
} OodleLZ_Compressor;
typedef enum OodleLZ_CheckCRC {
OodleLZ_CheckCRC_No = 0,
OodleLZ_CheckCRC_Yes = 1,
OodleLZ_CheckCRC_Force32 = 0x40000000
} OodleLZ_CheckCRC;
/* Selection of compression encoder complexity
Higher numerical value of CompressionLevel = slower compression, but smaller compressed data.
The compressed stream is always decodable with the same decompressors.
CompressionLevel controls the amount of work the encoder does to find the best compressed bit stream.
CompressionLevel does not primary affect decode speed, it trades off encode speed for compressed bit stream quality.
I recommend starting with OodleLZ_CompressionLevel_Normal, then try up or down if you want
faster encoding or smaller output files.
The Optimal levels are good for distribution when you compress rarely and decompress often;
they provide very high compression ratios but are slow to encode. Optimal2 is the recommended level
to start with of the optimal levels.
Optimal4 and 5 are not recommended for common use, they are very slow and provide the maximum compression ratio,
but the gain over Optimal3 is usually small.
The HyperFast levels have negative numeric CompressionLevel values.
They are faster than SuperFast for when you're encoder CPU time constrained or want
something closer to symmetric compression vs. decompression time.
The HyperFast levels are currently only available in Kraken, Mermaid & Selkie.
Higher levels of HyperFast are faster to encode, eg. HyperFast4 is the fastest.
The CompressionLevel does not affect decode speed much. Higher compression level does not mean
slower to decode. To trade off decode speed vs ratio, use _spaceSpeedTradeoffBytes_ in $OodleLZ_CompressOptions
*/
typedef enum OodleLZ_CompressionLevel {
OodleLZ_CompressionLevel_None = 0, // don't compress, just copy raw bytes
OodleLZ_CompressionLevel_SuperFast = 1, // super fast mode, lower compression ratio
OodleLZ_CompressionLevel_VeryFast = 2, // fastest LZ mode with still decent compression ratio
OodleLZ_CompressionLevel_Fast = 3, // fast - good for daily use
OodleLZ_CompressionLevel_Normal = 4, // standard medium speed LZ mode
OodleLZ_CompressionLevel_Optimal1 = 5, // optimal parse level 1 (faster optimal encoder)
OodleLZ_CompressionLevel_Optimal2 = 6, // optimal parse level 2 (recommended baseline optimal encoder)
OodleLZ_CompressionLevel_Optimal3 = 7, // optimal parse level 3 (slower optimal encoder)
OodleLZ_CompressionLevel_Optimal4 = 8, // optimal parse level 4 (very slow optimal encoder)
OodleLZ_CompressionLevel_Optimal5 = 9, // optimal parse level 5 (don't care about encode speed, maximum compression)
OodleLZ_CompressionLevel_HyperFast1 = -1, // faster than SuperFast, less compression
OodleLZ_CompressionLevel_HyperFast2 = -2, // faster than HyperFast1, less compression
OodleLZ_CompressionLevel_HyperFast3 = -3, // faster than HyperFast2, less compression
OodleLZ_CompressionLevel_HyperFast4 = -4, // fastest, less compression
// aliases :
OodleLZ_CompressionLevel_HyperFast = OodleLZ_CompressionLevel_HyperFast1, // alias hyperfast base level
OodleLZ_CompressionLevel_Optimal = OodleLZ_CompressionLevel_Optimal2, // alias optimal standard level
OodleLZ_CompressionLevel_Max = OodleLZ_CompressionLevel_Optimal5, // maximum compression level
OodleLZ_CompressionLevel_Min = OodleLZ_CompressionLevel_HyperFast4, // fastest compression level
OodleLZ_CompressionLevel_Force32 = 0x40000000,
OodleLZ_CompressionLevel_Invalid = OodleLZ_CompressionLevel_Force32
} OodleLZ_CompressionLevel;
typedef enum OodleLZ_Decode_ThreadPhase {
OodleLZ_Decode_ThreadPhase1 = 1,
OodleLZ_Decode_ThreadPhase2 = 2,
OodleLZ_Decode_ThreadPhaseAll = 3,
OodleLZ_Decode_Unthreaded = OodleLZ_Decode_ThreadPhaseAll
} OodleLZ_Decode_ThreadPhase;
typedef enum OodleLZ_FuzzSafe {
OodleLZ_FuzzSafe_No = 0,
OodleLZ_FuzzSafe_Yes = 1
} OodleLZ_FuzzSafe;
/* Compress some data from memory to memory, synchronously, with OodleLZ
$:compressor which OodleLZ variant to use in compression
$:rawBuf raw data to compress
$:rawLen number of bytes in rawBuf to compress
$:compBuf pointer to write compressed data to ; should be at least $OodleLZ_GetCompressedBufferSizeNeeded
$:level OodleLZ_CompressionLevel controls how much CPU effort is put into maximizing compression
$:pOptions (optional) options; if NULL, $OodleLZ_CompressOptions_GetDefault is used
$:dictionaryBase (optional) if not NULL, provides preceding data to prime the dictionary; must be contiguous with rawBuf, the data between the pointers _dictionaryBase_ and _rawBuf_ is used as the preconditioning data. The exact same precondition must be passed to encoder and decoder.
$:lrm (optional) long range matcher
$:scratchMem (optional) pointer to scratch memory
$:scratchSize (optional) size of scratch memory (see $OodleLZ_GetCompressScratchMemBound)
$:return size of compressed data written, or $OODLELZ_FAILED for failure
Performs synchronous memory to memory LZ compression.
In tools, you should generally use $OodleXLZ_Compress_AsyncAndWait instead to get parallelism. (in the Oodle2 Ext lib)
You can compress a large buffer in several calls by setting _dictionaryBase_ to the start
of the buffer, and then making _rawBuf_ and _rawLen_ select portions of that buffer. As long
as _rawLen_ is a multiple of $OODLELZ_BLOCK_LEN , the compressed chunks can simply be
concatenated together.
If _scratchMem_ is provided, it will be used for the compressor's scratch memory needs before OodleMalloc is
called. If the scratch is big enough, no malloc will be done. If the scratch is not big enough, the compress
will not fail, instead OodleMalloc will be used. OodleMalloc should not return null. There is currently no way
to make compress fail cleanly due to using too much memory, it must either succeed or abort the process.
If _scratchSize_ is at least $OodleLZ_GetCompressScratchMemBound , additional allocations will not be needed.
See $OodleLZ_About for tips on setting the compression options.
If _dictionaryBase_ is provided, the backup distance from _rawBuf_ must be a multiple of $OODLELZ_BLOCK_LEN
If $(OodleLZ_CompressOptions:seekChunkReset) is enabled, and _dictionaryBase_ is not NULL or _rawBuf_ , then the
seek chunk boundaries are relative to _dictionaryBase_, not to _rawBuf_.
*/
extern "C" intptr_t __stdcall OodleLZ_Compress(
OodleLZ_Compressor compressor,
const void* raw_buffer,
size_t raw_len,
void* compressed_buffer,
OodleLZ_CompressionLevel level,
void* options, // Default: null
size_t dictionary_base, // Default: null
const void* lrm, // Default: null
void* scratch_memory, // Default: null
size_t scratch_size // Default: null
);
// Decompress returns raw (decompressed) len received
// Decompress returns 0 (OODLELZ_FAILED) if it detects corruption
/* Decompress a some data from memory to memory, synchronously.
$:compBuf pointer to compressed data
$:compBufSize number of compressed bytes available (must be greater or equal to the number consumed)
$:rawBuf pointer to output uncompressed data into
$:rawLen number of uncompressed bytes to output
$:fuzzSafe (optional) should the decode fail if it contains non-fuzz safe codecs?
$:checkCRC (optional) if data could be corrupted and you want to know about it, pass OodleLZ_CheckCRC_Yes
$:verbosity (optional) if not OodleLZ_Verbosity_None, logs some info
$:decBufBase (optional) if not NULL, provides preceding data to prime the dictionary; must be contiguous with rawBuf, the data between the pointers _dictionaryBase_ and _rawBuf_ is used as the preconditioning data. The exact same precondition must be passed to encoder and decoder. The decBufBase must be a reset point.
$:decBufSize (optional) size of decode buffer starting at decBufBase, if 0, _rawLen_ is assumed
$:fpCallback (optional) OodleDecompressCallback to call incrementally as decode proceeds
$:callbackUserData (optional) passed as userData to fpCallback
$:decoderMemory (optional) pre-allocated memory for the Decoder, of size _decoderMemorySize_
$:decoderMemorySize (optional) size of the buffer at _decoderMemory_; must be at least $OodleLZDecoder_MemorySizeNeeded bytes to be used
$:threadPhase (optional) for threaded decode; see $OodleLZ_About_ThreadPhasedDecode (default OodleLZ_Decode_Unthreaded)
$:return the number of decompressed bytes output, $OODLELZ_FAILED (0) if none can be decompressed
Decodes data encoded with any $OodleLZ_Compressor.
Note : _rawLen_ must be the actual number of bytes to output, the same as the number that were encoded with the corresponding
OodleLZ_Compress size. You must store this somewhere in your own header and pass it in to this call. _compBufSize_ does NOT
need to be the exact number of compressed bytes, is the number of bytes available in the buffer, it must be greater or equal to
the actual compressed length.
Note that the new compressors (Kraken,Mermaid,Selkie,BitKnit) are all fuzz safe and you can use OodleLZ_FuzzSafe_Yes
with them and no padding of the decode target buffer.
If checkCRC is OodleLZ_CheckCRC_Yes, then corrupt data will be detected and the decode aborted.
If checkCRC is OodleLZ_CheckCRC_No, then corruption might result in invalid data, but no detection of any error (garbage in, garbage out).
If corruption is possible, _fuzzSafe_ is No and _checkCRC_ is OodleLZ_CheckCRC_No, $OodleLZ_GetDecodeBufferSize must be used to allocate
_rawBuf_ large enough to prevent overrun.
$OodleLZ_GetDecodeBufferSize should always be used to ensure _rawBuf_ is large enough, even when corruption is not
possible (when fuzzSafe is No).
_compBuf_ and _rawBuf_ are allowed to overlap for "in place" decoding, but then _rawBuf_ must be allocated to
the size given by $OodleLZ_GetInPlaceDecodeBufferSize , and the compressed data must be at the end of that buffer.
An easy way to take the next step to parallel decoding is with $OodleXLZ_Decompress_MakeSeekTable_Wide_Async (in the Oodle2 Ext lib)
NOTE : the return value is the *total* number of decompressed bytes output so far. If rawBuf is > decBufBase, that means
the initial inset of (rawBuf - decBufBase) is included! (eg. you won't just get _rawLen_)
If _decBufBase_ is provided, the backup distance from _rawBuf_ must be a multiple of $OODLELZ_BLOCK_LEN
About fuzz safety:
OodleLZ_Decompress is guaranteed not to crash even if the data is corrupted when _fuzzSafe_ is set to OodleLZ_FuzzSafe_Yes.
When _fuzzSafe_ is Yes, the target buffer (_rawBuf_ and _rawLen_) will never be overrun. Note that corrupted data might not
be detected (the return value might indicate success).
Fuzz Safe decodes will not crash on corrupt data. They may or may not return failure, and produce garbage output.
Fuzz safe decodes will not read out of bounds. They won't put data on the stack or previously in memory
into the output buffer.
Fuzz safe decodes will not output more than the uncompressed size. (eg. the output buffer does not need to
be padded like OodleLZ_GetDecodeBufferSize)
If you ask for a fuzz safe decode and the compressor doesn't satisfy OodleLZ_Compressor_CanDecodeFuzzSafe
then it will return failure.
The _fuzzSafe_ argument should always be OodleLZ_FuzzSafe_Yes as of Oodle 2.9.0 ; older compressors did not
support fuzz safety but they now all do.
Use of OodleLZ_FuzzSafe_No is deprecated.
*/
extern "C" intptr_t __stdcall OodleLZ_Decompress(
const void* compressed_buffer,
size_t compressed_length,
void* raw_buffer,
size_t raw_length,
OodleLZ_FuzzSafe fuzz_safe, // Default: OodleLZ_FuzzSafe_Yes
OodleLZ_CheckCRC check_crc, // Default: OodleLZ_CheckCRC_No
OodleLZ_Verbosity verbosity, // Default: OodleLZ_Verbosity_None
void* decBufBase, // Default: null
size_t decBufSize, // Default: 0
void* callback, // Default: null
void* callback_user_data, // Default: null
void* decoder_memory, // Default: null
size_t decoder_memory_size, // Default: 0
OodleLZ_Decode_ThreadPhase thread_phase // Default: OodleLZ_Decode_Unthreaded
);
/* Function pointer to Oodle Core printf
$:verboseLevel verbosity of the message; 0-2 ; lower = more important
$:file C file that sent the message
$:line C line that sent the message
$:fmt vararg printf format string
The logging function installed here must parse varargs like printf.
_verboseLevel_ may be used to omit verbose messages.
*/
extern "C" typedef void(__stdcall t_fp_OodleCore_Plugin_Printf)(int verboseLevel, const char* file, int line, const char* fmt, ...);
/* Install the callback used by Oodle Core for logging
$:fp_rrRawPrintf function pointer to your log function; may be NULL to disable all logging
$:return returns the previous function pointer
Use this function to install your own printf for Oodle Core.
The default implementation in debug builds, if you install nothing, uses the C stdio printf for logging.
On Microsoft platforms, it uses OutputDebugString and not stdio.
To disable all logging, call OodleCore_Plugins_SetPrintf(NULL)
WARNING : this function is NOT thread safe! It should be done only once and done in a place where the caller can guarantee thread safety.
In the debug build of Oodle, you can install OodleCore_Plugin_Printf_Verbose to get more verbose logging
*/
t_fp_OodleCore_Plugin_Printf* __stdcall OodleCore_Plugins_SetPrintf(t_fp_OodleCore_Plugin_Printf* fp_rrRawPrintf);