303 lines
		
	
	
		
			8.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
		
		
			
		
	
	
			303 lines
		
	
	
		
			8.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
|  | /* Xz.h - Xz interface
 | ||
|  | 2017-07-27 : Igor Pavlov : Public domain */ | ||
|  | 
 | ||
|  | #ifndef __XZ_H
 | ||
|  | #define __XZ_H
 | ||
|  | 
 | ||
|  | #include "Sha256.h"
 | ||
|  | 
 | ||
|  | EXTERN_C_BEGIN | ||
|  | 
 | ||
|  | #define XZ_ID_Subblock 1
 | ||
|  | #define XZ_ID_Delta 3
 | ||
|  | #define XZ_ID_X86 4
 | ||
|  | #define XZ_ID_PPC 5
 | ||
|  | #define XZ_ID_IA64 6
 | ||
|  | #define XZ_ID_ARM 7
 | ||
|  | #define XZ_ID_ARMT 8
 | ||
|  | #define XZ_ID_SPARC 9
 | ||
|  | #define XZ_ID_LZMA2 0x21
 | ||
|  | 
 | ||
|  | unsigned Xz_ReadVarInt(const Byte *p, size_t maxSize, UInt64 *value); | ||
|  | unsigned Xz_WriteVarInt(Byte *buf, UInt64 v); | ||
|  | 
 | ||
|  | /* ---------- xz block ---------- */ | ||
|  | 
 | ||
|  | #define XZ_BLOCK_HEADER_SIZE_MAX 1024
 | ||
|  | 
 | ||
|  | #define XZ_NUM_FILTERS_MAX 4
 | ||
|  | #define XZ_BF_NUM_FILTERS_MASK 3
 | ||
|  | #define XZ_BF_PACK_SIZE (1 << 6)
 | ||
|  | #define XZ_BF_UNPACK_SIZE (1 << 7)
 | ||
|  | 
 | ||
|  | #define XZ_FILTER_PROPS_SIZE_MAX 20
 | ||
|  | 
 | ||
|  | typedef struct | ||
|  | { | ||
|  |   UInt64 id; | ||
|  |   UInt32 propsSize; | ||
|  |   Byte props[XZ_FILTER_PROPS_SIZE_MAX]; | ||
|  | } CXzFilter; | ||
|  | 
 | ||
|  | typedef struct | ||
|  | { | ||
|  |   UInt64 packSize; | ||
|  |   UInt64 unpackSize; | ||
|  |   Byte flags; | ||
|  |   CXzFilter filters[XZ_NUM_FILTERS_MAX]; | ||
|  | } CXzBlock; | ||
|  | 
 | ||
|  | #define XzBlock_GetNumFilters(p) (((p)->flags & XZ_BF_NUM_FILTERS_MASK) + 1)
 | ||
|  | #define XzBlock_HasPackSize(p)   (((p)->flags & XZ_BF_PACK_SIZE) != 0)
 | ||
|  | #define XzBlock_HasUnpackSize(p) (((p)->flags & XZ_BF_UNPACK_SIZE) != 0)
 | ||
|  | #define XzBlock_HasUnsupportedFlags(p) (((p)->flags & ~(XZ_BF_NUM_FILTERS_MASK | XZ_BF_PACK_SIZE | XZ_BF_UNPACK_SIZE)) != 0)
 | ||
|  | 
 | ||
|  | SRes XzBlock_Parse(CXzBlock *p, const Byte *header); | ||
|  | SRes XzBlock_ReadHeader(CXzBlock *p, ISeqInStream *inStream, Bool *isIndex, UInt32 *headerSizeRes); | ||
|  | 
 | ||
|  | /* ---------- xz stream ---------- */ | ||
|  | 
 | ||
|  | #define XZ_SIG_SIZE 6
 | ||
|  | #define XZ_FOOTER_SIG_SIZE 2
 | ||
|  | 
 | ||
|  | extern const Byte XZ_SIG[XZ_SIG_SIZE]; | ||
|  | 
 | ||
|  | /*
 | ||
|  | extern const Byte XZ_FOOTER_SIG[XZ_FOOTER_SIG_SIZE]; | ||
|  | */ | ||
|  | 
 | ||
|  | #define XZ_FOOTER_SIG_0 'Y'
 | ||
|  | #define XZ_FOOTER_SIG_1 'Z'
 | ||
|  | 
 | ||
