// File: crn_lzma_codec.cpp // See Copyright Notice and license at the end of inc/crnlib.h #include "crn_core.h" #include "crn_lzma_codec.h" #include "crn_strutils.h" #include "crn_checksum.h" #include "lzma_LzmaLib.h" #include "crn_threading.h" namespace crnlib { lzma_codec::lzma_codec() : m_pCompress(LzmaCompress), m_pUncompress(LzmaUncompress) { CRNLIB_ASSUME(cLZMAPropsSize == LZMA_PROPS_SIZE); } lzma_codec::~lzma_codec() { } bool lzma_codec::pack(const void* p, uint n, crnlib::vector& buf) { if (n > 1024U*1024U*1024U) return false; uint max_comp_size = n + math::maximum(128, n >> 8); buf.resize(sizeof(header) + max_comp_size); header* pHDR = reinterpret_cast(&buf[0]); uint8* pComp_data = &buf[sizeof(header)]; utils::zero_object(*pHDR); pHDR->m_uncomp_size = n; pHDR->m_adler32 = adler32(p, n); if (n) { size_t destLen = 0; size_t outPropsSize = 0; int status = SZ_ERROR_INPUT_EOF; for (uint trial = 0; trial < 3; trial++) { destLen = max_comp_size; outPropsSize = cLZMAPropsSize; status = (*m_pCompress)(pComp_data, &destLen, reinterpret_cast(p), n, pHDR->m_lzma_props, &outPropsSize, -1, /* 0 <= level <= 9, default = 5 */ 0, /* default = (1 << 24) */ -1, /* 0 <= lc <= 8, default = 3 */ -1, /* 0 <= lp <= 4, default = 0 */ -1, /* 0 <= pb <= 4, default = 2 */ -1, /* 5 <= fb <= 273, default = 32 */ #ifdef WIN32 (g_number_of_processors > 1) ? 2 : 1 #else 1 #endif ); if (status != SZ_ERROR_OUTPUT_EOF) break; max_comp_size += ((n+1)/2); buf.resize(sizeof(header) + max_comp_size); pHDR = reinterpret_cast(&buf[0]); pComp_data = &buf[sizeof(header)]; } if (status != SZ_OK) { buf.clear(); return false; } pHDR->m_comp_size = static_cast(destLen); buf.resize(CRNLIB_SIZEOF_U32(header) + static_cast(destLen)); } pHDR->m_sig = header::cSig; pHDR->m_checksum = static_cast(adler32((uint8*)pHDR + header::cChecksumSkipBytes, sizeof(header) - header::cChecksumSkipBytes)); return true; } bool lzma_codec::unpack(const void* p, uint n, crnlib::vector& buf) { buf.resize(0); if (n < sizeof(header)) return false; const header& hdr = *static_cast(p); if (hdr.m_sig != header::cSig) return false; if (static_cast(adler32((const uint8*)&hdr + header::cChecksumSkipBytes, sizeof(hdr) - header::cChecksumSkipBytes)) != hdr.m_checksum) return false; if (!hdr.m_uncomp_size) return true; if (!hdr.m_comp_size) return false; if (hdr.m_uncomp_size > 1024U*1024U*1024U) return false; if (!buf.try_resize(hdr.m_uncomp_size)) return false; const uint8* pComp_data = static_cast(p) + sizeof(header); size_t srcLen = n - sizeof(header); if (srcLen < hdr.m_comp_size) return false; size_t destLen = hdr.m_uncomp_size; int status = (*m_pUncompress)(&buf[0], &destLen, pComp_data, &srcLen, hdr.m_lzma_props, cLZMAPropsSize); if ((status != SZ_OK) || (destLen != hdr.m_uncomp_size)) { buf.clear(); return false; } if (adler32(&buf[0], buf.size()) != hdr.m_adler32) { buf.clear(); return false; } return true; } } // namespace crnlib