aboutsummaryrefslogtreecommitdiff
path: root/src/dtf/WixToolset.Dtf.Compression.Cab/CabWorker.cs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/dtf/WixToolset.Dtf.Compression.Cab/CabWorker.cs337
1 files changed, 337 insertions, 0 deletions
diff --git a/src/dtf/WixToolset.Dtf.Compression.Cab/CabWorker.cs b/src/dtf/WixToolset.Dtf.Compression.Cab/CabWorker.cs
new file mode 100644
index 00000000..cb2a7263
--- /dev/null
+++ b/src/dtf/WixToolset.Dtf.Compression.Cab/CabWorker.cs
@@ -0,0 +1,337 @@
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
3namespace WixToolset.Dtf.Compression.Cab
4{
5 using System;
6 using System.IO;
7 using System.IO.IsolatedStorage;
8 using System.Text;
9 using System.Security;
10 using System.Collections.Generic;
11 using System.Runtime.InteropServices;
12 using System.Diagnostics.CodeAnalysis;
13
14 internal abstract class CabWorker : IDisposable
15 {
16 internal const string CabStreamName = "%%CAB%%";
17
18 private CabEngine cabEngine;
19
20 private HandleManager<Stream> streamHandles;
21 private Stream cabStream;
22 private Stream fileStream;
23
24 private NativeMethods.ERF erf;
25 private GCHandle erfHandle;
26
27 private IDictionary<string, short> cabNumbers;
28 private string nextCabinetName;
29
30 private bool suppressProgressEvents;
31
32 private byte[] buf;
33
34 // Progress data
35 protected string currentFileName;
36 protected int currentFileNumber;
37 protected int totalFiles;
38 protected long currentFileBytesProcessed;
39 protected long currentFileTotalBytes;
40 protected short currentFolderNumber;
41 protected long currentFolderTotalBytes;
42 protected string currentArchiveName;
43 protected short currentArchiveNumber;
44 protected short totalArchives;
45 protected long currentArchiveBytesProcessed;
46 protected long currentArchiveTotalBytes;
47 protected long fileBytesProcessed;
48 protected long totalFileBytes;
49
50 [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")]
51 protected CabWorker(CabEngine cabEngine)
52 {
53 this.cabEngine = cabEngine;
54 this.streamHandles = new HandleManager<Stream>();
55 this.erf = new NativeMethods.ERF();
56 this.erfHandle = GCHandle.Alloc(this.erf, GCHandleType.Pinned);
57 this.cabNumbers = new Dictionary<string, short>(1);
58
59 // 32K seems to be the size of the largest chunks processed by cabinet.dll.
60 // But just in case, this buffer will auto-enlarge.
61 this.buf = new byte[32768];
62 }
63
64 ~CabWorker()
65 {
66 this.Dispose(false);
67 }
68
69 public CabEngine CabEngine
70 {
71 get
72 {
73 return this.cabEngine;
74 }
75 }
76
77 internal NativeMethods.ERF Erf
78 {
79 get
80 {
81 return this.erf;
82 }
83 }
84
85 internal GCHandle ErfHandle
86 {
87 get
88 {
89 return this.erfHandle;
90 }
91 }
92
93 internal HandleManager<Stream> StreamHandles
94 {
95 get
96 {
97 return this.streamHandles;
98 }
99 }
100
101 internal bool SuppressProgressEvents
102 {
103 get
104 {
105 return this.suppressProgressEvents;
106 }
107
108 set
109 {
110 this.suppressProgressEvents = value;
111 }
112 }
113
114 internal IDictionary<string, short> CabNumbers
115 {
116 get
117 {
118 return this.cabNumbers;
119 }
120 }
121
122 internal string NextCabinetName
123 {
124 get
125 {
126 return this.nextCabinetName;
127 }
128
129 set
130 {
131 this.nextCabinetName = value;
132 }
133 }
134
135 internal Stream CabStream
136 {
137 get
138 {
139 return this.cabStream;
140 }
141
142 set
143 {
144 this.cabStream = value;
145 }
146 }
147
148 internal Stream FileStream
149 {
150 get
151 {
152 return this.fileStream;
153 }
154
155 set
156 {
157 this.fileStream = value;
158 }
159 }
160
161 public void Dispose()
162 {
163 this.Dispose(true);
164 GC.SuppressFinalize(this);
165 }
166
167 protected void ResetProgressData()
168 {
169 this.currentFileName = null;
170 this.currentFileNumber = 0;
171 this.totalFiles = 0;
172 this.currentFileBytesProcessed = 0;
173 this.currentFileTotalBytes = 0;
174 this.currentFolderNumber = 0;
175 this.currentFolderTotalBytes = 0;
176 this.currentArchiveName = null;
177 this.currentArchiveNumber = 0;
178 this.totalArchives = 0;
179 this.currentArchiveBytesProcessed = 0;
180 this.currentArchiveTotalBytes = 0;
181 this.fileBytesProcessed = 0;
182 this.totalFileBytes = 0;
183 }
184
185 protected void OnProgress(ArchiveProgressType progressType)
186 {
187 if (!this.suppressProgressEvents)
188 {
189 ArchiveProgressEventArgs e = new ArchiveProgressEventArgs(
190 progressType,
191 this.currentFileName,
192 this.currentFileNumber >= 0 ? this.currentFileNumber : 0,
193 this.totalFiles,
194 this.currentFileBytesProcessed,
195 this.currentFileTotalBytes,
196 this.currentArchiveName,
197 this.currentArchiveNumber,
198 this.totalArchives,
199 this.currentArchiveBytesProcessed,
200 this.currentArchiveTotalBytes,
201 this.fileBytesProcessed,
202 this.totalFileBytes);
203 this.CabEngine.ReportProgress(e);
204 }
205 }
206
207 internal IntPtr CabAllocMem(int byteCount)
208 {
209 IntPtr memPointer = Marshal.AllocHGlobal((IntPtr) byteCount);
210 return memPointer;
211 }
212
213 internal void CabFreeMem(IntPtr memPointer)
214 {
215 Marshal.FreeHGlobal(memPointer);
216 }
217
218 internal int CabOpenStream(string path, int openFlags, int shareMode)
219 {
220 int err; return this.CabOpenStreamEx(path, openFlags, shareMode, out err, IntPtr.Zero);
221 }
222
223 internal virtual int CabOpenStreamEx(string path, int openFlags, int shareMode, out int err, IntPtr pv)
224 {
225 path = path.Trim();
226 Stream stream = this.cabStream;
227 this.cabStream = new DuplicateStream(stream);
228 int streamHandle = this.streamHandles.AllocHandle(stream);
229 err = 0;
230 return streamHandle;
231 }
232
233 internal int CabReadStream(int streamHandle, IntPtr memory, int cb)
234 {
235 int err; return this.CabReadStreamEx(streamHandle, memory, cb, out err, IntPtr.Zero);
236 }
237
238 internal virtual int CabReadStreamEx(int streamHandle, IntPtr memory, int cb, out int err, IntPtr pv)
239 {
240 Stream stream = this.streamHandles[streamHandle];
241 int count = (int) cb;
242 if (count > this.buf.Length)
243 {
244 this.buf = new byte[count];
245 }
246 count = stream.Read(this.buf, 0, count);
247 Marshal.Copy(this.buf, 0, memory, count);
248 err = 0;
249 return count;
250 }
251
252 internal int CabWriteStream(int streamHandle, IntPtr memory, int cb)
253 {
254 int err; return this.CabWriteStreamEx(streamHandle, memory, cb, out err, IntPtr.Zero);
255 }
256
257 internal virtual int CabWriteStreamEx(int streamHandle, IntPtr memory, int cb, out int err, IntPtr pv)
258 {
259 Stream stream = this.streamHandles[streamHandle];
260 int count = (int) cb;
261 if (count > this.buf.Length)
262 {
263 this.buf = new byte[count];
264 }
265 Marshal.Copy(memory, this.buf, 0, count);
266 stream.Write(this.buf, 0, count);
267 err = 0;
268 return cb;
269 }
270
271 internal int CabCloseStream(int streamHandle)
272 {
273 int err; return this.CabCloseStreamEx(streamHandle, out err, IntPtr.Zero);
274 }
275
276 internal virtual int CabCloseStreamEx(int streamHandle, out int err, IntPtr pv)
277 {
278 this.streamHandles.FreeHandle(streamHandle);
279 err = 0;
280 return 0;
281 }
282
283 internal int CabSeekStream(int streamHandle, int offset, int seekOrigin)
284 {
285 int err; return this.CabSeekStreamEx(streamHandle, offset, seekOrigin, out err, IntPtr.Zero);
286 }
287
288 internal virtual int CabSeekStreamEx(int streamHandle, int offset, int seekOrigin, out int err, IntPtr pv)
289 {
290 Stream stream = this.streamHandles[streamHandle];
291 offset = (int) stream.Seek(offset, (SeekOrigin) seekOrigin);
292 err = 0;
293 return offset;
294 }
295
296 /// <summary>
297 /// Disposes of resources allocated by the cabinet engine.
298 /// </summary>
299 /// <param name="disposing">If true, the method has been called directly or indirectly by a user's code,
300 /// so managed and unmanaged resources will be disposed. If false, the method has been called by the
301 /// runtime from inside the finalizer, and only unmanaged resources will be disposed.</param>
302 [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")]
303 protected virtual void Dispose(bool disposing)
304 {
305 if (disposing)
306 {
307 if (this.cabStream != null)
308 {
309 this.cabStream.Close();
310 this.cabStream = null;
311 }
312
313 if (this.fileStream != null)
314 {
315 this.fileStream.Close();
316 this.fileStream = null;
317 }
318 }
319
320 if (this.erfHandle.IsAllocated)
321 {
322 this.erfHandle.Free();
323 }
324 }
325
326 protected void CheckError(bool extracting)
327 {
328 if (this.Erf.Error)
329 {
330 throw new CabException(
331 this.Erf.Oper,
332 this.Erf.Type,
333 CabException.GetErrorMessage(this.Erf.Oper, this.Erf.Type, extracting));
334 }
335 }
336 }
337}