Upload 2.0.2
[physicsfs] / lzma / CPP / 7zip / Archive / 7z / 7zFolderOutStream.cpp
1 // 7zFolderOutStream.cpp
2
3 #include "StdAfx.h"
4
5 #include "7zFolderOutStream.h"
6
7 namespace NArchive {
8 namespace N7z {
9
10 CFolderOutStream::CFolderOutStream()
11 {
12   _outStreamWithHashSpec = new COutStreamWithCRC;
13   _outStreamWithHash = _outStreamWithHashSpec;
14 }
15
16 HRESULT CFolderOutStream::Init(
17     const CArchiveDatabaseEx *archiveDatabase,
18     UInt32 ref2Offset,
19     UInt32 startIndex,
20     const CBoolVector *extractStatuses, 
21     IArchiveExtractCallback *extractCallback,
22     bool testMode,
23     bool checkCrc)
24 {
25   _archiveDatabase = archiveDatabase;
26   _ref2Offset = ref2Offset;
27   _startIndex = startIndex;
28
29   _extractStatuses = extractStatuses;
30   _extractCallback = extractCallback;
31   _testMode = testMode;
32
33   _checkCrc = checkCrc;
34
35   _currentIndex = 0;
36   _fileIsOpen = false;
37   return WriteEmptyFiles();
38 }
39
40 HRESULT CFolderOutStream::OpenFile()
41 {
42   Int32 askMode;
43   if((*_extractStatuses)[_currentIndex])
44     askMode = _testMode ? 
45         NArchive::NExtract::NAskMode::kTest :
46         NArchive::NExtract::NAskMode::kExtract;
47   else
48     askMode = NArchive::NExtract::NAskMode::kSkip;
49   CMyComPtr<ISequentialOutStream> realOutStream;
50
51   UInt32 index = _startIndex + _currentIndex;
52   RINOK(_extractCallback->GetStream(_ref2Offset + index, &realOutStream, askMode));
53
54   _outStreamWithHashSpec->SetStream(realOutStream);
55   _outStreamWithHashSpec->Init(_checkCrc);
56   if (askMode == NArchive::NExtract::NAskMode::kExtract &&
57       (!realOutStream)) 
58   {
59     const CFileItem &fileInfo = _archiveDatabase->Files[index];
60     if (!fileInfo.IsAnti && !fileInfo.IsDirectory)
61       askMode = NArchive::NExtract::NAskMode::kSkip;
62   }
63   return _extractCallback->PrepareOperation(askMode);
64 }
65
66 HRESULT CFolderOutStream::WriteEmptyFiles()
67 {
68   for(;_currentIndex < _extractStatuses->Size(); _currentIndex++)
69   {
70     UInt32 index = _startIndex + _currentIndex;
71     const CFileItem &fileInfo = _archiveDatabase->Files[index];
72     if (!fileInfo.IsAnti && !fileInfo.IsDirectory && fileInfo.UnPackSize != 0)
73       return S_OK;
74     RINOK(OpenFile());
75     RINOK(_extractCallback->SetOperationResult(
76         NArchive::NExtract::NOperationResult::kOK));
77     _outStreamWithHashSpec->ReleaseStream();
78   }
79   return S_OK;
80 }
81
82 STDMETHODIMP CFolderOutStream::Write(const void *data, 
83     UInt32 size, UInt32 *processedSize)
84 {
85   UInt32 realProcessedSize = 0;
86   while(_currentIndex < _extractStatuses->Size())
87   {
88     if (_fileIsOpen)
89     {
90       UInt32 index = _startIndex + _currentIndex;
91       const CFileItem &fileInfo = _archiveDatabase->Files[index];
92       UInt64 fileSize = fileInfo.UnPackSize;
93       
94       UInt32 numBytesToWrite = (UInt32)MyMin(fileSize - _filePos, 
95           UInt64(size - realProcessedSize));
96       
97       UInt32 processedSizeLocal;
98       RINOK(_outStreamWithHash->Write((const Byte *)data + realProcessedSize, 
99             numBytesToWrite, &processedSizeLocal));
100
101       _filePos += processedSizeLocal;
102       realProcessedSize += processedSizeLocal;
103       if (_filePos == fileSize)
104       {
105         bool digestsAreEqual;
106         if (fileInfo.IsFileCRCDefined && _checkCrc)
107           digestsAreEqual = fileInfo.FileCRC == _outStreamWithHashSpec->GetCRC();
108         else
109           digestsAreEqual = true;
110
111         RINOK(_extractCallback->SetOperationResult(
112             digestsAreEqual ? 
113             NArchive::NExtract::NOperationResult::kOK :
114             NArchive::NExtract::NOperationResult::kCRCError));
115         _outStreamWithHashSpec->ReleaseStream();
116         _fileIsOpen = false;
117         _currentIndex++;
118       }
119       if (realProcessedSize == size)
120       {
121         if (processedSize != NULL)
122           *processedSize = realProcessedSize;
123         return WriteEmptyFiles();
124       }
125     }
126     else
127     {
128       RINOK(OpenFile());
129       _fileIsOpen = true;
130       _filePos = 0;
131     }
132   }
133   if (processedSize != NULL)
134     *processedSize = size;
135   return S_OK;
136 }
137
138 HRESULT CFolderOutStream::FlushCorrupted(Int32 resultEOperationResult)
139 {
140   while(_currentIndex < _extractStatuses->Size())
141   {
142     if (_fileIsOpen)
143     {
144       RINOK(_extractCallback->SetOperationResult(resultEOperationResult));
145       _outStreamWithHashSpec->ReleaseStream();
146       _fileIsOpen = false;
147       _currentIndex++;
148     }
149     else
150     {
151       RINOK(OpenFile());
152       _fileIsOpen = true;
153     }
154   }
155   return S_OK;
156 }
157
158 HRESULT CFolderOutStream::WasWritingFinished()
159 {
160   if (_currentIndex == _extractStatuses->Size())
161     return S_OK;
162   return E_FAIL;
163 }
164
165 }}