Added ENotifyKeypresses and ECaptureCtrlC flags to CCommandBase.
Commands can now get keypresses and handle ctrl-C via callbacks instead of having to implement custom active objects. As part of this extended the CCommandBase extension interface to MCommandExtensionsV2 for the new virtual functions KeyPressed(TUint aKeyCode, TUint aModifiers) and CtrlCPressed(). sudo now cleans up correctly by using ECaptureCtrlC.
// 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."));
}
}
ExpandArchiveL();
}
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 = NULL;
TRAPL(zip = CZipFile::NewL(Fs(), iArchive), _L("Couldn't create CZipFile for %S"), &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 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))
{
LeaveIfErr(err, _L("Couldn't create directory for file %S"), &dest);
}
if (aMember.Name()->Right(1) == _L("\\")) return; // It's a directory entry, nothing more to be done
// prep. the stream
RZipFileMemberReaderStream* readStream;
aZip.GetInputStreamL(&aMember, readStream);
CleanupStack::PushL(readStream);
LeaveIfErr(newFile.Replace(Fs(), dest, EFileShareExclusive), _L("Couldn't create file %S"), &dest);
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
{
LeaveIfErr(readStream->Read(ptr, length), _L("Error reading from zip stream"));
LeaveIfErr(newFile.Write(ptr), _L("Error writing to file %S"), &dest);
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)