diff -r f5050f1da672 -r 04becd199f91 javaextensions/pim/framework/src.s60/pimbase64converter.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/javaextensions/pim/framework/src.s60/pimbase64converter.cpp Tue Apr 27 16:30:29 2010 +0300 @@ -0,0 +1,384 @@ +/* +* Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* This component and the accompanying materials are made available +* under the terms of "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: +* Nokia Corporation - initial contribution. +* +* Contributors: +* +* Description: Base64 coder and decoder. + * +*/ + + +// INCLUDE FILES +#include "pimbase64converter.h" +#include "pimcommon.h" +#include "pimpanics.h" +#include "logger.h" + +// CONSTANTS + +/** + * Six least significant bits. + */ +const TUint8 KSixLSBits = 63; // 00111111 + +/** + * Eight least significant bits. + */ +const TUint8 KEightLSBits = 255; // 11111111 + +/** + * Pad byte. + */ +const TUint8 KPadLetter = '='; + +/** + * A non-base64 letter. + * Can be used to denote an erroneous situation. + */ +const TUint8 KNonBase64Letter = 255; + +/** + * Byte array granularity. Byte arrays are usually quite large. + */ +const TInt KByteArrayGranularity = 24; + +#if 0 // Disabled to satisfy TCK, which expects no newlines +/** + * Recommended number of encoded characters per line. + */ +const TInt KNumEncodedCharsPerLine = 76; +#endif + +/** + * Base64 alphabet from RFC 2045. + * 64 characters, indexed from 0 to 63. The pad byte is not included + * in the array. + * + *
+ * Table 1: The Base64 Alphabet + * + * Value Encoding Value Encoding Value Encoding Value Encoding + * 0 A 17 R 34 i 51 z + * 1 B 18 S 35 j 52 0 + * 2 C 19 T 36 k 53 1 + * 3 D 20 U 37 l 54 2 + * 4 E 21 V 38 m 55 3 + * 5 F 22 W 39 n 56 4 + * 6 G 23 X 40 o 57 5 + * 7 H 24 Y 41 p 58 6 + * 8 I 25 Z 42 q 59 7 + * 9 J 26 a 43 r 60 8 + * 10 K 27 b 44 s 61 9 + * 11 L 28 c 45 t 62 + + * 12 M 29 d 46 u 63 / + * 13 N 30 e 47 v + * 14 O 31 f 48 w (pad) = + * 15 P 32 g 49 x + * 16 Q 33 h 50 y + * + *+ */ +const TUint8 KBase64Alphabet[64] = +{ + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', + 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', + + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', + 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', + + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/' +}; + +CPIMByteArray* PIMBase64Converter::EncodeBase64L(const CPIMByteArray& aSource) +{ + JELOG2(EPim); + CPIMByteArray* targetBytes = + new(ELeave) CPIMByteArray(KByteArrayGranularity); + CleanupStack::PushL(targetBytes); + + // Loop through the source array. + // + // Read an 8 bit byte on each iteration. Insert the byte to current + // quantum, shifting it's contents 8 bits left before insertion. + // When three bytes are read, append the bytes as four base64-encoded + // bytes to the target array. Then reset the quantum and start reading + // another three bytes. + // + // If less than three bytes could be read from the source array, + // Convert a partial quantum. If zero bytes were read, the encoding + // stops. If one or two bytes were read, pad bytes ('=') are appended + // after conversion to make it full four base64 bytes and encoding stops. + + TUint32 quantum = 0; + TInt numBytesInQuantum = 0; + const TInt numTotalSourceBytes = aSource.Count(); + TInt targetByteCount = 0; + + for (TInt i = 0; i < numTotalSourceBytes; i++) + { + TUint8 sourceByte = aSource[i]; // 8 raw, non-encoded bits + quantum <<= 8; + quantum |= sourceByte; + numBytesInQuantum++; + + if (numBytesInQuantum == 3) + { + // 24 bits in the quantum + EncodeQuantumL(quantum, *targetBytes, 3); + quantum = 0; + numBytesInQuantum = 0; + targetByteCount += 4; + } + +#if 0 // Disabled to satisfy TCK, which expects no newlines + // PIM API TCK does not accept newlines in output. + if ((targetByteCount> 0) && + ((targetByteCount % KNumEncodedCharsPerLine) == 0)) + { + targetBytes->AppendL('\n'); + } +#endif + } + + // 0, 8 or 16 bits in the quantum + EncodeQuantumL(quantum, *targetBytes, numBytesInQuantum); + + CleanupStack::Pop(targetBytes); + return targetBytes; + +} + +CPIMByteArray* PIMBase64Converter::DecodeBase64L(const CPIMByteArray& aSource) +{ + JELOG2(EPim); + CPIMByteArray* targetBytes = + new(ELeave) CPIMByteArray(KByteArrayGranularity); + CleanupStack::PushL(targetBytes); + + // Loop through the source array. + // + // Read an 8 bit byte on each iteration. If the byte is a pad byte, stop + // reading. If the byte is not a base64 letter, skip it. Otherwise, + // consider it a base64 letter and convert it to the corresponding 6 bit + // value (in an 8 bit byte, of course). Insert the 6 bits to a quantum, + // shifting its contents 6 bits left before insertion. When four bytes + // are read, append the bytes as three base64-decoded bytes to the target + // array. Then reset the quantum and start reading another four bytes. + // + // If a pad byte was read before full quantum was constructed, a partial + // quantum is constructed. Quantum decoding method can also parse an empty + // quantum, in which case it does nothing. + + TUint32 quantum = 0; + TInt numBytesInQuantum = 0; + const TInt numTotalSourceBytes = aSource.Count(); + + for (TInt i = 0; i < numTotalSourceBytes; i++) + { + TUint8 sourceBase64Letter = aSource[i]; + + if (sourceBase64Letter == KPadLetter) + { + break; // End of input + } + + TUint8 sourceByte = Base64LetterToByte(sourceBase64Letter); + + if (sourceByte == KNonBase64Letter) + { + continue; // Skip + } + + quantum <<= 6; + quantum |= sourceByte; + numBytesInQuantum++; + + if (numBytesInQuantum == 4) + { + // 24 bits in quantum + DecodeQuantumL(quantum, *targetBytes, 4); + quantum = 0; + numBytesInQuantum = 0; + } + } + + // 0, 6, 12 or 18 bits in quantum + DecodeQuantumL(quantum, *targetBytes, numBytesInQuantum); + + CleanupStack::Pop(targetBytes); + return targetBytes; +} + +void PIMBase64Converter::EncodeQuantumL(const TUint32& aQuantum, + CPIMByteArray& aTargetArray, const TInt& aNumSourceBytes) +{ + JELOG2(EPim); + TInt numTargetBytes = 0; + TInt padShift = 0; + + switch (aNumSourceBytes) + { + case 3: // 24 bits + { + numTargetBytes = 4; // 6 + 6 + 6 + 6 + break; + } + case 2: // 16 bits + { + numTargetBytes = 3; // 6 + 6 + 4 + padShift = 2; + break; + } + case 1: // 8 bits + { + numTargetBytes = 2; // 6 + 2 + padShift = 4; + break; + } + case 0: // 0 bits + { + return; // Done. + } + default: + { + User::Leave(KErrArgument); + } + } + + TInt numPadBytes = 4 - numTargetBytes; + + while (numTargetBytes > 0) + { + numTargetBytes--; + TUint32 tempQuantum = aQuantum; + TInt shift = 6 * numTargetBytes; + tempQuantum <<= padShift; + tempQuantum >>= shift; + tempQuantum &= KSixLSBits; + + TUint8 byte = static_cast