Imported Upstream version 9.20
[platform/upstream/7zip.git] / CPP / 7zip / Archive / Common / MultiStream.cpp
1 // MultiStream.cpp\r
2 \r
3 #include "StdAfx.h"\r
4 \r
5 #include "MultiStream.h"\r
6 \r
7 STDMETHODIMP CMultiStream::Read(void *data, UInt32 size, UInt32 *processedSize)\r
8 {\r
9   if (processedSize)\r
10     *processedSize = 0;\r
11   if (size == 0)\r
12     return S_OK;\r
13   if (_pos >= _totalLength)\r
14     return (_pos == _totalLength) ? S_OK : E_FAIL;\r
15 \r
16   {\r
17     int left = 0, mid = _streamIndex, right = Streams.Size();\r
18     for (;;)\r
19     {\r
20       CSubStreamInfo &m = Streams[mid];\r
21       if (_pos < m.GlobalOffset)\r
22         right = mid;\r
23       else if (_pos >= m.GlobalOffset + m.Size)\r
24         left = mid + 1;\r
25       else\r
26       {\r
27         _streamIndex = mid;\r
28         break;\r
29       }\r
30       mid = (left + right) / 2;\r
31     }\r
32     _streamIndex = mid;\r
33   }\r
34   \r
35   CSubStreamInfo &s = Streams[_streamIndex];\r
36   UInt64 localPos = _pos - s.GlobalOffset;\r
37   if (localPos != s.LocalPos)\r
38   {\r
39     RINOK(s.Stream->Seek(localPos, STREAM_SEEK_SET, &s.LocalPos));\r
40   }\r
41   UInt64 rem = s.Size - localPos;\r
42   if (size > rem)\r
43     size = (UInt32)rem;\r
44   HRESULT result = s.Stream->Read(data, size, &size);\r
45   _pos += size;\r
46   s.LocalPos += size;\r
47   if (processedSize)\r
48     *processedSize = size;\r
49   return result;\r
50 }\r
51   \r
52 STDMETHODIMP CMultiStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)\r
53 {\r
54   switch(seekOrigin)\r
55   {\r
56     case STREAM_SEEK_SET: _pos = offset; break;\r
57     case STREAM_SEEK_CUR: _pos = _pos + offset; break;\r
58     case STREAM_SEEK_END: _pos = _totalLength + offset; break;\r
59     default: return STG_E_INVALIDFUNCTION;\r
60   }\r
61   if (newPosition != 0)\r
62     *newPosition = _pos;\r
63   return S_OK;\r
64 }\r
65 \r
66 \r
67 /*\r
68 class COutVolumeStream:\r
69   public ISequentialOutStream,\r
70   public CMyUnknownImp\r
71 {\r
72   int _volIndex;\r
73   UInt64 _volSize;\r
74   UInt64 _curPos;\r
75   CMyComPtr<ISequentialOutStream> _volumeStream;\r
76   COutArchive _archive;\r
77   CCRC _crc;\r
78 \r
79 public:\r
80   MY_UNKNOWN_IMP\r
81 \r
82   CFileItem _file;\r
83   CUpdateOptions _options;\r
84   CMyComPtr<IArchiveUpdateCallback2> VolumeCallback;\r
85   void Init(IArchiveUpdateCallback2 *volumeCallback,\r
86       const UString &name)\r
87   {\r
88     _file.Name = name;\r
89     _file.IsStartPosDefined = true;\r
90     _file.StartPos = 0;\r
91     \r
92     VolumeCallback = volumeCallback;\r
93     _volIndex = 0;\r
94     _volSize = 0;\r
95   }\r
96   \r
97   HRESULT Flush();\r
98   STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);\r
99 };\r
100 \r
101 HRESULT COutVolumeStream::Flush()\r
102 {\r
103   if (_volumeStream)\r
104   {\r
105     _file.UnPackSize = _curPos;\r
106     _file.FileCRC = _crc.GetDigest();\r
107     RINOK(WriteVolumeHeader(_archive, _file, _options));\r
108     _archive.Close();\r
109     _volumeStream.Release();\r
110     _file.StartPos += _file.UnPackSize;\r
111   }\r
112   return S_OK;\r
113 }\r
114 */\r
115 \r
116 /*\r
117 STDMETHODIMP COutMultiStream::Write(const void *data, UInt32 size, UInt32 *processedSize)\r
118 {\r
119   if(processedSize != NULL)\r
120     *processedSize = 0;\r
121   while(size > 0)\r
122   {\r
123     if (_streamIndex >= Streams.Size())\r
124     {\r
125       CSubStreamInfo subStream;\r
126       RINOK(VolumeCallback->GetVolumeSize(Streams.Size(), &subStream.Size));\r
127       RINOK(VolumeCallback->GetVolumeStream(Streams.Size(), &subStream.Stream));\r
128       subStream.Pos = 0;\r
129       Streams.Add(subStream);\r
130       continue;\r
131     }\r
132     CSubStreamInfo &subStream = Streams[_streamIndex];\r
133     if (_offsetPos >= subStream.Size)\r
134     {\r
135       _offsetPos -= subStream.Size;\r
136       _streamIndex++;\r
137       continue;\r
138     }\r
139     if (_offsetPos != subStream.Pos)\r
140     {\r
141       CMyComPtr<IOutStream> outStream;\r
142       RINOK(subStream.Stream.QueryInterface(IID_IOutStream, &outStream));\r
143       RINOK(outStream->Seek(_offsetPos, STREAM_SEEK_SET, NULL));\r
144       subStream.Pos = _offsetPos;\r
145     }\r
146 \r
147     UInt32 curSize = (UInt32)MyMin((UInt64)size, subStream.Size - subStream.Pos);\r
148     UInt32 realProcessed;\r
149     RINOK(subStream.Stream->Write(data, curSize, &realProcessed));\r
150     data = (void *)((Byte *)data + realProcessed);\r
151     size -= realProcessed;\r
152     subStream.Pos += realProcessed;\r
153     _offsetPos += realProcessed;\r
154     _absPos += realProcessed;\r
155     if (_absPos > _length)\r
156       _length = _absPos;\r
157     if(processedSize != NULL)\r
158       *processedSize += realProcessed;\r
159     if (subStream.Pos == subStream.Size)\r
160     {\r
161       _streamIndex++;\r
162       _offsetPos = 0;\r
163     }\r
164     if (realProcessed != curSize && realProcessed == 0)\r
165       return E_FAIL;\r
166   }\r
167   return S_OK;\r
168 }\r
169 \r
170 STDMETHODIMP COutMultiStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)\r
171 {\r
172   if(seekOrigin >= 3)\r
173     return STG_E_INVALIDFUNCTION;\r
174   switch(seekOrigin)\r
175   {\r
176     case STREAM_SEEK_SET:\r
177       _absPos = offset;\r
178       break;\r
179     case STREAM_SEEK_CUR:\r
180       _absPos += offset;\r
181       break;\r
182     case STREAM_SEEK_END:\r
183       _absPos = _length + offset;\r
184       break;\r
185   }\r
186   _offsetPos = _absPos;\r
187   _streamIndex = 0;\r
188   return S_OK;\r
189 }\r
190 */\r