1// CoderMixer2.h
2
3#ifndef ZIP7_INC_CODER_MIXER2_H
4#define ZIP7_INC_CODER_MIXER2_H
5
6#include "../../../Common/MyCom.h"
7#include "../../../Common/MyVector.h"
8
9#include "../../ICoder.h"
10
11#include "../../Common/CreateCoder.h"
12
13#ifdef Z7_ST
14  #define USE_MIXER_ST
15#else
16  #define USE_MIXER_MT
17  #ifndef Z7_SFX
18    #define USE_MIXER_ST
19  #endif
20#endif
21
22#ifdef USE_MIXER_MT
23#include "../../Common/StreamBinder.h"
24#include "../../Common/VirtThread.h"
25#endif
26
27
28
29#ifdef USE_MIXER_ST
30
31Z7_CLASS_IMP_COM_1(
32  CSequentialInStreamCalcSize
33  , ISequentialInStream
34)
35  bool _wasFinished;
36  CMyComPtr<ISequentialInStream> _stream;
37  UInt64 _size;
38public:
39  void SetStream(ISequentialInStream *stream) { _stream = stream;  }
40  void Init()
41  {
42    _size = 0;
43    _wasFinished = false;
44  }
45  void ReleaseStream() { _stream.Release(); }
46  UInt64 GetSize() const { return _size; }
47  bool WasFinished() const { return _wasFinished; }
48};
49
50
51Z7_CLASS_IMP_COM_2(
52  COutStreamCalcSize
53  , ISequentialOutStream
54  , IOutStreamFinish
55)
56  CMyComPtr<ISequentialOutStream> _stream;
57  UInt64 _size;
58public:
59  void SetStream(ISequentialOutStream *stream) { _stream = stream; }
60  void ReleaseStream() { _stream.Release(); }
61  void Init() { _size = 0; }
62  UInt64 GetSize() const { return _size; }
63};
64
65#endif
66
67
68
69namespace NCoderMixer2 {
70
71struct CBond
72{
73  UInt32 PackIndex;
74  UInt32 UnpackIndex;
75
76  UInt32 Get_InIndex(bool encodeMode) const { return encodeMode ? UnpackIndex : PackIndex; }
77  UInt32 Get_OutIndex(bool encodeMode) const { return encodeMode ? PackIndex : UnpackIndex; }
78};
79
80
81struct CCoderStreamsInfo
82{
83  UInt32 NumStreams;
84};
85
86
87struct CBindInfo
88{
89  CRecordVector<CCoderStreamsInfo> Coders;
90  CRecordVector<CBond> Bonds;
91  CRecordVector<UInt32> PackStreams;
92  unsigned UnpackCoder;
93
94  unsigned GetNum_Bonds_and_PackStreams() const { return Bonds.Size() + PackStreams.Size(); }
95
96  int FindBond_for_PackStream(UInt32 packStream) const
97  {
98    FOR_VECTOR (i, Bonds)
99      if (Bonds[i].PackIndex == packStream)
100        return (int)i;
101    return -1;
102  }
103
104  int FindBond_for_UnpackStream(UInt32 unpackStream) const
105  {
106    FOR_VECTOR (i, Bonds)
107      if (Bonds[i].UnpackIndex == unpackStream)
108        return (int)i;
109    return -1;
110  }
111
112  bool SetUnpackCoder()
113  {
114    bool isOk = false;
115    FOR_VECTOR (i, Coders)
116    {
117      if (FindBond_for_UnpackStream(i) < 0)
118      {
119        if (isOk)
120          return false;
121        UnpackCoder = i;
122        isOk = true;
123      }
124    }
125    return isOk;
126  }
127
128  bool IsStream_in_PackStreams(UInt32 streamIndex) const
129  {
130    return FindStream_in_PackStreams(streamIndex) >= 0;
131  }
132
133  int FindStream_in_PackStreams(UInt32 streamIndex) const
134  {
135    FOR_VECTOR (i, PackStreams)
136      if (PackStreams[i] == streamIndex)
137        return (int)i;
138    return -1;
139  }
140
141
142  // that function is used before Maps is calculated
143
144  UInt32 GetStream_for_Coder(UInt32 coderIndex) const
145  {
146    UInt32 streamIndex = 0;
147    for (UInt32 i = 0; i < coderIndex; i++)
148      streamIndex += Coders[i].NumStreams;
149    return streamIndex;
150  }
151
152  // ---------- Maps Section ----------
153
154  CRecordVector<UInt32> Coder_to_Stream;
155  CRecordVector<UInt32> Stream_to_Coder;
156
157  void ClearMaps();
158  bool CalcMapsAndCheck();
159
160  // ---------- End of Maps Section ----------
161
162  void Clear()
163  {
164    Coders.Clear();
165    Bonds.Clear();
166    PackStreams.Clear();
167
168    ClearMaps();
169  }
170
171  void GetCoder_for_Stream(UInt32 streamIndex, UInt32 &coderIndex, UInt32 &coderStreamIndex) const
172  {
173    coderIndex = Stream_to_Coder[streamIndex];
174    coderStreamIndex = streamIndex - Coder_to_Stream[coderIndex];
175  }
176};
177
178
179
180class CCoder
181{
182  Z7_CLASS_NO_COPY(CCoder)
183public:
184  CMyComPtr<ICompressCoder> Coder;
185  CMyComPtr<ICompressCoder2> Coder2;
186  UInt32 NumStreams;
187  bool Finish;
188
189  UInt64 UnpackSize;
190  const UInt64 *UnpackSizePointer;
191
192  CRecordVector<UInt64> PackSizes;
193  CRecordVector<const UInt64 *> PackSizePointers;
194
195  CCoder(): Finish(false) {}
196
197  void SetCoderInfo(const UInt64 *unpackSize, const UInt64 * const *packSizes, bool finish);
198
199  HRESULT CheckDataAfterEnd(bool &dataAfterEnd_Error /* , bool &InternalPackSizeError */) const;
200
201  IUnknown *GetUnknown() const
202  {
203    return Coder ? (IUnknown *)Coder : (IUnknown *)Coder2;
204  }
205
206  HRESULT QueryInterface(REFGUID iid, void** pp) const
207  {
208    return GetUnknown()->QueryInterface(iid, pp);
209  }
210};
211
212
213
214class CMixer
215{
216  bool Is_PackSize_Correct_for_Stream(UInt32 streamIndex);
217
218protected:
219  CBindInfo _bi;
220
221  int FindBond_for_Stream(bool forInputStream, UInt32 streamIndex) const
222  {
223    if (EncodeMode == forInputStream)
224      return _bi.FindBond_for_UnpackStream(streamIndex);
225    else
226      return _bi.FindBond_for_PackStream(streamIndex);
227  }
228
229  CBoolVector IsFilter_Vector;
230  CBoolVector IsExternal_Vector;
231  bool EncodeMode;
232public:
233  unsigned MainCoderIndex;
234
235  // bool InternalPackSizeError;
236
237  CMixer(bool encodeMode):
238      EncodeMode(encodeMode),
239      MainCoderIndex(0)
240      // , InternalPackSizeError(false)
241      {}
242
243  virtual ~CMixer() {}
244  /*
245  Sequence of calling:
246
247      SetBindInfo();
248      for each coder
249        AddCoder();
250      SelectMainCoder();
251
252      for each file
253      {
254        ReInit()
255        for each coder
256          SetCoderInfo();
257        Code();
258      }
259  */
260
261  virtual HRESULT SetBindInfo(const CBindInfo &bindInfo)
262  {
263    _bi = bindInfo;
264    IsFilter_Vector.Clear();
265    MainCoderIndex = 0;
266    return S_OK;
267  }
268
269  virtual void AddCoder(const CCreatedCoder &cod) = 0;
270  virtual CCoder &GetCoder(unsigned index) = 0;
271  virtual void SelectMainCoder(bool useFirst) = 0;
272  virtual HRESULT ReInit2() = 0;
273  virtual void SetCoderInfo(unsigned coderIndex, const UInt64 *unpackSize, const UInt64 * const *packSizes, bool finish) = 0;
274  virtual HRESULT Code(
275      ISequentialInStream * const *inStreams,
276      ISequentialOutStream * const *outStreams,
277      ICompressProgressInfo *progress,
278      bool &dataAfterEnd_Error) = 0;
279  virtual UInt64 GetBondStreamSize(unsigned bondIndex) const = 0;
280
281  bool Is_UnpackSize_Correct_for_Coder(UInt32 coderIndex);
282  bool Is_PackSize_Correct_for_Coder(UInt32 coderIndex);
283  bool IsThere_ExternalCoder_in_PackTree(UInt32 coderIndex);
284};
285
286
287
288
289#ifdef USE_MIXER_ST
290
291struct CCoderST: public CCoder
292{
293  bool CanRead;
294  bool CanWrite;
295
296  CCoderST(): CanRead(false), CanWrite(false) {}
297};
298
299
300struct CStBinderStream
301{
302  CSequentialInStreamCalcSize *InStreamSpec;
303  COutStreamCalcSize *OutStreamSpec;
304  CMyComPtr<IUnknown> StreamRef;
305
306  CStBinderStream(): InStreamSpec(NULL), OutStreamSpec(NULL) {}
307};
308
309
310class CMixerST:
311  public IUnknown,
312  public CMixer,
313  public CMyUnknownImp
314{
315  Z7_COM_UNKNOWN_IMP_0
316  Z7_CLASS_NO_COPY(CMixerST)
317
318  HRESULT GetInStream2(ISequentialInStream * const *inStreams, /* const UInt64 * const *inSizes, */
319      UInt32 outStreamIndex, ISequentialInStream **inStreamRes);
320  HRESULT GetInStream(ISequentialInStream * const *inStreams, /* const UInt64 * const *inSizes, */
321      UInt32 inStreamIndex, ISequentialInStream **inStreamRes);
322  HRESULT GetOutStream(ISequentialOutStream * const *outStreams, /* const UInt64 * const *outSizes, */
323      UInt32 outStreamIndex, ISequentialOutStream **outStreamRes);
324
325  HRESULT FinishStream(UInt32 streamIndex);
326  HRESULT FinishCoder(UInt32 coderIndex);
327
328public:
329  CObjectVector<CCoderST> _coders;
330
331  CObjectVector<CStBinderStream> _binderStreams;
332
333  CMixerST(bool encodeMode);
334  ~CMixerST() Z7_DESTRUCTOR_override;
335
336  virtual void AddCoder(const CCreatedCoder &cod) Z7_override;
337  virtual CCoder &GetCoder(unsigned index) Z7_override;
338  virtual void SelectMainCoder(bool useFirst) Z7_override;
339  virtual HRESULT ReInit2() Z7_override;
340  virtual void SetCoderInfo(unsigned coderIndex, const UInt64 *unpackSize, const UInt64 * const *packSizes, bool finish) Z7_override
341    { _coders[coderIndex].SetCoderInfo(unpackSize, packSizes, finish); }
342  virtual HRESULT Code(
343      ISequentialInStream * const *inStreams,
344      ISequentialOutStream * const *outStreams,
345      ICompressProgressInfo *progress,
346      bool &dataAfterEnd_Error) Z7_override;
347  virtual UInt64 GetBondStreamSize(unsigned bondIndex) const Z7_override;
348
349  HRESULT GetMainUnpackStream(
350      ISequentialInStream * const *inStreams,
351      ISequentialInStream **inStreamRes);
352};
353
354#endif
355
356
357
358
359#ifdef USE_MIXER_MT
360
361class CCoderMT: public CCoder, public CVirtThread
362{
363  Z7_CLASS_NO_COPY(CCoderMT)
364  CRecordVector<ISequentialInStream*> InStreamPointers;
365  CRecordVector<ISequentialOutStream*> OutStreamPointers;
366
367private:
368  virtual void Execute() Z7_override;
369public:
370  bool EncodeMode;
371  HRESULT Result;
372  CObjectVector< CMyComPtr<ISequentialInStream> > InStreams;
373  CObjectVector< CMyComPtr<ISequentialOutStream> > OutStreams;
374
375  void Release()
376  {
377    InStreamPointers.Clear();
378    OutStreamPointers.Clear();
379    unsigned i;
380    for (i = 0; i < InStreams.Size(); i++)
381      InStreams[i].Release();
382    for (i = 0; i < OutStreams.Size(); i++)
383      OutStreams[i].Release();
384  }
385
386  class CReleaser
387  {
388    Z7_CLASS_NO_COPY(CReleaser)
389    CCoderMT &_c;
390  public:
391    CReleaser(CCoderMT &c): _c(c) {}
392    ~CReleaser() { _c.Release(); }
393  };
394
395  CCoderMT(): EncodeMode(false) {}
396  ~CCoderMT() Z7_DESTRUCTOR_override
397  {
398    /* WaitThreadFinish() will be called in ~CVirtThread().
399       But we need WaitThreadFinish() call before CCoder destructor,
400       and before destructors of this class members.
401    */
402    CVirtThread::WaitThreadFinish();
403  }
404
405  void Code(ICompressProgressInfo *progress);
406};
407
408
409class CMixerMT:
410  public IUnknown,
411  public CMixer,
412  public CMyUnknownImp
413{
414  Z7_COM_UNKNOWN_IMP_0
415  Z7_CLASS_NO_COPY(CMixerMT)
416
417  CObjectVector<CStreamBinder> _streamBinders;
418
419  HRESULT Init(ISequentialInStream * const *inStreams, ISequentialOutStream * const *outStreams);
420  HRESULT ReturnIfError(HRESULT code);
421
422  // virtual ~CMixerMT() {}
423public:
424  CObjectVector<CCoderMT> _coders;
425
426  virtual HRESULT SetBindInfo(const CBindInfo &bindInfo) Z7_override;
427  virtual void AddCoder(const CCreatedCoder &cod) Z7_override;
428  virtual CCoder &GetCoder(unsigned index) Z7_override;
429  virtual void SelectMainCoder(bool useFirst) Z7_override;
430  virtual HRESULT ReInit2() Z7_override;
431  virtual void SetCoderInfo(unsigned coderIndex, const UInt64 *unpackSize, const UInt64 * const *packSizes, bool finish) Z7_override
432    { _coders[coderIndex].SetCoderInfo(unpackSize, packSizes, finish); }
433  virtual HRESULT Code(
434      ISequentialInStream * const *inStreams,
435      ISequentialOutStream * const *outStreams,
436      ICompressProgressInfo *progress,
437      bool &dataAfterEnd_Error) Z7_override;
438  virtual UInt64 GetBondStreamSize(unsigned bondIndex) const Z7_override;
439
440  CMixerMT(bool encodeMode): CMixer(encodeMode) {}
441};
442
443#endif
444
445}
446
447#endif
448