|  | #define XZ_STREAM_FLAGS_SIZE 2
 | ||
|  | #define XZ_STREAM_CRC_SIZE 4
 | ||
|  | 
 | ||
|  | #define XZ_STREAM_HEADER_SIZE (XZ_SIG_SIZE + XZ_STREAM_FLAGS_SIZE + XZ_STREAM_CRC_SIZE)
 | ||
|  | #define XZ_STREAM_FOOTER_SIZE (XZ_FOOTER_SIG_SIZE + XZ_STREAM_FLAGS_SIZE + XZ_STREAM_CRC_SIZE + 4)
 | ||
|  | 
 | ||
|  | #define XZ_CHECK_MASK 0xF
 | ||
|  | #define XZ_CHECK_NO 0
 | ||
|  | #define XZ_CHECK_CRC32 1
 | ||
|  | #define XZ_CHECK_CRC64 4
 | ||
|  | #define XZ_CHECK_SHA256 10
 | ||
|  | 
 | ||
|  | typedef struct | ||
|  | { | ||
|  |   unsigned mode; | ||
|  |   UInt32 crc; | ||
|  |   UInt64 crc64; | ||
|  |   CSha256 sha; | ||
|  | } CXzCheck; | ||
|  | 
 | ||
|  | void XzCheck_Init(CXzCheck *p, unsigned mode); | ||
|  | void XzCheck_Update(CXzCheck *p, const void *data, size_t size); | ||
|  | int XzCheck_Final(CXzCheck *p, Byte *digest); | ||
|  | 
 | ||
|  | typedef UInt16 CXzStreamFlags; | ||
|  | 
 | ||
|  | #define XzFlags_IsSupported(f) ((f) <= XZ_CHECK_MASK)
 | ||
|  | #define XzFlags_GetCheckType(f) ((f) & XZ_CHECK_MASK)
 | ||
|  | #define XzFlags_HasDataCrc32(f) (Xz_GetCheckType(f) == XZ_CHECK_CRC32)
 | ||
|  | unsigned XzFlags_GetCheckSize(CXzStreamFlags f); | ||
|  | 
 | ||
|  | SRes Xz_ParseHeader(CXzStreamFlags *p, const Byte *buf); | ||
|  | SRes Xz_ReadHeader(CXzStreamFlags *p, ISeqInStream *inStream); | ||
|  | 
 | ||
|  | typedef struct | ||
|  | { | ||
|  |   UInt64 unpackSize; | ||
|  |   UInt64 totalSize; | ||
|  | } CXzBlockSizes; | ||
|  | 
 | ||
|  | typedef struct | ||
|  | { | ||
|  |   CXzStreamFlags flags; | ||
|  |   size_t numBlocks; | ||
|  |   CXzBlockSizes *blocks; | ||
|  |   UInt64 startOffset; | ||
|  | } CXzStream; | ||
|  | 
 | ||
|  | void Xz_Construct(CXzStream *p); | ||
|  | void Xz_Free(CXzStream *p, ISzAllocPtr alloc); | ||
|  | 
 | ||
|  | #define XZ_SIZE_OVERFLOW ((UInt64)(Int64)-1)
 | ||
|  | 
 | ||
|  | UInt64 Xz_GetUnpackSize(const CXzStream *p); | ||
|  | UInt64 Xz_GetPackSize(const CXzStream *p); | ||
|  | 
 | ||
|  | typedef struct | ||
|  | { | ||
|  |   size_t num; | ||
|  |   size_t numAllocated; | ||
|  |   CXzStream *streams; | ||
|  | } CXzs; | ||
|  | 
 | ||
|  | void Xzs_Construct(CXzs *p); | ||
|  | void Xzs_Free(CXzs *p, ISzAllocPtr alloc); | ||
|  | SRes Xzs_ReadBackward(CXzs *p, ILookInStream *inStream, Int64 *startOffset, ICompressProgress *progress, ISzAllocPtr alloc); | ||
|  | 
 | ||
|  | UInt64 Xzs_GetNumBlocks(const CXzs *p); | ||
|  | UInt64 Xzs_GetUnpackSize(const CXzs *p); | ||
|  | 
 | ||
