commands/fzip/fzip.cpp
changeset 0 7f656887cf89
child 31 d0e1c40de386
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/commands/fzip/fzip.cpp	Wed Jun 23 15:52:26 2010 +0100
@@ -0,0 +1,393 @@
+// fzip.cpp
+// 
+// Copyright (c) 2008 - 2010 Accenture. All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of the "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+// 
+// Initial Contributors:
+// Accenture - Initial contribution
+//
+
+#include <zipfile.h>
+#include <ezgzip.h>
+#include "fzip.h"
+
+_LIT(KGzExtension, ".gz");
+
+CCommandBase* CCmdZip::NewLC()
+	{
+	CCmdZip* self = new (ELeave) CCmdZip();
+	CleanupStack::PushL(self);
+	self->BaseConstructL();
+	return self;
+	}
+
+CCmdZip::~CCmdZip()
+	{
+	if (iFileToZip.Count() > 0)
+		iFileToZip.Close();
+	}
+	
+CCmdZip::CCmdZip() : CCommandBase(CCommandBase::EManualComplete)
+	{
+	}
+
+const TDesC& CCmdZip::Name() const
+	{	
+	_LIT(KName, "fzip");
+	return KName;
+	}
+
+void CCmdZip::DoRunL()
+	{
+	FsL();
+	if (iUnzip)
+		{
+		if (!iOptions.IsPresent(&iUnzipPath))
+			{
+			iUnzipPath = Env().Pwd();
+			}
+
+		if (iVerbose)
+			{
+			// command-line sanity checks
+			if (iFileToZip.Count() > 0)
+				{
+				PrintWarning(_L("Ignoring \'-f\' file option."));
+				}
+			if (iRecurse)
+				{
+				PrintWarning(_L("Ignoring \'-r\' recurse option."));
+				}
+			}
+		TRAPL(ExpandArchiveL(), _L("Couldn't expand archive"));
+		}
+	else
+		{
+		if (iVerbose)
+			{
+			// command-line sanity checks
+			if (iUnzipPath.Length() > 0)
+				{
+				PrintWarning(_L("Ignoring '-d' directory option."));	
+				}
+			}
+		if (iFileToZip.Count() == 0)
+			{
+			PrintError(KErrArgument, _L("Use '-f' to specify source files."));
+			User::Leave(KErrArgument);
+			}
+		TRAPD(err, CreateArchiveL());
+		if (err != KErrNone)
+			{
+			PrintError(err, _L("Couldn't create archive"));
+			Fs().Delete(iArchive); // ignore error
+			User::Leave(err);
+			}
+		}
+	if (iVerbose)
+		{
+		Printf(_L("Done\r\n"));	
+		}
+	Complete(KErrNone);
+	}
+	
+void CCmdZip::ArgumentsL(RCommandArgumentList& aArguments)
+	{
+	_LIT(KArg1, "archive");
+	aArguments.AppendFileNameL(iArchive, KArg1);
+	}
+
+void CCmdZip::OptionsL(RCommandOptionList& aOptions)
+	{
+	_LIT(KOptVerbose, "verbose");
+	aOptions.AppendBoolL(iVerbose, KOptVerbose);
+
+	_LIT(KOptUnzip, "unzip");
+	aOptions.AppendBoolL(iUnzip, KOptUnzip);
+
+	_LIT(KOptDirectory, "directory");
+	aOptions.AppendFileNameL(iUnzipPath, KOptDirectory);
+
+	_LIT(KOptRecurse, "recurse");
+	aOptions.AppendBoolL(iRecurse, KOptRecurse);
+
+	_LIT(KOptSource, "file");
+	aOptions.AppendFileNameL(iFileToZip, KOptSource);
+
+	_LIT(KOptCompressionType, "compression-type");
+	aOptions.AppendEnumL((TInt&)iCompressionType, KOptCompressionType);
+	}
+
+
+//
+// COMPRESSION FUNCTIONS
+//
+
+//
+// CCmdZip::CreateArchiveL
+// determine which zip format to use and go ahead & create the archive
+//
+void CCmdZip::CreateArchiveL()
+	{
+	if (iCompressionType == EGZip)
+		{
+		CreateGzArchiveL();
+		}
+	else
+		{
+		CreateZipArchiveL();
+		}
+	}
+
+//
+// CCmdZip::CreateGzArchiveL
+// create an archive, zipping up all the specified files
+//
+void CCmdZip::CreateGzArchiveL()
+	{
+	if (iRecurse)
+		{
+		LeaveIfErr(KErrArgument, _L("GNU Zip format does not support recursion"));
+		}
+
+	if (iFileToZip.Count() > 1)
+		{
+		LeaveIfErr(KErrArgument, _L("GNU Zip format can only handle a single file"));
+		}
+
+	if (iArchive.Length() == 0)
+		{
+		iArchive = iFileToZip[0];
+		iArchive.Append(KGzExtension);
+		}
+
+	RFile input;
+	if (iVerbose)
+		{
+		Printf(_L("Creating '%S'\r\n"), &iArchive);
+		}
+
+	// open the input file
+	User::LeaveIfError(input.Open(Fs(), iFileToZip[0], EFileStream | EFileRead | EFileShareAny));
+	CleanupClosePushL(input);
+
+	CEZFileToGZip* zip = CEZFileToGZip::NewLC(Fs(), iArchive, input);
+	while (zip->DeflateL())
+		{
+		// do nothing
+		}
+	if (iVerbose)
+		{
+		Printf(_L("Deflating '%S'\r\n"), &iFileToZip[0]);
+		}
+
+	CleanupStack::PopAndDestroy(2); // zip, input
+	}
+
+//
+// CCmdZip::CreateZipArchiveL
+// zip format archive creation
+//
+void CCmdZip::CreateZipArchiveL()
+	{
+	CZipItUp* zipArchive = CZipItUp::NewLC(Fs(), iArchive);
+	for (TInt ii = 0 ; ii < iFileToZip.Count() ; ii++)
+		{
+		TFileName2& fileName = iFileToZip[ii];
+		fileName.SetTypeL(Fs());
+		AddFileL(*zipArchive, fileName);
+		}
+	zipArchive->CreateZipL();
+	if (iVerbose)
+		{
+		Printf(_L("Created '%S'\r\n"), &iArchive);
+		}
+	CleanupStack::PopAndDestroy(); // zipArchive 
+	}
+
+//
+// CCmdZip::AddFileL
+// examines a file for wildcards, directories/recursion etc
+// if it finds an actual file, it'll add it to the zip archive
+// recursive function
+//
+void CCmdZip::AddFileL(CZipItUp& aZipArchive, const TFileName2& aFile)
+	{
+	if (aFile.IsDir())
+		{
+		CDir* dir;
+		LeaveIfErr(Fs().GetDir(aFile, KEntryAttMatchMask, EDirsLast, dir), _L("Unable to read directory '%S'"), &aFile);
+		CleanupStack::PushL(dir);
+		for (TInt ii = 0 ; ii < dir->Count() ; ii++)
+			{
+			const TEntry& entry = (*dir)[ii];
+			TFileName2* newFile = new(ELeave) TFileName2(entry.iName);
+			CleanupStack::PushL(newFile);
+			newFile->MakeAbsoluteL(aFile.DriveAndPath());
+			newFile->SetTypeL(Fs());
+			if (newFile->IsDir())
+				{
+				if (iRecurse)
+					{
+					AddFileL(aZipArchive, *newFile);
+					}
+				}
+			else
+				{
+				AddFileL(aZipArchive, *newFile);
+				}
+			CleanupStack::PopAndDestroy(newFile);
+			}
+		CleanupStack::PopAndDestroy(dir);
+		}
+	else
+		{
+		if (iVerbose)
+			{
+			Printf(_L("Adding '%S'\r\n"), &aFile);
+			}
+		aZipArchive.AddFileL(aFile);
+		}
+	}
+
+
+//
+// DECOMPRESSION FUNCTIONS
+//
+
+//
+// CCmdZip::ExpandArchiveL
+// determine which zip format to use and go ahead & expand the archive
+//
+void CCmdZip::ExpandArchiveL()
+	{
+	if (iCompressionType == EGZip)
+		{
+		ExpandGzArchiveL();
+		}
+	else
+		{
+		ExpandZipArchiveL();
+		}
+	}
+
+//
+// CCmdZip::ExpandGzArchiveL
+// unzip an existing gzip compressed file
+//
+void CCmdZip::ExpandGzArchiveL()
+	{
+	// open the destination file, determine where it goes
+	RFile newFile;
+	TFileName2 dest(iUnzipPath);
+	if (iVerbose)
+		{
+		Printf(_L("Opening\t\t\'%S\'\r\n"), &iArchive);
+		}
+	if (iArchive.Ext().CompareF(KGzExtension) != 0)
+		{
+		LeaveIfErr(KErrArgument, _L("Compressed file must have '.gz' extension."));
+		}
+	dest.AppendComponentL(iArchive.Name());
+	TInt err = Fs().MkDirAll(dest);
+	if ((err != KErrNone) && (err != KErrAlreadyExists))
+		{
+		LeaveIfErr(err, _L("Couldn't create path '%S'"), &dest);
+		}
+	User::LeaveIfError(newFile.Replace(Fs(), dest, EFileStream | EFileRead | EFileShareAny));
+	CleanupClosePushL(newFile);
+
+	// inflate the compressed file
+	CEZGZipToFile* zip = CEZGZipToFile::NewLC(Fs(), iArchive, newFile);
+	while (zip->InflateL())
+		{
+		// do nothing
+		}
+	if (iVerbose)
+		{
+		Printf(_L("Inflating '%S'\r\n"), &dest);
+		}
+	CleanupStack::PopAndDestroy(2); // zip, newFile
+	}
+
+//
+// CCmdZip::ExpandZipArchiveL
+// Unzip an existing archive iterating through each member file contained within the archive
+//
+void CCmdZip::ExpandZipArchiveL()
+	{
+	if (iVerbose)
+		{
+		Printf(_L("Opening\t\t\'%S\'\r\n"), &iArchive);
+		}
+	CZipFile* zip = CZipFile::NewL(Fs(), iArchive);
+	CleanupStack::PushL(zip);
+	CZipFileMemberIterator* zipIterator = zip->GetMembersL();
+	CleanupStack::PushL(zipIterator);
+	CZipFileMember* zipMember = zipIterator->NextL();
+	while (zipMember)
+		{
+		CleanupStack::PushL(zipMember);
+		ExtractZipFileL(*zip, *zipMember);
+		CleanupStack::PopAndDestroy(zipMember);
+		zipMember = zipIterator->NextL();
+		}
+	CleanupStack::PopAndDestroy(2); // zipIterator, zip
+	}
+	
+//
+// CCmdZip::ExtractZipFileL
+// extracts a single file from within the zip archive
+//
+void CCmdZip::ExtractZipFileL(CZipFile& aZip, const CZipFileMember& aMember)
+	{
+	// prep. the stream
+	RZipFileMemberReaderStream* readStream;
+	aZip.GetInputStreamL(&aMember, readStream);
+	CleanupStack::PushL(readStream);
+	// prep. the destination file. 
+	// note if iUnzipPath is not specified, it'll stuff the extracted file in the current directory from which fzip.exe runs
+	RFile newFile;
+	TFileName2 dest(iUnzipPath);
+	dest.AppendComponentL(*aMember.Name());
+	TInt err = Fs().MkDirAll(dest);
+	if ((err != KErrNone) && (err != KErrAlreadyExists))
+		{
+		User::Leave(err);
+		}
+	User::LeaveIfError(newFile.Replace(Fs(), dest, EFileShareExclusive));
+	CleanupClosePushL(newFile);
+	if (iVerbose)
+		{
+		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());
+		}
+		
+	// stream from the zip archive member into the destination file
+	TInt bytesRead = 0;
+	TInt length = KDefaultZipBufferLength; // 32Kb
+	if (aMember.UncompressedSize() < KDefaultZipBufferLength)
+		{
+		length = aMember.UncompressedSize();
+		}
+	HBufC8* data = HBufC8::NewLC(length);
+	TPtr8 ptr = data->Des();
+	do
+		{
+		User::LeaveIfError(readStream->Read(ptr, length));
+		User::LeaveIfError(newFile.Write(ptr));
+		bytesRead += length;
+		if ((aMember.UncompressedSize() - bytesRead) < KDefaultZipBufferLength)
+			{
+			length = aMember.UncompressedSize() - bytesRead;
+			}
+		} while (length > 0);
+		
+	// cleanup
+	CleanupStack::PopAndDestroy(3); // data, newfile, readstream
+	}
+
+	
+EXE_BOILER_PLATE(CCmdZip)