// XzEncoder.cpp #include "StdAfx.h" #include "../../../C/Alloc.h" #include "../../Common/MyString.h" #include "../../Common/StringToInt.h" #include "../Common/CWrappers.h" #include "../Common/StreamUtils.h" #include "XzEncoder.h" namespace NCompress { namespace NLzma2 { HRESULT SetLzma2Prop(PROPID propID, const PROPVARIANT &prop, CLzma2EncProps &lzma2Props); } namespace NXz { void CEncoder::InitCoderProps() { XzProps_Init(&xzProps); } CEncoder::CEncoder() { XzProps_Init(&xzProps); _encoder = NULL; _encoder = XzEnc_Create(&g_Alloc, &g_BigAlloc); if (!_encoder) throw 1; } CEncoder::~CEncoder() { if (_encoder) XzEnc_Destroy(_encoder); } struct CMethodNamePair { UInt32 Id; const char *Name; }; static const CMethodNamePair g_NamePairs[] = { { XZ_ID_Delta, "Delta" }, { XZ_ID_X86, "BCJ" }, { XZ_ID_PPC, "PPC" }, { XZ_ID_IA64, "IA64" }, { XZ_ID_ARM, "ARM" }, { XZ_ID_ARMT, "ARMT" }, { XZ_ID_SPARC, "SPARC" } // { XZ_ID_LZMA2, "LZMA2" } }; static int FilterIdFromName(const wchar_t *name) { for (unsigned i = 0; i < ARRAY_SIZE(g_NamePairs); i++) { const CMethodNamePair &pair = g_NamePairs[i]; if (StringsAreEqualNoCase_Ascii(name, pair.Name)) return (int)pair.Id; } return -1; } HRESULT CEncoder::SetCheckSize(UInt32 checkSizeInBytes) { unsigned id; switch (checkSizeInBytes) { case 0: id = XZ_CHECK_NO; break; case 4: id = XZ_CHECK_CRC32; break; case 8: id = XZ_CHECK_CRC64; break; case 32: id = XZ_CHECK_SHA256; break; default: return E_INVALIDARG; } xzProps.checkId = id; return S_OK; } HRESULT CEncoder::SetCoderProp(PROPID propID, const PROPVARIANT &prop) { if (propID == NCoderPropID::kNumThreads) { if (prop.vt != VT_UI4) return E_INVALIDARG; xzProps.numTotalThreads = (int)(prop.ulVal); return S_OK; } if (propID == NCoderPropID::kCheckSize) { if (prop.vt != VT_UI4) return E_INVALIDARG; return SetCheckSize(prop.ulVal); } if (propID == NCoderPropID::kBlockSize2) { if (prop.vt == VT_UI4) xzProps.blockSize = prop.ulVal; else if (prop.vt == VT_UI8) xzProps.blockSize = prop.uhVal.QuadPart; else return E_INVALIDARG; return S_OK; } if (propID == NCoderPropID::kReduceSize) { if (prop.vt == VT_UI8) xzProps.reduceSize = prop.uhVal.QuadPart; else return E_INVALIDARG; return S_OK; } if (propID == NCoderPropID::kFilter) { if (prop.vt == VT_UI4) { UInt32 id32 = prop.ulVal; if (id32 == XZ_ID_Delta) return E_INVALIDARG; xzProps.filterProps.id = prop.ulVal; } else { if (prop.vt != VT_BSTR) return E_INVALIDARG; const wchar_t *name = prop.bstrVal; const wchar_t *end; UInt32 id32 = ConvertStringToUInt32(name, &end); if (end != name) name = end; else { if (IsString1PrefixedByString2_NoCase_Ascii(name, "Delta")) { name += 5; // strlen("Delta"); id32 = XZ_ID_Delta; } else { int filterId = FilterIdFromName(prop.bstrVal); if (filterId < 0 /* || filterId == XZ_ID_LZMA2 */) return E_INVALIDARG; id32 = filterId; } } if (id32 == XZ_ID_Delta) { wchar_t c = *name; if (c != '-' && c != ':') return E_INVALIDARG; name++; UInt32 delta = ConvertStringToUInt32(name, &end); if (end == name || *end != 0 || delta == 0 || delta > 256) return E_INVALIDARG; xzProps.filterProps.delta = delta; } xzProps.filterProps.id = id32; } return S_OK; } return NLzma2::SetLzma2Prop(propID, prop, xzProps.lzma2Props); } STDMETHODIMP CEncoder::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *coderProps, UInt32 numProps) { XzProps_Init(&xzProps); for (UInt32 i = 0; i < numProps; i++) { RINOK(SetCoderProp(propIDs[i], coderProps[i])); } return S_OK; // return SResToHRESULT(XzEnc_SetProps(_encoder, &xzProps)); } STDMETHODIMP CEncoder::SetCoderPropertiesOpt(const PROPID *propIDs, const PROPVARIANT *coderProps, UInt32 numProps) { for (UInt32 i = 0; i < numProps; i++) { const PROPVARIANT &prop = coderProps[i]; PROPID propID = propIDs[i]; if (propID == NCoderPropID::kExpectedDataSize) if (prop.vt == VT_UI8) XzEnc_SetDataSize(_encoder, prop.uhVal.QuadPart); } return S_OK; } #define RET_IF_WRAP_ERROR(wrapRes, sRes, sResErrorCode) \ if (wrapRes != S_OK /* && (sRes == SZ_OK || sRes == sResErrorCode) */) return wrapRes; STDMETHODIMP CEncoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, const UInt64 * /* inSize */, const UInt64 * /* outSize */, ICompressProgressInfo *progress) { CSeqInStreamWrap inWrap; CSeqOutStreamWrap outWrap; CCompressProgressWrap progressWrap; inWrap.Init(inStream); outWrap.Init(outStream); progressWrap.Init(progress); SRes res = XzEnc_SetProps(_encoder, &xzProps); if (res == SZ_OK) res = XzEnc_Encode(_encoder, &outWrap.vt, &inWrap.vt, progress ? &progressWrap.vt : NULL); // SRes res = Xz_Encode(&outWrap.vt, &inWrap.vt, &xzProps, progress ? &progressWrap.vt : NULL); RET_IF_WRAP_ERROR(inWrap.Res, res, SZ_ERROR_READ) RET_IF_WRAP_ERROR(outWrap.Res, res, SZ_ERROR_WRITE) RET_IF_WRAP_ERROR(progressWrap.Res, res, SZ_ERROR_PROGRESS) return SResToHRESULT(res); } }}