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 |
|
9 extern "C" |
|
10 { |
|
11 #include "../../../../C/Compress/Branch/BranchX86.h" |
|
12 } |
|
13 |
|
14 class CInStreamRam: |
|
15 public ISequentialInStream, |
|
16 public CMyUnknownImp |
|
17 { |
|
18 const Byte *Data; |
|
19 size_t Size; |
|
20 size_t Pos; |
|
21 public: |
|
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 |
|
32 STDMETHODIMP 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 |
|
44 class COutStreamRam: |
|
45 public ISequentialOutStream, |
|
46 public CMyUnknownImp |
|
47 { |
|
48 size_t Size; |
|
49 public: |
|
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 |
|
79 STDMETHODIMP 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 |
|
98 int 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 } |
|