main
cpp 190 lines 6.18 KB
Raw
1 // Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
3 #include "precomp.h"
4
5 static HRESULT CompressFiles(__in HANDLE hCab, __inout_z LPWSTR* psczFirstFileToken);
6 static void __stdcall CabNamesCallback(__in_z LPCWSTR wzFirstCabName, __in_z LPCWSTR wzNewCabName, __in_z LPCWSTR wzFileToken);
7
8
9 HRESULT SmartCabCommand(
10 __in int argc,
11 __in_ecount(argc) LPWSTR argv[]
12 )
13 {
14 HRESULT hr = E_INVALIDARG;
15 LPWSTR sczCabPath = NULL;
16 LPCWSTR wzCabName = NULL;
17 LPWSTR sczCabDir = NULL;
18 UINT uiFileCount = 0;
19 UINT uiMaxSize = 0;
20 UINT uiMaxThresh = 0;
21 COMPRESSION_TYPE ct = COMPRESSION_TYPE_NONE;
22 HANDLE hCab = NULL;
23 LPWSTR sczFirstFileToken = NULL;
24
25 if (argc < 1)
26 {
27 ConsoleExitOnFailure(hr, CONSOLE_COLOR_RED, "Must specify: outCabPath [compressionType] [fileCount] [maxSizePerCabInMB [maxThreshold]]");
28 }
29 else
30 {
31 hr = PathExpand(&sczCabPath, argv[0], PATH_EXPAND_FULLPATH);
32 ConsoleExitOnFailure(hr, CONSOLE_COLOR_RED, "Could not expand path: %ls", argv[0]);
33
34 wzCabName = PathFile(sczCabPath);
35
36 hr = PathGetDirectory(sczCabPath, &sczCabDir);
37 ConsoleExitOnFailure(hr, CONSOLE_COLOR_RED, "Could not parse directory from path: %ls", sczCabPath);
38
39 if (argc > 1)
40 {
41 UINT uiCompressionType;
42 hr = StrStringToUInt32(argv[1], 0, &uiCompressionType);
43 ConsoleExitOnFailure(hr, CONSOLE_COLOR_RED, "Could not parse compression type as number: %ls", argv[1]);
44
45 ct = (uiCompressionType > 4) ? COMPRESSION_TYPE_HIGH : static_cast<COMPRESSION_TYPE>(uiCompressionType);
46 }
47
48 if (argc > 2)
49 {
50 hr = StrStringToUInt32(argv[2], 0, &uiFileCount);
51 ConsoleExitOnFailure(hr, CONSOLE_COLOR_RED, "Could not parse file count as number: %ls", argv[2]);
52 }
53
54 if (argc > 3)
55 {
56 hr = StrStringToUInt32(argv[3], 0, &uiMaxSize);
57 ConsoleExitOnFailure(hr, CONSOLE_COLOR_RED, "Could not parse max size as number: %ls", argv[3]);
58 }
59
60 if (argc > 4)
61 {
62 hr = StrStringToUInt32(argv[4], 0, &uiMaxThresh);
63 ConsoleExitOnFailure(hr, CONSOLE_COLOR_RED, "Could not parse max threshold as number: %ls", argv[4]);
64 }
65 }
66
67 hr = CabCBegin(wzCabName, sczCabDir, uiFileCount, uiMaxSize, uiMaxThresh, ct, &hCab);
68 ConsoleExitOnFailure(hr, CONSOLE_COLOR_RED, "failed to initialize cabinet: %ls", sczCabPath);
69
70 if (uiFileCount > 0)
71 {
72 hr = WixNativeReadStdinPreamble();
73 ExitOnFailure(hr, "failed to read stdin preamble before smartcabbing");
74
75 hr = CompressFiles(hCab, &sczFirstFileToken);
76 ExitOnFailure(hr, "failed to compress files into cabinet: %ls", sczCabPath);
77
78 CabNamesCallback(wzCabName, wzCabName, sczFirstFileToken);
79 }
80 else
81 {
82 CabNamesCallback(wzCabName, wzCabName, L"");
83 }
84
85 hr = CabCFinish(hCab, CabNamesCallback);
86 hCab = NULL; // once finish is called, the handle is invalid.
87 ConsoleExitOnFailure(hr, CONSOLE_COLOR_RED, "failed to compress cabinet: %ls", sczCabPath);
88
89 LExit:
90 ReleaseStr(sczFirstFileToken);
91 if (hCab)
92 {
93 CabCCancel(hCab);
94 }
95 ReleaseStr(sczCabDir);
96 ReleaseStr(sczCabPath);
97
98 return hr;
99 }
100
101
102 static HRESULT CompressFiles(
103 __in HANDLE hCab,
104 __inout_z LPWSTR* psczFirstFileToken
105 )
106 {
107 HRESULT hr = S_OK;
108 LPWSTR sczLine = NULL;
109 LPWSTR* rgsczSplit = NULL;
110 UINT cSplit = 0;
111 MSIFILEHASHINFO hashInfo = { sizeof(MSIFILEHASHINFO) };
112
113 for (;;)
114 {
115 hr = ConsoleReadW(&sczLine);
116 ConsoleExitOnFailure(hr, CONSOLE_COLOR_RED, "failed to read smartcab line from stdin");
117
118 if (!*sczLine)
119 {
120 break;
121 }
122
123 hr = StrSplitAllocArray(&rgsczSplit, &cSplit, sczLine, L"\t");
124 ConsoleExitOnFailure(hr, CONSOLE_COLOR_RED, "failed to split smartcab line from stdin: %ls", sczLine);
125
126 if (!rgsczSplit || (cSplit != 2 && cSplit != 6))
127 {
128 hr = E_INVALIDARG;
129 ConsoleExitOnFailure(hr, CONSOLE_COLOR_RED, "failed to split smartcab line into hash x 4, token, source file: %ls", sczLine);
130 }
131
132 LPCWSTR wzFilePath = rgsczSplit[0];
133 LPCWSTR wzToken = rgsczSplit[1];
134 PMSIFILEHASHINFO pHashInfo = NULL;
135
136 if (cSplit == 6)
137 {
138 for (int i = 0; i < 4; ++i)
139 {
140 LPCWSTR wzHash = rgsczSplit[i + 2];
141
142 hr = StrStringToInt32(wzHash, 0, reinterpret_cast<INT*>(hashInfo.dwData + i));
143 ConsoleExitOnFailure(hr, CONSOLE_COLOR_RED, "failed to parse hash: %ls for file: %ls", wzHash, wzFilePath);
144 }
145
146 pHashInfo = &hashInfo;
147 }
148
149 if (psczFirstFileToken && !*psczFirstFileToken)
150 {
151 hr = StrAllocString(psczFirstFileToken, wzToken, 0);
152 ConsoleExitOnFailure(hr, CONSOLE_COLOR_RED, "failed to allocate first file token: %ls", wzToken);
153 }
154
155 hr = CabCAddFile(wzFilePath, wzToken, pHashInfo, hCab);
156 ConsoleExitOnFailure(hr, CONSOLE_COLOR_RED, "failed to add file: %ls", wzFilePath);
157
158 ReleaseNullStrArray(rgsczSplit, cSplit);
159 }
160
161 LExit:
162 ReleaseNullStrArray(rgsczSplit, cSplit);
163 ReleaseStr(sczLine);
164
165 return hr;
166 }
167
168
169 // Callback from PFNFCIGETNEXTCABINET CabCGetNextCabinet method
170 // First argument is the name of splitting cabinet without extension e.g. "cab1"
171 // Second argument is name of the new cabinet that would be formed by splitting e.g. "cab1b.cab"
172 // Third argument is the file token of the first file present in the splitting cabinet
173 static void __stdcall CabNamesCallback(
174 __in_z LPCWSTR wzFirstCabName,
175 __in_z LPCWSTR wzNewCabName,
176 __in_z LPCWSTR wzFileToken
177 )
178 {
179 HRESULT hr;
180 LPWSTR scz = NULL;
181
182 hr = StrAllocFormatted(&scz, L"%s\t%s\t%s\r\n", wzFirstCabName, wzNewCabName, wzFileToken);
183 ConsoleExitOnFailure(hr, CONSOLE_COLOR_RED, "failed to allocate cabinet names message");
184
185 hr = ConsoleWriteW(CONSOLE_COLOR_NORMAL, scz);
186 ConsoleExitOnFailure(hr, CONSOLE_COLOR_RED, "failed to send cabinet names message");
187
188 LExit:
189 ReleaseStr(scz);
190 }