commands/base64/base64.cpp
changeset 78 b3ffff030d5c
equal deleted inserted replaced
77:8df58d8c99e8 78:b3ffff030d5c
       
     1 // base64.cpp
       
     2 //
       
     3 // Copyright (c) 2010 Accenture. All rights reserved.
       
     4 // This component and the accompanying materials are made available
       
     5 // under the terms of the "Eclipse Public License v1.0"
       
     6 // which accompanies this distribution, and is available
       
     7 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 // 
       
     9 // Initial Contributors:
       
    10 // Accenture - Initial contribution
       
    11 //
       
    12 
       
    13 #include <fshell/ioutils.h>
       
    14 #include <fshell/common.mmh>
       
    15 
       
    16 using namespace IoUtils;
       
    17 
       
    18 const TInt KBlockSize = 512;
       
    19 const TInt KLineLength = 76;
       
    20 const TUint8 KBase64Chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
       
    21 const TUint8 KPadCharacter = '=';
       
    22 
       
    23 const TUint8 KInvBase64[] =
       
    24 	{
       
    25 	0x0,
       
    26 	0x0,
       
    27 	0x0,
       
    28 	0x0,
       
    29 	0x0,
       
    30 	0x0,
       
    31 	0x0,
       
    32 	0x0,
       
    33 	0x0,
       
    34 	0x0,
       
    35 	0x0,
       
    36 	0x0,
       
    37 	0x0,
       
    38 	0x0,
       
    39 	0x0,
       
    40 	0x0,
       
    41 	0x0,
       
    42 	0x0,
       
    43 	0x0,
       
    44 	0x0,
       
    45 	0x0,
       
    46 	0x0,
       
    47 	0x0,
       
    48 	0x0,
       
    49 	0x0,
       
    50 	0x0,
       
    51 	0x0,
       
    52 	0x0,
       
    53 	0x0,
       
    54 	0x0,
       
    55 	0x0,
       
    56 	0x0,
       
    57 	0x0,
       
    58 	0x0,
       
    59 	0x0,
       
    60 	0x0,
       
    61 	0x0,
       
    62 	0x0,
       
    63 	0x0,
       
    64 	0x0,
       
    65 	0x0,
       
    66 	0x0,
       
    67 	0x0,
       
    68 	0x3e,
       
    69 	0x0,
       
    70 	0x0,
       
    71 	0x0,
       
    72 	0x3f,
       
    73 	0x34,
       
    74 	0x35,
       
    75 	0x36,
       
    76 	0x37,
       
    77 	0x38,
       
    78 	0x39,
       
    79 	0x3a,
       
    80 	0x3b,
       
    81 	0x3c,
       
    82 	0x3d,
       
    83 	0x0,
       
    84 	0x0,
       
    85 	0x0,
       
    86 	0x0,
       
    87 	0x0,
       
    88 	0x0,
       
    89 	0x0,
       
    90 	0x0,
       
    91 	0x1,
       
    92 	0x2,
       
    93 	0x3,
       
    94 	0x4,
       
    95 	0x5,
       
    96 	0x6,
       
    97 	0x7,
       
    98 	0x8,
       
    99 	0x9,
       
   100 	0xa,
       
   101 	0xb,
       
   102 	0xc,
       
   103 	0xd,
       
   104 	0xe,
       
   105 	0xf,
       
   106 	0x10,
       
   107 	0x11,
       
   108 	0x12,
       
   109 	0x13,
       
   110 	0x14,
       
   111 	0x15,
       
   112 	0x16,
       
   113 	0x17,
       
   114 	0x18,
       
   115 	0x19,
       
   116 	0x0,
       
   117 	0x0,
       
   118 	0x0,
       
   119 	0x0,
       
   120 	0x0,
       
   121 	0x0,
       
   122 	0x1a,
       
   123 	0x1b,
       
   124 	0x1c,
       
   125 	0x1d,
       
   126 	0x1e,
       
   127 	0x1f,
       
   128 	0x20,
       
   129 	0x21,
       
   130 	0x22,
       
   131 	0x23,
       
   132 	0x24,
       
   133 	0x25,
       
   134 	0x26,
       
   135 	0x27,
       
   136 	0x28,
       
   137 	0x29,
       
   138 	0x2a,
       
   139 	0x2b,
       
   140 	0x2c,
       
   141 	0x2d,
       
   142 	0x2e,
       
   143 	0x2f,
       
   144 	0x30,
       
   145 	0x31,
       
   146 	0x32,
       
   147 	0x33
       
   148 	};
       
   149 
       
   150 _LIT(KNewLine, "\r\n");
       
   151 _LIT(KCr, "\r");
       
   152 _LIT(KLf, "\n");
       
   153 
       
   154 
       
   155 class CCmdBase64 : public CCommandBase
       
   156 	{
       
   157 public:
       
   158 	static CCommandBase* NewLC();
       
   159 	~CCmdBase64();
       
   160 private:
       
   161 	CCmdBase64();
       
   162 	void DecodeL();
       
   163 	void EncodeL();
       
   164 private: // From CCommandBase.
       
   165 	virtual const TDesC& Name() const;
       
   166 	virtual void DoRunL();
       
   167 	virtual void ArgumentsL(RCommandArgumentList& aArguments);
       
   168 	virtual void OptionsL(RCommandOptionList& aOptions);
       
   169 private:
       
   170 	enum 
       
   171 		{
       
   172 		EDecode,
       
   173 		EEncode
       
   174 		} iOperation;
       
   175 	TFileName2 iFileName;
       
   176 	TBool iVerbose;
       
   177 	TBool iOverwrite;
       
   178 	};
       
   179 
       
   180 EXE_BOILER_PLATE(CCmdBase64)
       
   181 
       
   182 CCommandBase* CCmdBase64::NewLC()
       
   183 	{
       
   184 	CCmdBase64* self = new(ELeave) CCmdBase64();
       
   185 	CleanupStack::PushL(self);
       
   186 	self->BaseConstructL();
       
   187 	return self;
       
   188 	}
       
   189 
       
   190 CCmdBase64::~CCmdBase64()
       
   191 	{
       
   192 	}
       
   193 
       
   194 CCmdBase64::CCmdBase64()
       
   195 	{
       
   196 	}
       
   197 
       
   198 void CCmdBase64::DecodeL()
       
   199 	{
       
   200 	if (!iOverwrite)
       
   201 		{
       
   202 		LeaveIfFileExists(iFileName);
       
   203 		}
       
   204 
       
   205 	User::LeaveIfError(Stdin().CaptureAllKeys()); // To iosrv buffering incoming data if we're not keeping up.
       
   206 	Stdin().SetReadModeL(RIoReadHandle::ELine);
       
   207 
       
   208 	RFile file;
       
   209 	LeaveIfErr(file.Replace(FsL(), iFileName, EFileWrite | EFileStream), _L("Unabled to open '%S' for writing"), &iFileName);
       
   210 	CleanupClosePushL(file);
       
   211 
       
   212 	TBuf<KLineLength + 2> lineBuf;
       
   213 	TBuf8<(KLineLength / 4) * 3> outputBuf;
       
   214 	TBool finished(EFalse);
       
   215 	TBool started(EFalse);
       
   216 	while (!finished)
       
   217 		{
       
   218 		TInt err = Stdin().Read(lineBuf);
       
   219 		if (err == KErrNone)
       
   220 			{
       
   221 			if (iVerbose)
       
   222 				{
       
   223 				Printf(_L("Read %d chars:\r\n'%S'\r\n"), lineBuf.Length(), &lineBuf);
       
   224 				}
       
   225 			if ((lineBuf == KNewLine) || (lineBuf == KCr) || (lineBuf == KLf))
       
   226 				{
       
   227 				if (started)
       
   228 					{
       
   229 					finished = ETrue;
       
   230 					}
       
   231 				}
       
   232 			else
       
   233 				{
       
   234 				if (lineBuf.Right(2) == KNewLine)
       
   235 					{
       
   236 					lineBuf.SetLength(lineBuf.Length() - 2);
       
   237 					}
       
   238 				if ((lineBuf.Right(1) == KCr) || (lineBuf.Right(1) == KLf))
       
   239 					{
       
   240 					lineBuf.SetLength(lineBuf.Length() - 1);
       
   241 					}
       
   242 				const TInt lineLength = lineBuf.Length();
       
   243 				if ((lineLength % 4) > 0)
       
   244 					{
       
   245 					LeaveIfErr(KErrArgument, _L("Invalid base 64 encoded line (not a multiple of 4 characters in length):\r\n%S\r\n"), &lineBuf);
       
   246 					}
       
   247 
       
   248 				started = ETrue;
       
   249 				outputBuf.Zero();
       
   250 
       
   251 				for (TInt i = 0; i < lineLength; i += 4)
       
   252 					{
       
   253 					TInt n = ((TInt)KInvBase64[lineBuf[i]] << 18) + ((TInt)KInvBase64[lineBuf[i + 1]] << 12) + ((TInt)KInvBase64[lineBuf[i + 2]] << 6) + (TInt)KInvBase64[lineBuf[i + 3]];
       
   254 
       
   255 					if (lineBuf[i + 2] == KPadCharacter)
       
   256 						{
       
   257 						// Two pad characters
       
   258 						outputBuf.Append((n >> 16) & 0x000000FF);
       
   259 						}
       
   260 					else if (lineBuf[i + 3] == KPadCharacter)
       
   261 						{
       
   262 						// One pad character
       
   263 						outputBuf.Append((n >> 16) & 0x000000FF);
       
   264 						outputBuf.Append((n >> 8) & 0x000000FF);
       
   265 						}
       
   266 					else
       
   267 						{
       
   268 						outputBuf.Append((n >> 16) & 0x000000FF);
       
   269 						outputBuf.Append((n >> 8) & 0x000000FF);
       
   270 						outputBuf.Append(n & 0x000000FF);
       
   271 						}
       
   272 					}
       
   273 
       
   274 				LeaveIfErr(file.Write(outputBuf), _L("Failed to write to '%S'"), &iFileName);
       
   275 				if (iVerbose)
       
   276 					{
       
   277 					Printf(_L("Wrote %d bytes to '%S'\r\n"), outputBuf.Length(), &iFileName);
       
   278 					}
       
   279 				}
       
   280 			}
       
   281 		else if (err == KErrEof)
       
   282 			{
       
   283 			finished = ETrue;
       
   284 			}
       
   285 		else
       
   286 			{
       
   287 			LeaveIfErr(err, _L("Couldn't read STDIN"));
       
   288 			}
       
   289 		}
       
   290 
       
   291 	CleanupStack::PopAndDestroy(&file);
       
   292 	}
       
   293 
       
   294 void CCmdBase64::EncodeL()
       
   295 	{
       
   296 	LeaveIfFileNotFound(iFileName);
       
   297 
       
   298 	RFile file;
       
   299 	User::LeaveIfError(file.Open(FsL(), iFileName, EFileRead | EFileStream));
       
   300 	CleanupClosePushL(file);
       
   301 
       
   302 	TBuf8<KBlockSize> inputBuf;
       
   303 	TBuf<KLineLength + 2> outputBuf;
       
   304 	TBool finished(EFalse);
       
   305 	while (!finished)
       
   306 		{
       
   307 		TPtr8 ptr((TUint8*)inputBuf.Ptr() + inputBuf.Length(), 0, inputBuf.MaxLength() - inputBuf.Length());
       
   308 		LeaveIfErr(file.Read(ptr), _L("Couldn't read from '%S'"), &iFileName);
       
   309 
       
   310 		if (ptr.Length() > 0)
       
   311 			{
       
   312 			inputBuf.SetLength(inputBuf.Length() + ptr.Length());
       
   313 			const TInt inputBufLength = inputBuf.Length();
       
   314 			const TInt excess = inputBufLength % 3;
       
   315 			const TInt bytesToProcess = inputBufLength - excess;
       
   316 
       
   317 			for (TInt i = 0; i < bytesToProcess; i += 3)
       
   318 				{
       
   319 				// Combine the next three bytes into a 24 bit number.
       
   320 				TInt n = ((TInt)inputBuf[i] << 16) + ((TInt)inputBuf[i + 1] << 8) + (TInt)inputBuf[i + 2];
       
   321 
       
   322 				// Split the 24-bit number into four 6-bit numbers.
       
   323 				TUint8 n0 = (TUint8)(n >> 18) & 0x3F;
       
   324 				TUint8 n1 = (TUint8)(n >> 12) & 0x3F;
       
   325 				TUint8 n2 = (TUint8)(n >> 6) & 0x3F;
       
   326 				TUint8 n3 = (TUint8)n & 0x3F;
       
   327 
       
   328 				// Buffer the base64 encoded equivalent.
       
   329 				outputBuf.Append(KBase64Chars[n0]);
       
   330 				outputBuf.Append(KBase64Chars[n1]);
       
   331 				outputBuf.Append(KBase64Chars[n2]);
       
   332 				outputBuf.Append(KBase64Chars[n3]);
       
   333 
       
   334 				// Flush output buffer if it's full.
       
   335 				if (outputBuf.Length() == KLineLength)
       
   336 					{
       
   337 					outputBuf.Append(KNewLine);
       
   338 					Write(outputBuf);
       
   339 					outputBuf.Zero();
       
   340 					}
       
   341 				}
       
   342 
       
   343 			inputBuf.Delete(0, inputBufLength - excess);
       
   344 			}
       
   345 		else
       
   346 			{
       
   347 			// Process what's left over in inputBuf from the previous successful read, padding as required.
       
   348 			const TInt inputBufLength = inputBuf.Length();
       
   349 			if (inputBufLength > 0)
       
   350 				{
       
   351 				TInt n = (TInt)inputBuf[0] << 16;
       
   352 				if (inputBufLength > 1)
       
   353 					{
       
   354 					n += (TInt)inputBuf[1] << 8;
       
   355 					if (inputBufLength > 2)
       
   356 						{
       
   357 						n += (TInt)inputBuf[2];
       
   358 						}
       
   359 					}
       
   360 
       
   361 				TUint8 n0 = (TUint8)(n >> 18) & 0x3F;
       
   362 				TUint8 n1 = (TUint8)(n >> 12) & 0x3F;
       
   363 				TUint8 n2 = (TUint8)(n >> 6) & 0x3F;
       
   364 				TUint8 n3 = (TUint8)n & 0x3F;
       
   365 
       
   366 				outputBuf.Append(KBase64Chars[n0]);
       
   367 				outputBuf.Append(KBase64Chars[n1]);
       
   368 				if (inputBufLength > 1)
       
   369 					{
       
   370 					outputBuf.Append(KBase64Chars[n2]);
       
   371 					if (inputBufLength > 2)
       
   372 						{
       
   373 						outputBuf.Append(KBase64Chars[n3]);
       
   374 						}
       
   375 					}
       
   376 
       
   377 				for (TInt i = inputBufLength; i < 3; ++i)
       
   378 					{
       
   379 					outputBuf.Append('=');
       
   380 					}
       
   381 				}
       
   382 
       
   383 			if (outputBuf.Length() > 0)
       
   384 				{
       
   385 				outputBuf.Append(KNewLine);
       
   386 				Write(outputBuf);
       
   387 				}
       
   388 
       
   389 			finished = ETrue;
       
   390 			}
       
   391 		}
       
   392 
       
   393 	CleanupStack::PopAndDestroy(&file);
       
   394 	}
       
   395 
       
   396 const TDesC& CCmdBase64::Name() const
       
   397 	{
       
   398 	_LIT(KName, "base64");	
       
   399 	return KName;
       
   400 	}
       
   401 
       
   402 void CCmdBase64::ArgumentsL(RCommandArgumentList& aArguments)
       
   403 	{
       
   404 	_LIT(KArgOperation, "operation");
       
   405 	aArguments.AppendEnumL((TInt&)iOperation, KArgOperation);
       
   406 
       
   407 	_LIT(KArgFilename, "filename");
       
   408 	aArguments.AppendFileNameL(iFileName, KArgFilename);
       
   409 	}
       
   410 
       
   411 void CCmdBase64::OptionsL(RCommandOptionList& aOptions)
       
   412 	{
       
   413 	_LIT(KOptVerbose, "verbose");
       
   414 	aOptions.AppendBoolL(iVerbose, KOptVerbose);
       
   415 
       
   416 	_LIT(KOptOverwrite, "overwrite");
       
   417 	aOptions.AppendBoolL(iOverwrite, KOptOverwrite);
       
   418 	}
       
   419 
       
   420 void CCmdBase64::DoRunL()
       
   421 	{
       
   422 	switch (iOperation)
       
   423 		{
       
   424 		case EDecode:
       
   425 			DecodeL();
       
   426 			break;
       
   427 		case EEncode:
       
   428 			EncodeL();
       
   429 			break;
       
   430 		default:
       
   431 			ASSERT(EFalse);
       
   432 		}
       
   433 	}