commands/fzip/fzip.cpp
changeset 0 7f656887cf89
child 31 d0e1c40de386
equal deleted inserted replaced
-1:000000000000 0:7f656887cf89
       
     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)