1// LzmaRam.cpp 2 3#include "StdAfx.h" 4#include "../../../Common/Types.h" 5#include "../LZMA/LZMADecoder.h" 6#include "../LZMA/LZMAEncoder.h" 7#include "LzmaRam.h" 8 9extern "C" 10{ 11 #include "../../../../C/Compress/Branch/BranchX86.h" 12} 13 14class CInStreamRam: 15 public ISequentialInStream, 16 public CMyUnknownImp 17{ 18 const Byte *Data; 19 size_t Size; 20 size_t Pos; 21public: 22 MY_UNKNOWN_IMP 23 void Init(const Byte *data, size_t size) 24 { 25 Data = data; 26 Size = size; 27 Pos = 0; 28 } 29 STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); 30}; 31 32STDMETHODIMP CInStreamRam::Read(void *data, UInt32 size, UInt32 *processedSize) 33{ 34 if (size > (Size - Pos)) 35 size = (UInt32)(Size - Pos); 36 for (UInt32 i = 0; i < size; i++) 37 ((Byte *)data)[i] = Data[Pos + i]; 38 Pos += size; 39 if(processedSize != NULL) 40 *processedSize = size; 41 return S_OK; 42} 43 44class COutStreamRam: 45 public ISequentialOutStream, 46 public CMyUnknownImp 47{ 48 size_t Size; 49public: 50 Byte *Data; 51 size_t Pos; 52 bool Overflow; 53 void Init(Byte *data, size_t size) 54 { 55 Data = data; 56 Size = size; 57 Pos = 0; 58 Overflow = false; 59 } 60 void SetPos(size_t pos) 61 { 62 Overflow = false; 63 Pos = pos; 64 } 65 MY_UNKNOWN_IMP 66 HRESULT WriteByte(Byte b) 67 { 68 if (Pos >= Size) 69 { 70 Overflow = true; 71 return E_FAIL; 72 } 73 Data[Pos++] = b; 74 return S_OK; 75 } 76 STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize); 77}; 78 79STDMETHODIMP COutStreamRam::Write(const void *data, UInt32 size, UInt32 *processedSize) 80{ 81 UInt32 i; 82 for (i = 0; i < size && Pos < Size; i++) 83 Data[Pos++] = ((const Byte *)data)[i]; 84 if(processedSize != NULL) 85 *processedSize = i; 86 if (i != size) 87 { 88 Overflow = true; 89 return E_FAIL; 90 } 91 return S_OK; 92} 93 94#define SZ_RAM_E_FAIL (1) 95#define SZ_RAM_E_OUTOFMEMORY (2) 96#define SZE_OUT_OVERFLOW (3) 97 98int LzmaRamEncode( 99 const Byte *inBuffer, size_t inSize, 100 Byte *outBuffer, size_t outSize, size_t *outSizeProcessed, 101 UInt32 dictionarySize, ESzFilterMode filterMode) 102{ 103 #ifndef _NO_EXCEPTIONS 104 try { 105 #endif 106 107 *outSizeProcessed = 0; 108 const size_t kIdSize = 1; 109 const size_t kLzmaPropsSize = 5; 110 const size_t kMinDestSize = kIdSize + kLzmaPropsSize + 8; 111 if (outSize < kMinDestSize) 112 return SZE_OUT_OVERFLOW; 113 NCompress::NLZMA::CEncoder *encoderSpec = new NCompress::NLZMA::CEncoder; 114 CMyComPtr<ICompressCoder> encoder = encoderSpec; 115 116 PROPID propIDs[] = 117 { 118 NCoderPropID::kAlgorithm, 119 NCoderPropID::kDictionarySize, 120 NCoderPropID::kNumFastBytes, 121 }; 122 const int kNumProps = sizeof(propIDs) / sizeof(propIDs[0]); 123 PROPVARIANT properties[kNumProps]; 124 properties[0].vt = VT_UI4; 125 properties[1].vt = VT_UI4; 126 properties[2].vt = VT_UI4; 127 properties[0].ulVal = (UInt32)2; 128 properties[1].ulVal = (UInt32)dictionarySize; 129 properties[2].ulVal = (UInt32)64; 130 131 if (encoderSpec->SetCoderProperties(propIDs, properties, kNumProps) != S_OK) 132 return 1; 133 134 COutStreamRam *outStreamSpec = new COutStreamRam; 135 if (outStreamSpec == 0) 136 return SZ_RAM_E_OUTOFMEMORY; 137 CMyComPtr<ISequentialOutStream> outStream = outStreamSpec; 138 CInStreamRam *inStreamSpec = new CInStreamRam; 139 if (inStreamSpec == 0) 140 return SZ_RAM_E_OUTOFMEMORY; 141 CMyComPtr<ISequentialInStream> inStream = inStreamSpec; 142 143 outStreamSpec->Init(outBuffer, outSize); 144 if (outStreamSpec->WriteByte(0) != S_OK) 145 return SZE_OUT_OVERFLOW; 146 147 if (encoderSpec->WriteCoderProperties(outStream) != S_OK) 148 return SZE_OUT_OVERFLOW; 149 if (outStreamSpec->Pos != kIdSize + kLzmaPropsSize) 150 return 1; 151 152 int i; 153 for (i = 0; i < 8; i++) 154 { 155 UInt64 t = (UInt64)(inSize); 156 if (outStreamSpec->WriteByte((Byte)((t) >> (8 * i))) != S_OK) 157 return SZE_OUT_OVERFLOW; 158 } 159 160 Byte *filteredStream = 0; 161 162 bool useFilter = (filterMode != SZ_FILTER_NO); 163 if (useFilter) 164 { 165 if (inSize != 0) 166 { 167 filteredStream = (Byte *)MyAlloc(inSize); 168 if (filteredStream == 0) 169 return SZ_RAM_E_OUTOFMEMORY; 170 memmove(filteredStream, inBuffer, inSize); 171 } 172 UInt32 x86State; 173 x86_Convert_Init(x86State); 174 x86_Convert(filteredStream, (SizeT)inSize, 0, &x86State, 1); 175 } 176 177 size_t minSize = 0; 178 int numPasses = (filterMode == SZ_FILTER_AUTO) ? 3 : 1; 179 bool bestIsFiltered = false; 180 int mainResult = 0; 181 size_t startPos = outStreamSpec->Pos; 182 for (i = 0; i < numPasses; i++) 183 { 184 if (numPasses > 1 && i == numPasses - 1 && !bestIsFiltered) 185 break; 186 outStreamSpec->SetPos(startPos); 187 bool curModeIsFiltered = false; 188 if (useFilter && i == 0) 189 curModeIsFiltered = true; 190 if (numPasses > 1 && i == numPasses - 1) 191 curModeIsFiltered = true; 192 193 inStreamSpec->Init(curModeIsFiltered ? filteredStream : inBuffer, inSize); 194 195 HRESULT lzmaResult = encoder->Code(inStream, outStream, 0, 0, 0); 196 197 mainResult = 0; 198 if (lzmaResult == E_OUTOFMEMORY) 199 { 200 mainResult = SZ_RAM_E_OUTOFMEMORY; 201 break; 202 } 203 if (i == 0 || outStreamSpec->Pos <= minSize) 204 { 205 minSize = outStreamSpec->Pos; 206 bestIsFiltered = curModeIsFiltered; 207 } 208 if (outStreamSpec->Overflow) 209 mainResult = SZE_OUT_OVERFLOW; 210 else if (lzmaResult != S_OK) 211 { 212 mainResult = SZ_RAM_E_FAIL; 213 break; 214 } 215 } 216 *outSizeProcessed = outStreamSpec->Pos; 217 if (bestIsFiltered) 218 outBuffer[0] = 1; 219 if (useFilter) 220 MyFree(filteredStream); 221 return mainResult; 222 223 #ifndef _NO_EXCEPTIONS 224 } catch(...) { return SZ_RAM_E_OUTOFMEMORY; } 225 #endif 226} 227