|  | typedef enum | ||
|  | { | ||
|  |   CODER_STATUS_NOT_SPECIFIED,               /* use main error code instead */ | ||
|  |   CODER_STATUS_FINISHED_WITH_MARK,          /* stream was finished with end mark. */ | ||
|  |   CODER_STATUS_NOT_FINISHED,                /* stream was not finished */ | ||
|  |   CODER_STATUS_NEEDS_MORE_INPUT             /* you must provide more input bytes */ | ||
|  | } ECoderStatus; | ||
|  | 
 | ||
|  | typedef enum | ||
|  | { | ||
|  |   CODER_FINISH_ANY,   /* finish at any point */ | ||
|  |   CODER_FINISH_END    /* block must be finished at the end */ | ||
|  | } ECoderFinishMode; | ||
|  | 
 | ||
|  | typedef struct _IStateCoder | ||
|  | { | ||
|  |   void *p; | ||
|  |   void (*Free)(void *p, ISzAllocPtr alloc); | ||
|  |   SRes (*SetProps)(void *p, const Byte *props, size_t propSize, ISzAllocPtr alloc); | ||
|  |   void (*Init)(void *p); | ||
|  |   SRes (*Code)(void *p, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, | ||
|  |       int srcWasFinished, ECoderFinishMode finishMode, int *wasFinished); | ||
|  | } IStateCoder; | ||
|  | 
 | ||
|  | #define MIXCODER_NUM_FILTERS_MAX 4
 | ||
|  | 
 | ||
|  | typedef struct | ||
|  | { | ||
|  |   ISzAllocPtr alloc; | ||
|  |   Byte *buf; | ||
|  |   unsigned numCoders; | ||
|  |   int finished[MIXCODER_NUM_FILTERS_MAX - 1]; | ||
|  |   size_t pos[MIXCODER_NUM_FILTERS_MAX - 1]; | ||
|  |   size_t size[MIXCODER_NUM_FILTERS_MAX - 1]; | ||
|  |   UInt64 ids[MIXCODER_NUM_FILTERS_MAX]; | ||
|  |   IStateCoder coders[MIXCODER_NUM_FILTERS_MAX]; | ||
|  | } CMixCoder; | ||
|  | 
 | ||
|  | void MixCoder_Construct(CMixCoder *p, ISzAllocPtr alloc); | ||
|  | void MixCoder_Free(CMixCoder *p); | ||
|  | void MixCoder_Init(CMixCoder *p); | ||
|  | SRes MixCoder_SetFromMethod(CMixCoder *p, unsigned coderIndex, UInt64 methodId); | ||
|  | SRes MixCoder_Code(CMixCoder *p, Byte *dest, SizeT *destLen, | ||
|  |     const Byte *src, SizeT *srcLen, int srcWasFinished, | ||
|  |     ECoderFinishMode finishMode, ECoderStatus *status); | ||
|  | 
 | ||
|  | typedef enum | ||
|  | { | ||
|  |   XZ_STATE_STREAM_HEADER, | ||
|  |   XZ_STATE_STREAM_INDEX, | ||
|  |   XZ_STATE_STREAM_INDEX_CRC, | ||
|  |   XZ_STATE_STREAM_FOOTER, | ||
|  |   XZ_STATE_STREAM_PADDING, | ||
|  |   XZ_STATE_BLOCK_HEADER, | ||
|  |   XZ_STATE_BLOCK, | ||
|  |   XZ_STATE_BLOCK_FOOTER | ||
|  | } EXzState; | ||
|  | 
 | ||
|  | typedef struct | ||
|  | { | ||
|  |   EXzState state; | ||
|  |   UInt32 pos; | ||
|  |   unsigned alignPos; | ||
|  |   unsigned indexPreSize; | ||
|  | 
 | ||
|  |   CXzStreamFlags streamFlags; | ||
|  |    | ||
|  |   UInt32 blockHeaderSize; | ||
|  |   UInt64 packSize; | ||
|  |   UInt64 unpackSize; | ||
|  | 
 | ||
|  |   UInt64 numBlocks; | ||
|  |   UInt64 indexSize; | ||
|  |   UInt64 indexPos; | ||
|  |   UInt64 padSize; | ||
|  | 
 | ||
|  |   UInt64 numStartedStreams; | ||
|  |   UInt64 numFinishedStreams; | ||
|  |   UInt64 numTotalBlocks; | ||
|  | 
 | ||
|  |   UInt32 crc; | ||
|  |   CMixCoder decoder; | ||
|  |   CXzBlock block; | ||
|  |   CXzCheck check; | ||
|  |   CSha256 sha; | ||
|  | 
 | ||
|  |   unsigned decodeOnlyOneBlock; | ||
|  | 
 | ||
|  |   Byte shaDigest[SHA256_DIGEST_SIZE]; | ||
|  |   Byte buf[XZ_BLOCK_HEADER_SIZE_MAX]; | ||
|  | } CXzUnpacker; | ||
|  | 
 | ||
