1370b324cSopenharmony_ci// MultiOutStream.h
2370b324cSopenharmony_ci
3370b324cSopenharmony_ci#ifndef ZIP7_INC_MULTI_OUT_STREAM_H
4370b324cSopenharmony_ci#define ZIP7_INC_MULTI_OUT_STREAM_H
5370b324cSopenharmony_ci
6370b324cSopenharmony_ci#include "FileStreams.h"
7370b324cSopenharmony_ci
8370b324cSopenharmony_ciZ7_CLASS_IMP_COM_2(
9370b324cSopenharmony_ci  CMultiOutStream
10370b324cSopenharmony_ci  , IOutStream
11370b324cSopenharmony_ci  , IStreamSetRestriction
12370b324cSopenharmony_ci)
13370b324cSopenharmony_ci  Z7_IFACE_COM7_IMP(ISequentialOutStream)
14370b324cSopenharmony_ci
15370b324cSopenharmony_ci  Z7_CLASS_NO_COPY(CMultiOutStream)
16370b324cSopenharmony_ci
17370b324cSopenharmony_ci  struct CVolStream
18370b324cSopenharmony_ci  {
19370b324cSopenharmony_ci    COutFileStream *StreamSpec;
20370b324cSopenharmony_ci    CMyComPtr<IOutStream> Stream;
21370b324cSopenharmony_ci    UInt64 Start;   // start pos of current Stream in global stream
22370b324cSopenharmony_ci    UInt64 Pos;     // pos in current Stream
23370b324cSopenharmony_ci    UInt64 RealSize;
24370b324cSopenharmony_ci    int Next;       // next older
25370b324cSopenharmony_ci    int Prev;       // prev newer
26370b324cSopenharmony_ci    AString Postfix;
27370b324cSopenharmony_ci
28370b324cSopenharmony_ci    HRESULT SetSize2(UInt64 size)
29370b324cSopenharmony_ci    {
30370b324cSopenharmony_ci      const HRESULT res = Stream->SetSize(size);
31370b324cSopenharmony_ci      if (res == SZ_OK)
32370b324cSopenharmony_ci        RealSize = size;
33370b324cSopenharmony_ci      return res;
34370b324cSopenharmony_ci    }
35370b324cSopenharmony_ci  };
36370b324cSopenharmony_ci
37370b324cSopenharmony_ci  unsigned _streamIndex; // (_streamIndex >= Stream.Size()) is allowed in some internal code
38370b324cSopenharmony_ci  UInt64 _offsetPos;     // offset relative to Streams[_streamIndex] volume. (_offsetPos >= volSize is allowed)
39370b324cSopenharmony_ci  UInt64 _absPos;
40370b324cSopenharmony_ci  UInt64 _length;        // virtual Length
41370b324cSopenharmony_ci  UInt64 _absLimit;
42370b324cSopenharmony_ci
43370b324cSopenharmony_ci  CObjectVector<CVolStream> Streams;
44370b324cSopenharmony_ci  CRecordVector<UInt64> Sizes;
45370b324cSopenharmony_ci
46370b324cSopenharmony_ci  UInt64 _restrict_Begin;
47370b324cSopenharmony_ci  UInt64 _restrict_End;
48370b324cSopenharmony_ci  UInt64 _restrict_Global;
49370b324cSopenharmony_ci
50370b324cSopenharmony_ci  unsigned NumOpenFiles_AllowedMax;
51370b324cSopenharmony_ci
52370b324cSopenharmony_ci  // ----- Double Linked List -----
53370b324cSopenharmony_ci
54370b324cSopenharmony_ci  unsigned NumListItems;
55370b324cSopenharmony_ci  int Head; // newest
56370b324cSopenharmony_ci  int Tail; // oldest
57370b324cSopenharmony_ci
58370b324cSopenharmony_ci  void InitLinkedList()
59370b324cSopenharmony_ci  {
60370b324cSopenharmony_ci    Head = -1;
61370b324cSopenharmony_ci    Tail = -1;
62370b324cSopenharmony_ci    NumListItems = 0;
63370b324cSopenharmony_ci  }
64370b324cSopenharmony_ci
65370b324cSopenharmony_ci  void InsertToLinkedList(unsigned index)
66370b324cSopenharmony_ci  {
67370b324cSopenharmony_ci    {
68370b324cSopenharmony_ci      CVolStream &node = Streams[index];
69370b324cSopenharmony_ci      node.Next = Head;
70370b324cSopenharmony_ci      node.Prev = -1;
71370b324cSopenharmony_ci    }
72370b324cSopenharmony_ci    if (Head != -1)
73370b324cSopenharmony_ci      Streams[(unsigned)Head].Prev = (int)index;
74370b324cSopenharmony_ci    else
75370b324cSopenharmony_ci    {
76370b324cSopenharmony_ci      // if (Tail != -1) throw 1;
77370b324cSopenharmony_ci      Tail = (int)index;
78370b324cSopenharmony_ci    }
79370b324cSopenharmony_ci    Head = (int)index;
80370b324cSopenharmony_ci    NumListItems++;
81370b324cSopenharmony_ci  }
82370b324cSopenharmony_ci
83370b324cSopenharmony_ci  void RemoveFromLinkedList(unsigned index)
84370b324cSopenharmony_ci  {
85370b324cSopenharmony_ci    CVolStream &s = Streams[index];
86370b324cSopenharmony_ci    if (s.Next != -1) Streams[(unsigned)s.Next].Prev = s.Prev; else Tail = s.Prev;
87370b324cSopenharmony_ci    if (s.Prev != -1) Streams[(unsigned)s.Prev].Next = s.Next; else Head = s.Next;
88370b324cSopenharmony_ci    s.Next = -1; // optional
89370b324cSopenharmony_ci    s.Prev = -1; // optional
90370b324cSopenharmony_ci    NumListItems--;
91370b324cSopenharmony_ci  }
92370b324cSopenharmony_ci
93370b324cSopenharmony_ci  /*
94370b324cSopenharmony_ci  void Delete_LastStream_Records()
95370b324cSopenharmony_ci  {
96370b324cSopenharmony_ci    if (Streams.Back().Stream)
97370b324cSopenharmony_ci      RemoveFromLinkedList(Streams.Size() - 1);
98370b324cSopenharmony_ci    Streams.DeleteBack();
99370b324cSopenharmony_ci  }
100370b324cSopenharmony_ci  */
101370b324cSopenharmony_ci
102370b324cSopenharmony_ci  UInt64 GetVolSize_for_Stream(unsigned i) const
103370b324cSopenharmony_ci  {
104370b324cSopenharmony_ci    const unsigned last = Sizes.Size() - 1;
105370b324cSopenharmony_ci    return Sizes[i < last ? i : last];
106370b324cSopenharmony_ci  }
107370b324cSopenharmony_ci  UInt64 GetGlobalOffset_for_NewStream() const
108370b324cSopenharmony_ci  {
109370b324cSopenharmony_ci    return Streams.Size() == 0 ? 0:
110370b324cSopenharmony_ci        Streams.Back().Start +
111370b324cSopenharmony_ci        GetVolSize_for_Stream(Streams.Size() - 1);
112370b324cSopenharmony_ci  }
113370b324cSopenharmony_ci  unsigned GetStreamIndex_for_Offset(UInt64 offset, UInt64 &relOffset) const;
114370b324cSopenharmony_ci  bool IsRestricted(const CVolStream &s) const;
115370b324cSopenharmony_ci  bool IsRestricted_Empty(const CVolStream &s) const
116370b324cSopenharmony_ci  {
117370b324cSopenharmony_ci    // (s) must be stream that has (VolSize == 0).
118370b324cSopenharmony_ci    // we treat empty stream as restricted, if next byte is restricted.
119370b324cSopenharmony_ci    if (s.Start < _restrict_Global)
120370b324cSopenharmony_ci      return true;
121370b324cSopenharmony_ci    return
122370b324cSopenharmony_ci         (_restrict_Begin != _restrict_End)
123370b324cSopenharmony_ci      && (_restrict_Begin <= s.Start)
124370b324cSopenharmony_ci      && (_restrict_Begin == s.Start || _restrict_End > s.Start);
125370b324cSopenharmony_ci  }
126370b324cSopenharmony_ci  // bool IsRestricted_for_Close(unsigned index) const;
127370b324cSopenharmony_ci  FString GetFilePath(unsigned index);
128370b324cSopenharmony_ci
129370b324cSopenharmony_ci  HRESULT CloseStream(unsigned index);
130370b324cSopenharmony_ci  HRESULT CloseStream_and_DeleteFile(unsigned index);
131370b324cSopenharmony_ci  HRESULT CloseStream_and_FinalRename(unsigned index);
132370b324cSopenharmony_ci
133370b324cSopenharmony_ci  HRESULT PrepareToOpenNew();
134370b324cSopenharmony_ci  HRESULT CreateNewStream(UInt64 newSize);
135370b324cSopenharmony_ci  HRESULT CreateStreams_If_Required(unsigned streamIndex);
136370b324cSopenharmony_ci  HRESULT ReOpenStream(unsigned streamIndex);
137370b324cSopenharmony_ci  HRESULT OptReOpen_and_SetSize(unsigned index, UInt64 size);
138370b324cSopenharmony_ci
139370b324cSopenharmony_ci  HRESULT Normalize_finalMode(bool finalMode);
140370b324cSopenharmony_cipublic:
141370b324cSopenharmony_ci  FString Prefix;
142370b324cSopenharmony_ci  CFiTime MTime;
143370b324cSopenharmony_ci  bool MTime_Defined;
144370b324cSopenharmony_ci  bool FinalVol_WasReopen;
145370b324cSopenharmony_ci  bool NeedDelete;
146370b324cSopenharmony_ci
147370b324cSopenharmony_ci  CMultiOutStream() {}
148370b324cSopenharmony_ci  ~CMultiOutStream();
149370b324cSopenharmony_ci  void Init(const CRecordVector<UInt64> &sizes);
150370b324cSopenharmony_ci  bool SetMTime_Final(const CFiTime &mTime);
151370b324cSopenharmony_ci  UInt64 GetSize() const { return _length; }
152370b324cSopenharmony_ci  /* it makes final flushing, closes open files and renames to final name if required
153370b324cSopenharmony_ci     but it still keeps Streams array of all closed files.
154370b324cSopenharmony_ci     So we still can delete all files later, if required */
155370b324cSopenharmony_ci  HRESULT FinalFlush_and_CloseFiles(unsigned &numTotalVolumesRes);
156370b324cSopenharmony_ci  // Destruct object without exceptions
157370b324cSopenharmony_ci  HRESULT Destruct();
158370b324cSopenharmony_ci};
159370b324cSopenharmony_ci
160370b324cSopenharmony_ci#endif
161