Upload 2.0.2
[physicsfs] / lzma / CPP / 7zip / Compress / LZMA_Alone / LzmaRam.cpp
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 }