|
1 // fzip.cpp |
|
2 // |
|
3 // Copyright (c) 2008 - 2010 Accenture. All rights reserved. |
|
4 // This component and the accompanying materials are made available |
|
5 // under the terms of the "Eclipse Public License v1.0" |
|
6 // which accompanies this distribution, and is available |
|
7 // at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 // |
|
9 // Initial Contributors: |
|
10 // Accenture - Initial contribution |
|
11 // |
|
12 |
|
13 #include <zipfile.h> |
|
14 #include <ezgzip.h> |
|
15 #include "fzip.h" |
|
16 |
|
17 _LIT(KGzExtension, ".gz"); |
|
18 |
|
19 CCommandBase* CCmdZip::NewLC() |
|
20 { |
|
21 CCmdZip* self = new (ELeave) CCmdZip(); |
|
22 CleanupStack::PushL(self); |
|
23 self->BaseConstructL(); |
|
24 return self; |
|
25 } |
|
26 |
|
27 CCmdZip::~CCmdZip() |
|
28 { |
|
29 if (iFileToZip.Count() > 0) |
|
30 iFileToZip.Close(); |
|
31 } |
|
32 |
|
33 CCmdZip::CCmdZip() : CCommandBase(CCommandBase::EManualComplete) |
|
34 { |
|
35 } |
|
36 |
|
37 const TDesC& CCmdZip::Name() const |
|
38 { |
|
39 _LIT(KName, "fzip"); |
|
40 return KName; |
|
41 } |
|
42 |
|
43 void CCmdZip::DoRunL() |
|
44 { |
|
45 FsL(); |
|
46 if (iUnzip) |
|
47 { |
|
48 if (!iOptions.IsPresent(&iUnzipPath)) |
|
49 { |
|
50 iUnzipPath = Env().Pwd(); |
|
51 } |
|
52 |
|
53 if (iVerbose) |
|
54 { |
|
55 // command-line sanity checks |
|
56 if (iFileToZip.Count() > 0) |
|
57 { |
|
58 PrintWarning(_L("Ignoring \'-f\' file option.")); |
|
59 } |
|
60 if (iRecurse) |
|
61 { |
|
62 PrintWarning(_L("Ignoring \'-r\' recurse option.")); |
|
63 } |
|
64 } |
|
65 TRAPL(ExpandArchiveL(), _L("Couldn't expand archive")); |
|
66 } |
|
67 else |
|
68 { |
|
69 if (iVerbose) |
|
70 { |
|
71 // command-line sanity checks |
|
72 if (iUnzipPath.Length() > 0) |
|
73 { |
|
74 PrintWarning(_L("Ignoring '-d' directory option.")); |
|
75 } |
|
76 } |
|
77 if (iFileToZip.Count() == 0) |
|
78 { |
|
79 PrintError(KErrArgument, _L("Use '-f' to specify source files.")); |
|
80 User::Leave(KErrArgument); |
|
81 } |
|
82 TRAPD(err, CreateArchiveL()); |
|
83 if (err != KErrNone) |
|
84 { |
|
85 PrintError(err, _L("Couldn't create archive")); |
|
86 Fs().Delete(iArchive); // ignore error |
|
87 User::Leave(err); |
|
88 } |
|
89 } |
|
90 if (iVerbose) |
|
91 { |
|
92 Printf(_L("Done\r\n")); |
|
93 } |
|
94 Complete(KErrNone); |
|
95 } |
|
96 |
|
97 void CCmdZip::ArgumentsL(RCommandArgumentList& aArguments) |
|
98 { |
|
99 _LIT(KArg1, "archive"); |
|
100 aArguments.AppendFileNameL(iArchive, KArg1); |
|
101 } |
|
102 |
|
103 void CCmdZip::OptionsL(RCommandOptionList& aOptions) |
|
104 { |
|
105 _LIT(KOptVerbose, "verbose"); |
|
106 aOptions.AppendBoolL(iVerbose, KOptVerbose); |
|
107 |
|
108 _LIT(KOptUnzip, "unzip"); |
|
109 aOptions.AppendBoolL(iUnzip, KOptUnzip); |
|
110 |
|
111 _LIT(KOptDirectory, "directory"); |
|
112 aOptions.AppendFileNameL(iUnzipPath, KOptDirectory); |
|
113 |
|
114 _LIT(KOptRecurse, "recurse"); |
|
115 aOptions.AppendBoolL(iRecurse, KOptRecurse); |
|
116 |
|
117 _LIT(KOptSource, "file"); |
|
118 aOptions.AppendFileNameL(iFileToZip, KOptSource); |
|
119 |
|
120 _LIT(KOptCompressionType, "compression-type"); |
|
121 aOptions.AppendEnumL((TInt&)iCompressionType, KOptCompressionType); |
|
122 } |
|
123 |
|
124 |
|
125 // |
|
126 // COMPRESSION FUNCTIONS |
|
127 // |
|
128 |
|
129 // |
|
130 // CCmdZip::CreateArchiveL |
|
131 // determine which zip format to use and go ahead & create the archive |
|
132 // |
|
133 void CCmdZip::CreateArchiveL() |
|
134 { |
|
135 if (iCompressionType == EGZip) |
|
136 { |
|
137 CreateGzArchiveL(); |
|
138 } |
|
139 else |
|
140 { |
|
141 CreateZipArchiveL(); |
|
142 } |
|
143 } |
|
144 |
|
145 // |
|
146 // CCmdZip::CreateGzArchiveL |
|
147 // create an archive, zipping up all the specified files |
|
148 // |
|
149 void CCmdZip::CreateGzArchiveL() |
|
150 { |
|
151 if (iRecurse) |
|
152 { |
|
153 LeaveIfErr(KErrArgument, _L("GNU Zip format does not support recursion")); |
|
154 } |
|
155 |
|
156 if (iFileToZip.Count() > 1) |
|
157 { |
|
158 LeaveIfErr(KErrArgument, _L("GNU Zip format can only handle a single file")); |
|
159 } |
|
160 |
|
161 if (iArchive.Length() == 0) |
|
162 { |
|
163 iArchive = iFileToZip[0]; |
|
164 iArchive.Append(KGzExtension); |
|
165 } |
|
166 |
|
167 RFile input; |
|
168 if (iVerbose) |
|
169 { |
|
170 Printf(_L("Creating '%S'\r\n"), &iArchive); |
|
171 } |
|
172 |
|
173 // open the input file |
|
174 User::LeaveIfError(input.Open(Fs(), iFileToZip[0], EFileStream | EFileRead | EFileShareAny)); |
|
175 CleanupClosePushL(input); |
|
176 |
|
177 CEZFileToGZip* zip = CEZFileToGZip::NewLC(Fs(), iArchive, input); |
|
178 while (zip->DeflateL()) |
|
179 { |
|
180 // do nothing |
|
181 } |
|
182 if (iVerbose) |
|
183 { |
|
184 Printf(_L("Deflating '%S'\r\n"), &iFileToZip[0]); |
|
185 } |
|
186 |
|
187 CleanupStack::PopAndDestroy(2); // zip, input |
|
188 } |
|
189 |
|
190 // |
|
191 // CCmdZip::CreateZipArchiveL |
|
192 // zip format archive creation |
|
193 // |
|
194 void CCmdZip::CreateZipArchiveL() |
|
195 { |
|
196 CZipItUp* zipArchive = CZipItUp::NewLC(Fs(), iArchive); |
|
197 for (TInt ii = 0 ; ii < iFileToZip.Count() ; ii++) |
|
198 { |
|
199 TFileName2& fileName = iFileToZip[ii]; |
|
200 fileName.SetTypeL(Fs()); |
|
201 AddFileL(*zipArchive, fileName); |
|
202 } |
|
203 zipArchive->CreateZipL(); |
|
204 if (iVerbose) |
|
205 { |
|
206 Printf(_L("Created '%S'\r\n"), &iArchive); |
|
207 } |
|
208 CleanupStack::PopAndDestroy(); // zipArchive |
|
209 } |
|
210 |
|
211 // |
|
212 // CCmdZip::AddFileL |
|
213 // examines a file for wildcards, directories/recursion etc |
|
214 // if it finds an actual file, it'll add it to the zip archive |
|
215 // recursive function |
|
216 // |
|
217 void CCmdZip::AddFileL(CZipItUp& aZipArchive, const TFileName2& aFile) |
|
218 { |
|
219 if (aFile.IsDir()) |
|
220 { |
|
221 CDir* dir; |
|
222 LeaveIfErr(Fs().GetDir(aFile, KEntryAttMatchMask, EDirsLast, dir), _L("Unable to read directory '%S'"), &aFile); |
|
223 CleanupStack::PushL(dir); |
|
224 for (TInt ii = 0 ; ii < dir->Count() ; ii++) |
|
225 { |
|
226 const TEntry& entry = (*dir)[ii]; |
|
227 TFileName2* newFile = new(ELeave) TFileName2(entry.iName); |
|
228 CleanupStack::PushL(newFile); |
|
229 newFile->MakeAbsoluteL(aFile.DriveAndPath()); |
|
230 newFile->SetTypeL(Fs()); |
|
231 if (newFile->IsDir()) |
|
232 { |
|
233 if (iRecurse) |
|
234 { |
|
235 AddFileL(aZipArchive, *newFile); |
|
236 } |
|
237 } |
|
238 else |
|
239 { |
|
240 AddFileL(aZipArchive, *newFile); |
|
241 } |
|
242 CleanupStack::PopAndDestroy(newFile); |
|
243 } |
|
244 CleanupStack::PopAndDestroy(dir); |
|
245 } |
|
246 else |
|
247 { |
|
248 if (iVerbose) |
|
249 { |
|
250 Printf(_L("Adding '%S'\r\n"), &aFile); |
|
251 } |
|
252 aZipArchive.AddFileL(aFile); |
|
253 } |
|
254 } |
|
255 |
|
256 |
|
257 // |
|
258 // DECOMPRESSION FUNCTIONS |
|
259 // |
|
260 |
|
261 // |
|
262 // CCmdZip::ExpandArchiveL |
|
263 // determine which zip format to use and go ahead & expand the archive |
|
264 // |
|
265 void CCmdZip::ExpandArchiveL() |
|
266 { |
|
267 if (iCompressionType == EGZip) |
|
268 { |
|
269 ExpandGzArchiveL(); |
|
270 } |
|
271 else |
|
272 { |
|
273 ExpandZipArchiveL(); |
|
274 } |
|
275 } |
|
276 |
|
277 // |
|
278 // CCmdZip::ExpandGzArchiveL |
|
279 // unzip an existing gzip compressed file |
|
280 // |
|
281 void CCmdZip::ExpandGzArchiveL() |
|
282 { |
|
283 // open the destination file, determine where it goes |
|
284 RFile newFile; |
|
285 TFileName2 dest(iUnzipPath); |
|
286 if (iVerbose) |
|
287 { |
|
288 Printf(_L("Opening\t\t\'%S\'\r\n"), &iArchive); |
|
289 } |
|
290 if (iArchive.Ext().CompareF(KGzExtension) != 0) |
|
291 { |
|
292 LeaveIfErr(KErrArgument, _L("Compressed file must have '.gz' extension.")); |
|
293 } |
|
294 dest.AppendComponentL(iArchive.Name()); |
|
295 TInt err = Fs().MkDirAll(dest); |
|
296 if ((err != KErrNone) && (err != KErrAlreadyExists)) |
|
297 { |
|
298 LeaveIfErr(err, _L("Couldn't create path '%S'"), &dest); |
|
299 } |
|
300 User::LeaveIfError(newFile.Replace(Fs(), dest, EFileStream | EFileRead | EFileShareAny)); |
|
301 CleanupClosePushL(newFile); |
|
302 |
|
303 // inflate the compressed file |
|
304 CEZGZipToFile* zip = CEZGZipToFile::NewLC(Fs(), iArchive, newFile); |
|
305 while (zip->InflateL()) |
|
306 { |
|
307 // do nothing |
|
308 } |
|
309 if (iVerbose) |
|
310 { |
|
311 Printf(_L("Inflating '%S'\r\n"), &dest); |
|
312 } |
|
313 CleanupStack::PopAndDestroy(2); // zip, newFile |
|
314 } |
|
315 |
|
316 // |
|
317 // CCmdZip::ExpandZipArchiveL |
|
318 // Unzip an existing archive iterating through each member file contained within the archive |
|
319 // |
|
320 void CCmdZip::ExpandZipArchiveL() |
|
321 { |
|
322 if (iVerbose) |
|
323 { |
|
324 Printf(_L("Opening\t\t\'%S\'\r\n"), &iArchive); |
|
325 } |
|
326 CZipFile* zip = CZipFile::NewL(Fs(), iArchive); |
|
327 CleanupStack::PushL(zip); |
|
328 CZipFileMemberIterator* zipIterator = zip->GetMembersL(); |
|
329 CleanupStack::PushL(zipIterator); |
|
330 CZipFileMember* zipMember = zipIterator->NextL(); |
|
331 while (zipMember) |
|
332 { |
|
333 CleanupStack::PushL(zipMember); |
|
334 ExtractZipFileL(*zip, *zipMember); |
|
335 CleanupStack::PopAndDestroy(zipMember); |
|
336 zipMember = zipIterator->NextL(); |
|
337 } |
|
338 CleanupStack::PopAndDestroy(2); // zipIterator, zip |
|
339 } |
|
340 |
|
341 // |
|
342 // CCmdZip::ExtractZipFileL |
|
343 // extracts a single file from within the zip archive |
|
344 // |
|
345 void CCmdZip::ExtractZipFileL(CZipFile& aZip, const CZipFileMember& aMember) |
|
346 { |
|
347 // prep. the stream |
|
348 RZipFileMemberReaderStream* readStream; |
|
349 aZip.GetInputStreamL(&aMember, readStream); |
|
350 CleanupStack::PushL(readStream); |
|
351 // prep. the destination file. |
|
352 // note if iUnzipPath is not specified, it'll stuff the extracted file in the current directory from which fzip.exe runs |
|
353 RFile newFile; |
|
354 TFileName2 dest(iUnzipPath); |
|
355 dest.AppendComponentL(*aMember.Name()); |
|
356 TInt err = Fs().MkDirAll(dest); |
|
357 if ((err != KErrNone) && (err != KErrAlreadyExists)) |
|
358 { |
|
359 User::Leave(err); |
|
360 } |
|
361 User::LeaveIfError(newFile.Replace(Fs(), dest, EFileShareExclusive)); |
|
362 CleanupClosePushL(newFile); |
|
363 if (iVerbose) |
|
364 { |
|
365 Printf(_L("Inflating '%S'\r\n\tcrc: 0x%x\r\n\tcompressed size: %d\r\n\tuncompressed size: %d\r\n"), &dest, aMember.CRC32(), aMember.CompressedSize(), aMember.UncompressedSize()); |
|
366 } |
|
367 |
|
368 // stream from the zip archive member into the destination file |
|
369 TInt bytesRead = 0; |
|
370 TInt length = KDefaultZipBufferLength; // 32Kb |
|
371 if (aMember.UncompressedSize() < KDefaultZipBufferLength) |
|
372 { |
|
373 length = aMember.UncompressedSize(); |
|
374 } |
|
375 HBufC8* data = HBufC8::NewLC(length); |
|
376 TPtr8 ptr = data->Des(); |
|
377 do |
|
378 { |
|
379 User::LeaveIfError(readStream->Read(ptr, length)); |
|
380 User::LeaveIfError(newFile.Write(ptr)); |
|
381 bytesRead += length; |
|
382 if ((aMember.UncompressedSize() - bytesRead) < KDefaultZipBufferLength) |
|
383 { |
|
384 length = aMember.UncompressedSize() - bytesRead; |
|
385 } |
|
386 } while (length > 0); |
|
387 |
|
388 // cleanup |
|
389 CleanupStack::PopAndDestroy(3); // data, newfile, readstream |
|
390 } |
|
391 |
|
392 |
|
393 EXE_BOILER_PLATE(CCmdZip) |