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(tempQuantum); + TUint8 base64Letter = ByteToBase64Letter(byte); + aTargetArray.AppendL(base64Letter); + } + + while (numPadBytes > 0) + { + aTargetArray.AppendL(KPadLetter); + numPadBytes--; + } +} + +void PIMBase64Converter::DecodeQuantumL(const TUint32& aQuantum, + CPIMByteArray& aTargetArray, const TInt& aNumSourceBytes) +{ + JELOG2(EPim); + TInt numTargetBytes = 0; + TInt padShift = 0; + + switch (aNumSourceBytes) + { + case 4: // 24 bits + { + numTargetBytes = 3; // 8 + 8 + 8 bits + break; + } + case 3: // 18 bits + { + numTargetBytes = 2; // 8 + 8 (+ 2) bits + padShift = 2; + break; + } + case 2: // 12 bits + { + numTargetBytes = 1; // 8 (+ 4) bits + padShift = 4; + break; + } + case 1: // 6 bits + { + // This should never happen + __ASSERT_DEBUG(EFalse, User::Panic(KPIMPanicCategory, + EPIMPanicBase64Error)); + break; + } + case 0: // 0 bits + { + return; // Done. + } + default: + { + User::Leave(KErrArgument); + } + } + + while (numTargetBytes > 0) + { + numTargetBytes--; + TUint32 tempQuantum = aQuantum; + tempQuantum >>= (8 * numTargetBytes + padShift); + tempQuantum &= KEightLSBits; + TUint8 byte = static_cast(tempQuantum); + aTargetArray.AppendL(byte); + } +} + +inline TUint8 PIMBase64Converter::ByteToBase64Letter(const TUint8& aByte) +{ + JELOG2(EPim); + __ASSERT_DEBUG(aByte < 64, User::Panic(KPIMPanicCategory, + EPIMPanicBase64Error)); + + return KBase64Alphabet[aByte]; +} + +TUint8 PIMBase64Converter::Base64LetterToByte(const TUint8& aLetter) +{ + JELOG2(EPim); + const TUint8 KUCAlphaBase = 0; // first upper case base64 letter + const TUint8 KLCAlphaBase = 26; // first lower case base64 letter + const TUint8 KNumBase = 52; // first numerical letter + const TUint8 KPlus = 62; // '+' character + const TUint8 KSlash = 63; // '/' character + + TUint8 retVal = 0; + + if ((aLetter >= 'A') && (aLetter <= 'Z')) + { + retVal = static_cast(aLetter - 'A' + KUCAlphaBase); + } + else if ((aLetter >= 'a') && (aLetter <= 'z')) + { + retVal = static_cast(aLetter - 'a' + KLCAlphaBase); + } + else if ((aLetter >= '0') && (aLetter <= '9')) + { + retVal = static_cast(aLetter - '0' + KNumBase); + } + else if (aLetter == '+') + { + retVal = KPlus; + } + else if (aLetter == '/') + { + retVal = KSlash; + } + else + { + retVal = KNonBase64Letter; + } + + __ASSERT_DEBUG((retVal < 64) || (retVal == KNonBase64Letter), User::Panic( + KPIMPanicCategory, EPIMPanicBase64Error)); + + return retVal; +} + +// End of File