1+ #include " stdafx.h"
2+ #pragma warning (disable: 5043)
3+ #include " ../../../Common/ComTry.h"
4+ #include " ../../../Common/MyString.h"
5+ #include " ../../../Windows/PropVariant.h"
6+ #include " ../../Common/ProgressUtils.h"
7+ #include " ../../Common/RegisterArc.h"
8+ #include " ../../Common/StreamObjects.h"
9+ #include " ../../Archive/IArchive.h"
10+ #include " ../../Common/LimitedStreams.h"
11+ #include " ../../Common/StreamUtils.h"
12+ #include " Pak.h"
13+
14+
15+ using namespace NWindows ;
16+ namespace NArchive {
17+ namespace NZzz {
18+
19+ // Define properties used by the handler
20+ static const Byte kProps [] =
21+ {
22+ kpidPath, // Path property identifier
23+ kpidSize, // Size property identifier
24+ };
25+ // CHandler class implements IInArchive and IInArchiveGetStream interfaces
26+ class CHandler : public IInArchive , public IInArchiveGetStream , public CMyUnknownImp {
27+ public:
28+ MY_UNKNOWN_IMP2 (IInArchive, IInArchiveGetStream) // Implementing unknown interface
29+ INTERFACE_IInArchive (;)
30+
31+ // Default constructor
32+ CHandler () = default ;
33+
34+ // Constructor that accepts a PyInstallerHandler reference
35+ CHandler (PakFileHandler& handler) : pakHandler(handler) {}
36+
37+ // Retrieves a stream from the archive
38+ STDMETHOD (GetStream)(UInt32 index, ISequentialInStream** stream);
39+
40+ PakFileHandler pakHandler; // Instance of PyInstallerHandler
41+ std::vector<PakFileHandler::Record> items; // Vector to store archive entries
42+ };
43+
44+ // Implement interface functions for the archive properties
45+ IMP_IInArchive_Props
46+ IMP_IInArchive_ArcProps_NO_Table
47+
48+ /* *
49+ * @brief Retrieves a property of the archive based on the provided property ID.
50+ *
51+ * @param propID The ID of the property to retrieve.
52+ * @param value Output parameter to receive the property value.
53+ * @return HRESULT indicating success or failure.
54+ */
55+ STDMETHODIMP CHandler::GetArchiveProperty (PROPID propID, PROPVARIANT* value)
56+ {
57+ NCOM::CPropVariant prop; // Property variant to hold the property value
58+ switch (propID)
59+ {
60+ case kpidPhySize:
61+ prop = (UInt64)1 ; // Assign a physical size value
62+ break ;
63+ }
64+ prop.Detach (value); // Detach the property from the variant
65+ return S_OK; // Indicate success
66+ }
67+
68+ /* *
69+ * @brief Opens the specified input stream as an archive.
70+ *
71+ * @param stream The input stream to open.
72+ * @param callback Callback interface for reporting progress and status.
73+ * @return HRESULT indicating success or failure.
74+ */
75+ STDMETHODIMP CHandler::Open (IInStream* stream, const UInt64*, IArchiveOpenCallback* callback) {
76+ Close (); // Close any existing archive state
77+
78+ // Validate input parameters
79+ if (!callback || !stream) {
80+ return S_FALSE; // Invalid arguments
81+ }
82+
83+
84+ // Attempt to open the PyInstaller handler
85+ HRESULT result = pakHandler.Open (stream, nullptr , callback);
86+ if (FAILED (result)) {
87+ return result; // Return if the handler fails to open
88+ }
89+
90+ items = pakHandler.items ; // Retrieve items from the handler
91+
92+ // Debug message to check the number of items after opening
93+ std::wstring msg = L" Size of items vector after PyInstallerHandler::Open: " + std::to_wstring (items.size ());
94+
95+ MessageBox (NULL , msg.c_str (), L" Debug - CHandler::Open" , MB_OK);
96+
97+ UInt64 fileSize = 0 ; // Declare file size variable
98+ result = stream->Seek (0 , STREAM_SEEK_END, &fileSize); // Seek to the end to get the file size
99+ if (FAILED (result) || fileSize == 0 ) {
100+ return S_FALSE; // Ensure the file size is valid
101+ }
102+ stream->Seek (0 , STREAM_SEEK_SET, nullptr ); // Seek back to the start of the stream
103+ // Get the name of the file from the callback
104+ CMyComPtr<IArchiveOpenVolumeCallback> volumeCallback;
105+ result = callback->QueryInterface (IID_IArchiveOpenVolumeCallback, (void **)&volumeCallback);
106+ if (FAILED (result) || !volumeCallback) {
107+ return S_FALSE; // Check that the interface was obtained
108+ }
109+ UString name;
110+ {
111+ NCOM::CPropVariant prop;
112+ result = volumeCallback->GetProperty (kpidName, &prop);
113+ if (FAILED (result) || prop.vt != VT_BSTR) {
114+ return S_FALSE; // Ensure the property is a string
115+ }
116+ name = prop.bstrVal ; // Get the name as UString
117+ }
118+
119+ }
120+
121+ /* *
122+ * @brief Closes the archive and releases resources.
123+ *
124+ * @return HRESULT indicating success.
125+ */
126+ STDMETHODIMP CHandler::Close () {
127+ return S_OK; // Indicate successful closure
128+ }
129+
130+ /* *
131+ * @brief Retrieves the number of items in the archive.
132+ *
133+ * @param numItems Output parameter to receive the number of items.
134+ * @return HRESULT indicating success or failure.
135+ */
136+ STDMETHODIMP CHandler::GetNumberOfItems (UInt32* numItems) {
137+ if (numItems == nullptr ) {
138+ return E_POINTER; // Return error if pointer is null
139+ }
140+
141+ // Access the number of items through the PyInstallerHandler instance
142+ *numItems = static_cast <UInt32>(pakHandler.items .size ()); // Correctly access size of vector
143+
144+ // Debug message to show the number of items
145+ std::wstring msg = L" Total items: " + std::to_wstring (*numItems);
146+
147+ MessageBox (NULL , msg.c_str (), L" Debug - GetNumberOfItems" , MB_OK);
148+
149+ return S_OK; // Indicate success
150+ }
151+
152+ /* *
153+ * @brief Retrieves a specific property for an item in the archive.
154+ *
155+ * @param index The index of the item.
156+ * @param propID The property ID to retrieve.
157+ * @param value Output parameter to receive the property value.
158+ * @return HRESULT indicating success or failure.
159+ */
160+ STDMETHODIMP CHandler::GetProperty (UInt32 index, PROPID propID, PROPVARIANT* value)
161+ {
162+ if (index >= items.size ()) {
163+ return E_INVALIDARG; // Handle out-of-bounds index
164+ }
165+
166+ NCOM::CPropVariant prop; // Property variant to hold the value
167+ switch (propID)
168+ {
169+ case kpidPath:
170+ if (!items[index].fileName .empty ()) {
171+ prop = items[index].fileName .c_str (); // Set the path property
172+ }
173+ else {
174+ return E_INVALIDARG; // Return error for empty file name
175+ }
176+ break ;
177+
178+ case kpidSize:
179+ prop = items[index].sizeDecompressed ; // Set the decompressed size property
180+ break ;
181+
182+ default :
183+ return E_INVALIDARG; // Return error if propID is not recognized
184+ }
185+
186+ prop.Detach (value); // Detach the property from the variant
187+ return S_OK; // Indicate success
188+ }
189+
190+
191+
192+ /* *
193+ * @brief Extracts items from the archive.
194+ *
195+ * @param indices Array of indices for items to extract.
196+ * @param numItems Number of items to extract.
197+ * @param testMode Flag indicating if this is a test extraction.
198+ * @param extractCallback Callback for extraction progress and results.
199+ * @return HRESULT indicating success or failure.
200+ */
201+ STDMETHODIMP CHandler::Extract (const UInt32* indices, UInt32 numItems, Int32 testMode, IArchiveExtractCallback* extractCallback) {
202+ bool allFilesMode = (numItems == (UInt32)(Int32)-1 );
203+ if (allFilesMode) numItems = static_cast <UInt32>(items.size ());
204+ if (numItems == 0 ) return S_OK;
205+
206+ UInt64 totalSize = 0 , currentSize = 0 ;
207+ for (size_t i = 0 ; i < numItems; i++) {
208+ totalSize += items[allFilesMode ? i : indices[i]].sizeDecompressed ;
209+ }
210+ extractCallback->SetTotal (totalSize);
211+
212+ CLocalProgress* lps = new CLocalProgress;
213+ CMyComPtr<ICompressProgressInfo> progress = lps;
214+ lps->Init (extractCallback, false );
215+
216+ for (UINT i = 0 ; i < numItems; i++) {
217+ lps->InSize = currentSize;
218+ lps->OutSize = currentSize;
219+ RINOK (lps->SetCur ());
220+
221+ CMyComPtr<ISequentialOutStream> realOutStream;
222+ Int32 askMode = testMode ? NExtract::NAskMode::kTest : NExtract::NAskMode::kExtract ;
223+ UINT32 index = allFilesMode ? i : indices[i];
224+ auto & item = items[index];
225+ currentSize += item.sizeDecompressed ;
226+
227+ RINOK (extractCallback->GetStream (index, &realOutStream, askMode));
228+ if (!testMode && !realOutStream) {
229+ MessageBox (NULL , L" [Debug] Skipping file due to missing output stream." , L" Debug Info" , MB_OK);
230+ continue ;
231+ }
232+
233+ RINOK (extractCallback->PrepareOperation (askMode));
234+
235+ std::wstringstream debugMsg;
236+ debugMsg << L" [Debug] Extracting file index " << index << L" :\n "
237+ << L" Name: " << item.fileName .c_str ();
238+
239+ MessageBox (NULL , debugMsg.str ().c_str (), L" Debug Info" , MB_OK);
240+
241+ // Check data content
242+ std::wstringstream contentMsg;
243+ contentMsg << L" [Debug] Data content for file index " << index << L" : " ;
244+ for (const auto & byte : item.Data ) {
245+ contentMsg << byte;
246+ }
247+ MessageBox (NULL , contentMsg.str ().c_str (), L" Debug Info" , MB_OK);
248+
249+ HRESULT writeResult = realOutStream->Write (item.Data .data (), (UINT32)item.Data .size (), NULL );
250+ if (writeResult != S_OK) {
251+ std::wstringstream errMsg;
252+ errMsg << L" [Debug] Failed to write data for file index " << index << L" . Data size: " << item.Data .size ();
253+ MessageBox (NULL , errMsg.str ().c_str (), L" Debug Info" , MB_OK);
254+ return writeResult;
255+ }
256+
257+ std::wstringstream successMsg;
258+ successMsg << L" [Debug] Successfully wrote data for file index " << index << L" . Data size: " << item.Data .size ();
259+ MessageBox (NULL , successMsg.str ().c_str (), L" Debug Info" , MB_OK);
260+
261+ realOutStream.Release ();
262+ RINOK (extractCallback->SetOperationResult (NExtract::NOperationResult::kOK ));
263+ }
264+
265+ lps->InSize = totalSize;
266+ lps->OutSize = totalSize;
267+ return lps->SetCur ();
268+ }
269+
270+
271+ /* *
272+ * @brief Retrieves a stream corresponding to a specific item in the archive.
273+ *
274+ * @param index The index of the item for which to retrieve the stream.
275+ * @param stream Output parameter to receive the stream.
276+ * @return HRESULT indicating success or failure.
277+ */
278+ STDMETHODIMP CHandler::GetStream (UInt32 index, ISequentialInStream** stream)
279+ {
280+ if (index >= items.size ()) {
281+ return E_FAIL; // Safety check for index bounds
282+ }
283+
284+ *stream = nullptr ; // Initialize the output stream pointer to nullptr
285+
286+ // Ensure the item has valid data to create a stream
287+ if (items[index].Data .empty ()) {
288+ return E_FAIL; // Return error if the data is empty
289+ }
290+
291+ // Create a buffer stream for the item data
292+ CBufInStream* streamSpec = new CBufInStream;
293+ CMyComPtr<ISequentialInStream> streamTemp = streamSpec; // Smart pointer management
294+
295+ // Initialize the stream with the item data
296+ streamSpec->Init (reinterpret_cast <const Byte*>(items[index].Data .data ()), static_cast <UInt32>(items[index].Data .size ()));
297+
298+ // If Init doesn't throw or return errors, assign the stream to the output parameter
299+ *stream = streamTemp.Detach ();
300+ return S_OK; // Indicate success
301+ }
302+
303+
304+
305+
306+
307+ // Register the archive handler for .exe files
308+ REGISTER_ARC_I_NO_SIG (
309+ " pak" , " pak" , 0 , 0xAA ,
310+ 0 ,
311+ 0 ,
312+ NULL )
313+ }
314+ }
0 commit comments