diff -r 000000000000 -r 7f656887cf89 commands/fzip/fzip.cpp --- /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 +#include +#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)