diff -r 8df58d8c99e8 -r b3ffff030d5c commands/base64/base64.cpp --- /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 +#include + +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 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 inputBuf; + TBuf 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); + } + }