Skip to content

Commit bee9116

Browse files
committed
adding Pak files
adding pak files still in beta
1 parent c773f3d commit bee9116

File tree

12 files changed

+3679
-0
lines changed

12 files changed

+3679
-0
lines changed

BuildAll.sln

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ClickTeam", "CPP\7zip\Bundl
77
EndProject
88
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PyInstaller", "CPP\7zip\Bundles\PyInstaller\PyInstaller\PyInstaller.vcxproj", "{C8B5AB86-D476-4B2E-9916-66EAAFA5A216}"
99
EndProject
10+
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Pak", "CPP\7zip\Bundles\Pak\Pak\Pak.vcxproj", "{3A75AC2B-7CAD-4BE3-A637-E472FEB99266}"
11+
EndProject
1012
Global
1113
GlobalSection(SolutionConfigurationPlatforms) = preSolution
1214
Debug|x64 = Debug|x64
@@ -31,6 +33,14 @@ Global
3133
{C8B5AB86-D476-4B2E-9916-66EAAFA5A216}.Release|x64.Build.0 = Release|x64
3234
{C8B5AB86-D476-4B2E-9916-66EAAFA5A216}.Release|x86.ActiveCfg = Release|Win32
3335
{C8B5AB86-D476-4B2E-9916-66EAAFA5A216}.Release|x86.Build.0 = Release|Win32
36+
{3A75AC2B-7CAD-4BE3-A637-E472FEB99266}.Debug|x64.ActiveCfg = Debug|x64
37+
{3A75AC2B-7CAD-4BE3-A637-E472FEB99266}.Debug|x64.Build.0 = Debug|x64
38+
{3A75AC2B-7CAD-4BE3-A637-E472FEB99266}.Debug|x86.ActiveCfg = Debug|Win32
39+
{3A75AC2B-7CAD-4BE3-A637-E472FEB99266}.Debug|x86.Build.0 = Debug|Win32
40+
{3A75AC2B-7CAD-4BE3-A637-E472FEB99266}.Release|x64.ActiveCfg = Release|x64
41+
{3A75AC2B-7CAD-4BE3-A637-E472FEB99266}.Release|x64.Build.0 = Release|x64
42+
{3A75AC2B-7CAD-4BE3-A637-E472FEB99266}.Release|x86.ActiveCfg = Release|Win32
43+
{3A75AC2B-7CAD-4BE3-A637-E472FEB99266}.Release|x86.Build.0 = Release|Win32
3444
EndGlobalSection
3545
GlobalSection(SolutionProperties) = preSolution
3646
HideSolutionNode = FALSE

CPP/7zip/Archive/Pak/Pak.cpp

Lines changed: 314 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,314 @@
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

Comments
 (0)