commands/base64/base64.cpp
changeset 95 b3ffff030d5c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/commands/base64/base64.cpp	Thu Oct 28 16:54:54 2010 +0100
@@ -0,0 +1,433 @@
+// base64.cpp
+//
+// Copyright (c) 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 <fshell/ioutils.h>
+#include <fshell/common.mmh>
+
+using namespace IoUtils;
+
+const TInt KBlockSize = 512;
+const TInt KLineLength = 76;
+const TUint8 KBase64Chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+const TUint8 KPadCharacter = '=';
+
+const TUint8 KInvBase64[] =
+	{
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x3e,
+	0x0,
+	0x0,
+	0x0,
+	0x3f,
+	0x34,
+	0x35,
+	0x36,
+	0x37,
+	0x38,
+	0x39,
+	0x3a,
+	0x3b,
+	0x3c,
+	0x3d,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x1,
+	0x2,
+	0x3,
+	0x4,
+	0x5,
+	0x6,
+	0x7,
+	0x8,
+	0x9,
+	0xa,
+	0xb,
+	0xc,
+	0xd,
+	0xe,
+	0xf,
+	0x10,
+	0x11,
+	0x12,
+	0x13,
+	0x14,
+	0x15,
+	0x16,
+	0x17,
+	0x18,
+	0x19,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x1a,
+	0x1b,
+	0x1c,
+	0x1d,
+	0x1e,
+	0x1f,
+	0x20,
+	0x21,
+	0x22,
+	0x23,
+	0x24,
+	0x25,
+	0x26,
+	0x27,
+	0x28,
+	0x29,
+	0x2a,
+	0x2b,
+	0x2c,
+	0x2d,
+	0x2e,
+	0x2f,
+	0x30,
+	0x31,
+	0x32,
+	0x33
+	};
+
+_LIT(KNewLine, "\r\n");
+_LIT(KCr, "\r");
+_LIT(KLf, "\n");
+
+
+class CCmdBase64 : public CCommandBase
+	{
+public:
+	static CCommandBase* NewLC();
+	~CCmdBase64();
+private:
+	CCmdBase64();
+	void DecodeL();
+	void EncodeL();
+private: // From CCommandBase.
+	virtual const TDesC& Name() const;
+	virtual void DoRunL();
+	virtual void ArgumentsL(RCommandArgumentList& aArguments);
+	virtual void OptionsL(RCommandOptionList& aOptions);
+private:
+	enum 
+		{
+		EDecode,
+		EEncode
+		} iOperation;
+	TFileName2 iFileName;
+	TBool iVerbose;
+	TBool iOverwrite;
+	};
+
+EXE_BOILER_PLATE(CCmdBase64)
+
+CCommandBase* CCmdBase64::NewLC()
+	{
+	CCmdBase64* self = new(ELeave) CCmdBase64();
+	CleanupStack::PushL(self);
+	self->BaseConstructL();
+	return self;
+	}
+
+CCmdBase64::~CCmdBase64()
+	{
+	}
+
+CCmdBase64::CCmdBase64()
+	{
+	}
+
+void CCmdBase64::DecodeL()
+	{
+	if (!iOverwrite)
+		{
+		LeaveIfFileExists(iFileName);
+		}
+
+	User::LeaveIfError(Stdin().CaptureAllKeys()); // To iosrv buffering incoming data if we're not keeping up.
+	Stdin().SetReadModeL(RIoReadHandle::ELine);
+
+	RFile file;
+	LeaveIfErr(file.Replace(FsL(), iFileName, EFileWrite | EFileStream), _L("Unabled to open '%S' for writing"), &iFileName);
+	CleanupClosePushL(file);
+
+	TBuf<KLineLength + 2> lineBuf;
+	TBuf8<(KLineLength / 4) * 3> outputBuf;
+	TBool finished(EFalse);
+	TBool started(EFalse);
+	while (!finished)
+		{
+		TInt err = Stdin().Read(lineBuf);
+		if (err == KErrNone)
+			{
+			if (iVerbose)
+				{
+				Printf(_L("Read %d chars:\r\n'%S'\r\n"), lineBuf.Length(), &lineBuf);
+				}
+			if ((lineBuf == KNewLine) || (lineBuf == KCr) || (lineBuf == KLf))
+				{
+				if (started)
+					{
+					finished = ETrue;
+					}
+				}
+			else
+				{
+				if (lineBuf.Right(2) == KNewLine)
+					{
+					lineBuf.SetLength(lineBuf.Length() - 2);
+					}
+				if ((lineBuf.Right(1) == KCr) || (lineBuf.Right(1) == KLf))
+					{
+					lineBuf.SetLength(lineBuf.Length() - 1);
+					}
+				const TInt lineLength = lineBuf.Length();
+				if ((lineLength % 4) > 0)
+					{
+					LeaveIfErr(KErrArgument, _L("Invalid base 64 encoded line (not a multiple of 4 characters in length):\r\n%S\r\n"), &lineBuf);
+					}
+
+				started = ETrue;
+				outputBuf.Zero();
+
+				for (TInt i = 0; i < lineLength; i += 4)
+					{
+					TInt n = ((TInt)KInvBase64[lineBuf[i]] << 18) + ((TInt)KInvBase64[lineBuf[i + 1]] << 12) + ((TInt)KInvBase64[lineBuf[i + 2]] << 6) + (TInt)KInvBase64[lineBuf[i + 3]];
+
+					if (lineBuf[i + 2] == KPadCharacter)
+						{
+						// Two pad characters
+						outputBuf.Append((n >> 16) & 0x000000FF);
+						}
+					else if (lineBuf[i + 3] == KPadCharacter)
+						{
+						// One pad character
+						outputBuf.Append((n >> 16) & 0x000000FF);
+						outputBuf.Append((n >> 8) & 0x000000FF);
+						}
+					else
+						{
+						outputBuf.Append((n >> 16) & 0x000000FF);
+						outputBuf.Append((n >> 8) & 0x000000FF);
+						outputBuf.Append(n & 0x000000FF);
+						}
+					}
+
+				LeaveIfErr(file.Write(outputBuf), _L("Failed to write to '%S'"), &iFileName);
+				if (iVerbose)
+					{
+					Printf(_L("Wrote %d bytes to '%S'\r\n"), outputBuf.Length(), &iFileName);
+					}
+				}
+			}
+		else if (err == KErrEof)
+			{
+			finished = ETrue;
+			}
+		else
+			{
+			LeaveIfErr(err, _L("Couldn't read STDIN"));
+			}
+		}
+
+	CleanupStack::PopAndDestroy(&file);
+	}
+
+void CCmdBase64::EncodeL()
+	{
+	LeaveIfFileNotFound(iFileName);
+
+	RFile file;
+	User::LeaveIfError(file.Open(FsL(), iFileName, EFileRead | EFileStream));
+	CleanupClosePushL(file);
+
+	TBuf8<KBlockSize> inputBuf;
+	TBuf<KLineLength + 2> outputBuf;
+	TBool finished(EFalse);
+	while (!finished)
+		{
+		TPtr8 ptr((TUint8*)inputBuf.Ptr() + inputBuf.Length(), 0, inputBuf.MaxLength() - inputBuf.Length());
+		LeaveIfErr(file.Read(ptr), _L("Couldn't read from '%S'"), &iFileName);
+
+		if (ptr.Length() > 0)
+			{
+			inputBuf.SetLength(inputBuf.Length() + ptr.Length());
+			const TInt inputBufLength = inputBuf.Length();
+			const TInt excess = inputBufLength % 3;
+			const TInt bytesToProcess = inputBufLength - excess;
+
+			for (TInt i = 0; i < bytesToProcess; i += 3)
+				{
+				// Combine the next three bytes into a 24 bit number.
+				TInt n = ((TInt)inputBuf[i] << 16) + ((TInt)inputBuf[i + 1] << 8) + (TInt)inputBuf[i + 2];
+
+				// Split the 24-bit number into four 6-bit numbers.
+				TUint8 n0 = (TUint8)(n >> 18) & 0x3F;
+				TUint8 n1 = (TUint8)(n >> 12) & 0x3F;
+				TUint8 n2 = (TUint8)(n >> 6) & 0x3F;
+				TUint8 n3 = (TUint8)n & 0x3F;
+
+				// Buffer the base64 encoded equivalent.
+				outputBuf.Append(KBase64Chars[n0]);
+				outputBuf.Append(KBase64Chars[n1]);
+				outputBuf.Append(KBase64Chars[n2]);
+				outputBuf.Append(KBase64Chars[n3]);
+
+				// Flush output buffer if it's full.
+				if (outputBuf.Length() == KLineLength)
+					{
+					outputBuf.Append(KNewLine);
+					Write(outputBuf);
+					outputBuf.Zero();
+					}
+				}
+
+			inputBuf.Delete(0, inputBufLength - excess);
+			}
+		else
+			{
+			// Process what's left over in inputBuf from the previous successful read, padding as required.
+			const TInt inputBufLength = inputBuf.Length();
+			if (inputBufLength > 0)
+				{
+				TInt n = (TInt)inputBuf[0] << 16;
+				if (inputBufLength > 1)
+					{
+					n += (TInt)inputBuf[1] << 8;
+					if (inputBufLength > 2)
+						{
+						n += (TInt)inputBuf[2];
+						}
+					}
+
+				TUint8 n0 = (TUint8)(n >> 18) & 0x3F;
+				TUint8 n1 = (TUint8)(n >> 12) & 0x3F;
+				TUint8 n2 = (TUint8)(n >> 6) & 0x3F;
+				TUint8 n3 = (TUint8)n & 0x3F;
+
+				outputBuf.Append(KBase64Chars[n0]);
+				outputBuf.Append(KBase64Chars[n1]);
+				if (inputBufLength > 1)
+					{
+					outputBuf.Append(KBase64Chars[n2]);
+					if (inputBufLength > 2)
+						{
+						outputBuf.Append(KBase64Chars[n3]);
+						}
+					}
+
+				for (TInt i = inputBufLength; i < 3; ++i)
+					{
+					outputBuf.Append('=');
+					}
+				}
+
+			if (outputBuf.Length() > 0)
+				{
+				outputBuf.Append(KNewLine);
+				Write(outputBuf);
+				}
+
+			finished = ETrue;
+			}
+		}
+
+	CleanupStack::PopAndDestroy(&file);
+	}
+
+const TDesC& CCmdBase64::Name() const
+	{
+	_LIT(KName, "base64");	
+	return KName;
+	}
+
+void CCmdBase64::ArgumentsL(RCommandArgumentList& aArguments)
+	{
+	_LIT(KArgOperation, "operation");
+	aArguments.AppendEnumL((TInt&)iOperation, KArgOperation);
+
+	_LIT(KArgFilename, "filename");
+	aArguments.AppendFileNameL(iFileName, KArgFilename);
+	}
+
+void CCmdBase64::OptionsL(RCommandOptionList& aOptions)
+	{
+	_LIT(KOptVerbose, "verbose");
+	aOptions.AppendBoolL(iVerbose, KOptVerbose);
+
+	_LIT(KOptOverwrite, "overwrite");
+	aOptions.AppendBoolL(iOverwrite, KOptOverwrite);
+	}
+
+void CCmdBase64::DoRunL()
+	{
+	switch (iOperation)
+		{
+		case EDecode:
+			DecodeL();
+			break;
+		case EEncode:
+			EncodeL();
+			break;
+		default:
+			ASSERT(EFalse);
+		}
+	}