--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/messagingappbase/smartmessaging/gmsmodel/src/GmsModel.cpp Thu Dec 17 08:44:11 2009 +0200
@@ -0,0 +1,692 @@
+/*
+* Copyright (c) 2002 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:
+* Picture Message model and converter.
+*
+*/
+
+
+
+// INCLUDE FILES
+#include "gmsModel.h"
+
+#include <txtrich.h> //for CRichText
+#include <s32file.h>
+
+// LOCAL CONSTANTS AND MACROS
+
+// size constants
+const TInt KGmsVersionLength = 1;
+const TInt KGmsItemLengthFieldLength = 2;
+const TInt KGmsItemHeaderLength = 3;
+
+// tokens
+const TUint8 KGmsVersionAsciiZero = 48; // "0"
+const TUint8 KGmsItemTypeLatin1 = 0; // "0"
+const TUint8 KGmsItemTypeUnicode = 1; // "1"
+const TUint8 KGmsItemTypeOTABitmap = 2; // "2"
+
+const TUint8 KGmsLF = 10;
+_LIT(KGmsModelDll,"GmsModel.dll");
+
+// MEMBER FUNCTIONS
+
+
+EXPORT_C CGmsModel* CGmsModel::NewL(RFs& aFs, TInt aLeaveCodeForCorrupt)
+ {
+ CGmsModel* self = new (ELeave) CGmsModel(aFs, aLeaveCodeForCorrupt);
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ CleanupStack::Pop(self);
+ return self;
+ }
+
+void CGmsModel::ConstructL()
+ {
+ }
+
+EXPORT_C CGmsModel::~CGmsModel()
+ {
+ delete iText;
+ delete iOTABitmap;
+ }
+
+EXPORT_C void CGmsModel::ImportGMSL(const TDesC8& aInput)
+ {
+ Reset();
+ TInt index = 0;
+ CheckVersionL(aInput, index); //this leaves if version is invalid
+
+ TInt length = aInput.Length();
+ while (index < length)
+ {
+ //either text, a picture or something unsupported
+ ExtractGMSSubItemL(aInput, index);
+ }
+ __ASSERT_ALWAYS(HasPicture(), User::Leave(iLeaveCorrupt));
+ }
+
+EXPORT_C void CGmsModel::ImportGMSL(const CRichText& aRichText)
+ {
+ Reset();
+
+ // Create a temporary HBufC16 for extracting from CRichText.
+ // (CRichText has no interface for extracting to 8 bit descriptor)
+ TInt docLength = aRichText.DocumentLength();
+ HBufC16* buf = HBufC16::NewLC(docLength);
+ TPtr16 ptr16(buf->Des());
+ aRichText.Extract(ptr16, 0, docLength);
+
+ //Create a temporary HBufC8 for importing to converter.
+ HBufC8* buf8 = HBufC8::NewLC(docLength);
+ TPtr8 ptr8 = buf8->Des();
+
+ //Copy from 16 to 8 bit descriptor.
+ ptr8.Copy(ptr16);
+
+ ImportGMSL(*buf8);
+ CleanupStack::PopAndDestroy(2); //buf8 buf16
+ }
+
+EXPORT_C HBufC8* CGmsModel::ExportGMS8LC()
+ {
+ // There has to be at least picture data.
+ __ASSERT_ALWAYS(HasPicture(), Panic(EGmsMPanicNoPicData1));
+
+ HBufC8* buf = NULL;
+ buf = HBufC8::NewLC(TotalSize());
+ TPtr8 gms(buf->Des());
+ AppendVersionL(gms); // <version>
+ AppendTextSubItemL(gms); // <item>
+ AppendPictureSubItemL(gms); // <item>
+ return buf;
+ }
+
+EXPORT_C HBufC16* CGmsModel::ExportGMS16LC()
+ {
+ HBufC16* buf16 = HBufC16::NewLC(TotalSize());
+ TPtr ptr16(buf16->Des());
+ HBufC8* buf8 = ExportGMS8LC();
+ TPtr8 ptr8(buf8->Des());
+ ptr16.Copy(ptr8);
+ CleanupStack::PopAndDestroy(); //buf8
+ return buf16;
+ }
+
+EXPORT_C HBufC* CGmsModel::TextAsHBufC16LC() const
+ {
+ if (iText)
+ {
+ return iText->AllocLC();
+ }
+ return KNullDesC().AllocLC();
+ }
+
+EXPORT_C void CGmsModel::SetTextL(const TDesC& aSource)
+ {
+ if (ContainsUnicodeL(aSource))
+ {
+ SetTextUnicodeL(aSource);
+ }
+ else
+ {
+ SetTextLatinL(aSource);
+ }
+ }
+
+EXPORT_C void CGmsModel::SetTextLatinL(const TDesC& aSource)
+ {
+ HBufC* text = aSource.AllocL();
+ delete iText;
+ iText = text;
+ iMode = EGmsModeLatin;
+ }
+
+EXPORT_C void CGmsModel::SetTextUnicodeL(const TDesC& aSource)
+ {
+ HBufC* text = aSource.AllocL();
+ delete iText;
+ iText = text;
+ iMode = EGmsModeUnicode;
+ }
+
+TBool CGmsModel::ContainsUnicodeL(const TDesC& aInputString) const
+ {
+ TInt length = aInputString.Length();
+ const TUint KGmsHighestLatin1 = 255;
+ for (TInt n = 0; n < length; n++)
+ {
+ TUint16 ch = aInputString[n];
+ // Latin-1 occupies dec. values 0 to 255 of Unicode. (U+0000..U+00FF)
+ if (ch > KGmsHighestLatin1 && ch != CEditableText::EParagraphDelimiter)
+ {
+ return ETrue;
+ }
+ }
+ return EFalse;
+ }
+
+EXPORT_C void CGmsModel::ExportOTABitmapL(RWriteStream& aOutStream)
+ {
+ __ASSERT_ALWAYS(HasPicture(), Panic(EGmsMPanicNoPictureToExport));
+ aOutStream.WriteL(*iOTABitmap);
+ }
+
+/// Assumes an 8 bit data stream
+EXPORT_C void CGmsModel::ImportOTABitmapL(RReadStream& aReadStream)
+ {
+ MStreamBuf* streamBuf = NULL;
+ streamBuf = aReadStream.Source();
+ User::LeaveIfNull(streamBuf);
+ TInt size = streamBuf->SizeL();
+ __ASSERT_ALWAYS(size > 0,
+ Panic(EGmsMPanicStreamIsEmpty));
+ HBufC8* bitmap = HBufC8::NewLC(size);
+ TPtr8 bitmapPtr(bitmap->Des());
+ aReadStream.ReadL(bitmapPtr, size);
+ // This leaves with iLeaveCorrupt if the bitmap is bad.
+ HBufC8* buf8 = CheckedAndFixedOtaBitmapL(*bitmap);
+ CleanupStack::PopAndDestroy(bitmap);
+ delete iOTABitmap;
+ iOTABitmap = buf8;
+ }
+
+EXPORT_C TInt CGmsModel::SizeOfCompleteMsgExcludingTextAndPic() const
+ {
+ return (KGmsVersionLength + KGmsItemHeaderLength*2);
+ }
+
+EXPORT_C TBool CGmsModel::HasText() const
+ {
+ if (!iText || iText->Length() <= 0)
+ {
+ return EFalse;
+ }
+ // length > 0
+ return ETrue;
+ }
+
+// This does not verify that the data is valid
+EXPORT_C TBool CGmsModel::HasPicture() const
+ {
+ if (!iOTABitmap || iOTABitmap->Length() <= 0)
+ {
+ return EFalse;
+ }
+ // length > 0
+ return ETrue;
+ }
+
+EXPORT_C TBool CGmsModel::IsTextLatin() const
+ {
+ return (iMode == EGmsModeLatin);
+ }
+
+EXPORT_C TInt CGmsModel::TotalSizeExcludingText() const
+ {
+ TInt bitmapSize = 0;
+ if (iOTABitmap)
+ {
+ bitmapSize = iOTABitmap->Size();
+ }
+ return bitmapSize + SizeOfCompleteMsgExcludingTextAndPic();
+ }
+
+EXPORT_C TInt CGmsModel::TotalSize() const
+ {
+ TInt textSize(0);
+
+ textSize = Textlength();
+ if (iMode == EGmsModeUnicode)
+ {
+ textSize *= 2; // (two bytes per char)
+ }
+
+ return TotalSizeExcludingText() + textSize;
+ }
+
+EXPORT_C TInt CGmsModel::Textlength() const
+ {
+ if (iText)
+ {
+ return iText->Length();
+ }
+ return 0;
+ }
+
+EXPORT_C TInt CGmsModel::PictureSize() const
+ {
+ if (iOTABitmap)
+ {
+ return iOTABitmap->Size();
+ }
+ return 0;
+ }
+
+EXPORT_C void CGmsModel::Reset()
+ {
+ delete iText;
+ iText = NULL;
+ delete iOTABitmap;
+ iOTABitmap = NULL;
+ }
+
+EXPORT_C TInt CGmsModel::_TestingL(TInt /*aCode1*/, TInt& /*aCode2*/, const TDesC8& /*aDes1*/, const TDesC16& /*aDes2*/)
+ {
+ // Nothing here.
+ return 0;
+ }
+
+// Deprecated. Do not use.
+//
+EXPORT_C HBufC* CGmsModel::ExtractTextFromMsgLC(const TDesC& /*aMsg*/, TInt /*aAmount*/)
+ {
+ return NULL; // for compiler
+ }
+
+EXPORT_C TBool CGmsModel::IsPictureValidL()
+ {
+ // Deprecated
+ return ETrue;
+ }
+
+TBool CGmsModel::ImportOtaBitmapL(const TDesC& aFileName)
+ {
+ RFileReadStream readStream;
+ User::LeaveIfError(readStream.Open(
+ iFs,
+ aFileName,
+ EFileStream));
+ readStream.PushL();
+ MStreamBuf* buf = readStream.Source();
+ User::LeaveIfNull(buf);
+ TInt size = buf->SizeL();
+ __ASSERT_ALWAYS(size > 0,
+ Panic(EGmsNull1));
+ HBufC8* data = HBufC8::NewLC(size);
+ TPtr8 dataPtr(data->Des());
+ readStream.ReadL(dataPtr, size);
+ TBool success;
+ HBufC8* buf8 = NULL;
+ buf8 = CheckedAndFixedOtaBitmapL(*data, success);
+ CleanupStack::PopAndDestroy(data);
+ CleanupStack::PopAndDestroy(); //(closes readStream)
+ if (success)
+ {
+ delete iOTABitmap;
+ iOTABitmap = buf8;
+ return ETrue;
+ }
+ else
+ {
+ __ASSERT_DEBUG(!buf8, Panic(EGmsProblem1));
+ return EFalse;
+ }
+ }
+
+// Call this as the first extraction method.
+void CGmsModel::CheckVersionL(const TDesC8& aInput, TInt& aIndex)
+ {
+ __ASSERT_ALWAYS(aInput.Length() >= KGmsVersionLength,
+ User::Leave(iLeaveCorrupt));
+ // To be a valid msg, its version identifier must be zero
+ if (aInput[0] != KGmsVersionAsciiZero)
+ {
+ User::Leave(iLeaveCorrupt);
+ }
+ aIndex++;
+ }
+
+void CGmsModel::ExtractGMSSubItemL(const TDesC8& aInput, TInt& aIndex)
+ {
+ ExtractGMSSubItemL(aInput, aIndex, EFalse);
+ }
+
+void CGmsModel::ExtractGMSSubItemL(const TDesC8& aInput, TInt& aIndex,
+ TBool aSkipBitmap)
+ {
+ __ASSERT_ALWAYS(aInput.Length() >= aIndex + KGmsItemHeaderLength,
+ User::Leave(iLeaveCorrupt));
+
+ //Get GMS item type. It should be one of the following:
+ // "00" <GMS-item-length> <ISO-8859-1-char>* = LATIN TEXT ITEM
+ // "01" <GMS-item-length> <UNICODE-char>* = UNICODE TEXT ITEM
+ // "02" <GMS-item-length> <OTA-bitmap> = PICTURE ITEM
+
+ TBuf8<1> msgItemType;
+ msgItemType = aInput.Mid(aIndex, 1); //pos, length
+ aIndex += 1;
+
+ if (KGmsItemTypeLatin1 == msgItemType[0]) // "00"
+ {
+ ExtractLatin1L(aInput, aIndex);
+ }
+ else if (KGmsItemTypeUnicode == msgItemType[0]) // "01"
+ {
+ ExtractUnicodeL(aInput, aIndex);
+ }
+ else if (KGmsItemTypeOTABitmap == msgItemType[0]) // "02"
+ {
+ if (aSkipBitmap)
+ {
+ ExtractUnknownL(aInput, aIndex); //just skips over it
+ }
+ else
+ {
+ ExtractOTABitmapL(aInput, aIndex);
+ }
+ }
+ else
+ {
+ ExtractUnknownL(aInput, aIndex); //just skips over the part
+ }
+ }
+
+void CGmsModel::ExtractLatin1L(const TDesC8& aInput, TInt& aIndex)
+ {
+ TInt length = ExtractLengthL(aInput, aIndex);
+
+ __ASSERT_ALWAYS(aInput.Length() >= aIndex + length,
+ User::Leave(iLeaveCorrupt));
+
+ delete iText;
+ iText = NULL;
+ iText = HBufC::NewL(length);
+ iText->Des().Copy(aInput.Mid(aIndex, length));
+ aIndex += length;
+ iMode = EGmsModeLatin;
+ }
+
+void CGmsModel::ExtractUnicodeL(const TDesC8& aInput, TInt& aIndex)
+ {
+ TInt length = ExtractLengthL(aInput, aIndex);
+ __ASSERT_ALWAYS(aInput.Length() >= aIndex + length,
+ User::Leave(iLeaveCorrupt));
+ __ASSERT_ALWAYS((length % 2) == 0, User::Leave(iLeaveCorrupt));//even nr.
+ delete iText;
+ iText = NULL;
+ iText = HBufC::NewL(length / 2);
+
+ //
+ // The data has to be reassembled from UCS-2 to 16 bit Unicode.
+ //
+ TPtr ptr(iText->Des());
+ for (TInt n = aIndex; n < aIndex + length; n += 2)
+ {
+ TUint16 lower = aInput[n + 1];
+ TUint16 upper = aInput[n];
+ upper = TUint16(upper << 8);
+ TUint16 ch = 0;
+ ch = TUint16(upper | lower);
+ ptr.Append(ch);
+ }
+ aIndex += length;
+ iMode = EGmsModeUnicode;
+ }
+
+void CGmsModel::ExtractOTABitmapL(const TDesC8& aInput, TInt& aIndex)
+ {
+ TInt length = ExtractLengthL(aInput, aIndex);
+ __ASSERT_ALWAYS(aInput.Length() >= aIndex + length,
+ User::Leave(iLeaveCorrupt));
+ delete iOTABitmap;
+ iOTABitmap = NULL;
+ // This leaves with iLeaveCorrupt if the bitmap is bad.
+ iOTABitmap = CheckedAndFixedOtaBitmapL(aInput.Mid(aIndex, length));
+ aIndex += length;
+ }
+
+void CGmsModel::ExtractUnknownL(const TDesC8& aInput, TInt& aIndex)
+ {
+ TInt length = ExtractLengthL(aInput, aIndex);
+ __ASSERT_ALWAYS(aInput.Length() >= aIndex + length,
+ User::Leave(iLeaveCorrupt));
+ aIndex += length; // Skip the unknown item.
+ }
+
+TInt CGmsModel::ExtractLengthL(const TDesC8& aInput, TInt& aIndex)
+ {
+ __ASSERT_ALWAYS(aInput.Length() >= aIndex + KGmsItemLengthFieldLength,
+ User::Leave(iLeaveCorrupt));
+
+ // (KGmsItemLengthFieldLength = 2)
+ TBuf8<KGmsItemLengthFieldLength> itemLength;
+ itemLength.Copy(aInput.Mid(aIndex, KGmsItemLengthFieldLength));
+ aIndex += KGmsItemLengthFieldLength;
+ TUint16 length = 0;
+ length = TUint16 ((itemLength[0]&0x000000FF));
+ length = TUint16 (length<<8);
+ length |= TUint16 ((itemLength[1]&0x000000FF));
+ return length;
+ }
+
+CGmsModel::CGmsModel(RFs& aFs, TInt aLeaveCodeForCorrupt) :
+ iFs(aFs),
+ iLeaveCorrupt(aLeaveCodeForCorrupt)
+ {
+ }
+
+void CGmsModel::AppendVersionL(TDes8& aGms)
+ {
+ TBuf8<1> gmsVersion;
+ _LIT(KEmpty1, "0");
+ gmsVersion.Copy(KEmpty1);
+ gmsVersion[0] = KGmsVersionAsciiZero;
+ aGms.Append(gmsVersion);
+ }
+
+void CGmsModel::AppendTextSubItemL(TDes8& aGms)
+ {
+ TBuf8<3> itemHeader;
+ _LIT(KEmpty3, "000");
+ itemHeader.Copy(KEmpty3);
+
+ if (iMode == EGmsModeLatin)
+ {
+ itemHeader[0] = KGmsItemTypeLatin1; // entity type identifier.
+ }
+ else
+ {
+ // Unicode
+ itemHeader[0] = KGmsItemTypeUnicode; // entity type identifier.
+ }
+
+ TInt sizeT = 0;
+ if (iText)
+ {
+ sizeT = iText->Length();
+ if (iMode == EGmsModeUnicode)
+ {
+ sizeT *= 2;
+ }
+ }
+
+ // The text header is added even if there is no text.
+ TInt lowerT = sizeT;
+ lowerT &= TInt(0x000000FF);
+
+ TUint upperT = sizeT;
+ upperT = TInt(upperT >> 8);
+ upperT &= TInt(0x000000FF);
+
+ itemHeader[1] = TInt8(upperT); //First byte of <Item-length>
+ itemHeader[2] = TInt8(lowerT); //Second byte of <Item-length>
+
+ aGms.Append(itemHeader);
+ if (iText)
+ {
+ if (iMode == EGmsModeLatin)
+ {
+ AppendLatin1TextL(aGms, *iText);
+ }
+ else
+ {
+ // Have to encode Unicode text to UCS2.
+ AppendUCS2TextL(aGms, *iText);
+ }
+ }
+ }
+
+void CGmsModel::AppendPictureSubItemL(TDes8& aGms)
+ {
+ __ASSERT_DEBUG(HasPicture(), Panic(EGmsMPanicNoPicData2));
+
+ TBuf8<3> itemHeader;
+ _LIT(KEmpty3, "000");
+ itemHeader.Copy(KEmpty3);
+
+ itemHeader[0] = KGmsItemTypeOTABitmap; // entity type identifier.
+
+ TInt sizeB = iOTABitmap->Size();
+ TInt lowerB = sizeB;
+ lowerB &= TInt(0x000000FF);
+
+ TUint upperB = sizeB;
+ upperB = TInt(upperB >> 8);
+ upperB &= TInt(0x000000FF);
+
+ itemHeader[1] = TInt8(upperB); //First byte of <Item-length>
+ itemHeader[2] = TInt8(lowerB); //Second byte of <Item-length>
+
+ aGms.Append(itemHeader);
+ aGms.Append(*iOTABitmap);
+ }
+
+void CGmsModel::AppendUCS2TextL(TDes8& aGms, const TDesC& aText)
+ {
+ TInt length = aText.Length();
+ for (TInt n = 0; n < length; n++)
+ {
+ TUint16 i = aText[n];
+
+ TUint16 lower = i;
+ lower &= TUint16(0x000000FF);
+
+ TUint16 upper = i;
+ upper = TUint16(upper >> 8);
+ upper &= TUint16(0x000000FF);
+ TChar ch = upper;
+ aGms.Append(ch);
+ ch = lower;
+ aGms.Append(ch);
+ }
+ }
+
+void CGmsModel::AppendLatin1TextL(TDes8& aGms, const TDesC& aText)
+ {
+ TInt length = aText.Length();
+ for (TInt n = 0; n < length; n++)
+ {
+ TUint16 ch = aText[n];
+ if (ch == CEditableText::EParagraphDelimiter)
+ {
+ aGms.Append(KGmsLF);
+ }
+ else
+ {
+ aGms.Append(ch);
+ }
+ }
+ }
+
+HBufC8* CGmsModel::CheckedAndFixedOtaBitmapL(const TDesC8& aOta) const
+ {
+ TBool success;
+ HBufC8* buf = CheckedAndFixedOtaBitmapL(aOta, success);
+ if (success)
+ {
+ return buf;
+ }
+ else
+ {
+ __ASSERT_DEBUG(!buf, Panic(EGmsProblem2));
+ User::Leave(iLeaveCorrupt);
+ return NULL; //for compiler
+ }
+ }
+
+HBufC8* CGmsModel::CheckedAndFixedOtaBitmapL(const TDesC8& aOta, TBool& aSuccess) const
+ {
+ // From Smart Messaging Specification 3.0.0:
+ // <ota-bitmap> ::= <header> <image- data> [<palette>]
+ // <header> ::= <infofield> [<extfield>]* <width><height><depth>
+
+ __ASSERT_DEBUG(aOta.Length(), Panic(EGmsNoPic1));
+ TInt length = aOta.Length();
+
+ // <header> should be four bytes
+ const TInt KHeaderBytes = 4;
+ if (length < KHeaderBytes)
+ {
+ aSuccess = EFalse;
+ return NULL;
+ }
+
+ // <infofield> byte should be zero, because the following should hold:
+ // Concatenation flag = 0 (no)
+ // Compression = 0 (no)
+ // External palette = 0 (not used)
+ // Icon max size fld len. = 0 (8 bit)
+ // Number of animated icons = 0
+ if (aOta[0] != 0)
+ {
+ aSuccess = EFalse;
+ return NULL;
+ }
+
+ // <extfield> not allowed, and it was ruled out by requiring 0 for
+ // the concatenation flag of <infofield>.
+
+ TInt width = aOta[1];
+ TInt height = aOta[2];
+ TInt depth = aOta[3];
+ if (!Rng(KGmsMinPictureWidthPixels, width, KGmsMaxPictureWidthPixels)
+ || !Rng(KGmsMinPictureHeightPixels, height,KGmsMaxPictureHeightPixels)
+ || depth != 1)
+ {
+ aSuccess = EFalse;
+ return NULL;
+ }
+
+ // Check that there is the right amount of picture data.
+ TInt pixels = width * height;
+ TInt bytesNeededForPicData = pixels / 8 + (pixels%8 == 0 ? 0 : 1);
+ TInt bytesNeeded = bytesNeededForPicData + KHeaderBytes;
+ TInt tooManyBytes = length - bytesNeeded;
+ if (tooManyBytes == 0)
+ {
+ aSuccess = ETrue;
+ return aOta.AllocL();
+ }
+ else if (tooManyBytes < 0)
+ {
+ // not enough bytes
+ aSuccess = EFalse;
+ return NULL;
+ }
+ else
+ {
+ // tooManyBytes > 0
+ // Discard the excess bytes.
+ aSuccess = ETrue;
+ return aOta.Left(bytesNeeded).AllocL();
+ }
+ }
+
+void CGmsModel::Panic(TGmsModelPanic aCode)
+ {
+ User::Panic(KGmsModelDll, aCode);
+ }
+
+//end of file