|  | void XzUnpacker_Construct(CXzUnpacker *p, ISzAllocPtr alloc); | ||
|  | void XzUnpacker_Init(CXzUnpacker *p); | ||
|  | void XzUnpacker_Free(CXzUnpacker *p); | ||
|  | 
 | ||
|  | /*
 | ||
|  | finishMode: | ||
|  |   It has meaning only if the decoding reaches output limit (*destLen). | ||
|  |   CODER_FINISH_ANY - use smallest number of input bytes | ||
|  |   CODER_FINISH_END - read EndOfStream marker after decoding | ||
|  | 
 | ||
|  | Returns: | ||
|  |   SZ_OK | ||
|  |     status: | ||
|  |       CODER_STATUS_NOT_FINISHED, | ||
|  |       CODER_STATUS_NEEDS_MORE_INPUT - maybe there are more xz streams, | ||
|  |                                       call XzUnpacker_IsStreamWasFinished to check that current stream was finished | ||
|  |   SZ_ERROR_MEM  - Memory allocation error | ||
|  |   SZ_ERROR_DATA - Data error | ||
|  |   SZ_ERROR_UNSUPPORTED - Unsupported method or method properties | ||
|  |   SZ_ERROR_CRC  - CRC error | ||
|  |   // SZ_ERROR_INPUT_EOF - It needs more bytes in input buffer (src).
 | ||
|  | 
 | ||
|  |   SZ_ERROR_NO_ARCHIVE - the error with xz Stream Header with one of the following reasons: | ||
|  |      - xz Stream Signature failure | ||
|  |      - CRC32 of xz Stream Header is failed | ||
|  |      - The size of Stream padding is not multiple of four bytes. | ||
|  |     It's possible to get that error, if xz stream was finished and the stream | ||
|  |     contains some another data. In that case you can call XzUnpacker_GetExtraSize() | ||
|  |     function to get real size of xz stream. | ||
|  | */ | ||
|  | 
 | ||
|  | 
 | ||
|  | SRes XzUnpacker_Code(CXzUnpacker *p, Byte *dest, SizeT *destLen, | ||
|  |     const Byte *src, SizeT *srcLen, ECoderFinishMode finishMode, | ||
|  |     ECoderStatus *status); | ||
|  | 
 | ||
|  | Bool XzUnpacker_IsStreamWasFinished(const CXzUnpacker *p); | ||
|  | 
 | ||
|  | /*
 | ||
|  | Call XzUnpacker_GetExtraSize after XzUnpacker_Code function to detect real size of | ||
|  | xz stream in two cases: | ||
|  | XzUnpacker_Code() returns: | ||
|  |   res == SZ_OK && status == CODER_STATUS_NEEDS_MORE_INPUT | ||
|  |   res == SZ_ERROR_NO_ARCHIVE | ||
|  | */ | ||
|  | 
 | ||
|  | UInt64 XzUnpacker_GetExtraSize(const CXzUnpacker *p); | ||
|  | 
 | ||
|  | 
 | ||
|  | /*
 | ||
|  |   for random block decoding: | ||
|  |     XzUnpacker_Init(); | ||
|  |     set CXzUnpacker::streamFlags | ||
|  |     XzUnpacker_PrepareToRandomBlockDecoding() | ||
|  |     loop | ||
|  |     { | ||
|  |       XzUnpacker_Code() | ||
|  |       XzUnpacker_IsBlockFinished() | ||
|  |     } | ||
|  | */ | ||
|  | 
 | ||
|  | void XzUnpacker_PrepareToRandomBlockDecoding(CXzUnpacker *p); | ||
|  | Bool XzUnpacker_IsBlockFinished(const CXzUnpacker *p); | ||
|  | 
 | ||
|  | #define XzUnpacker_GetPackSizeForIndex(p) ((p)->packSize + (p)->blockHeaderSize + XzFlags_GetCheckSize((p)->streamFlags))
 | ||
|  | 
 | ||
|  | EXTERN_C_END | ||
|  | 
 | ||
|  | #endif
 |