--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/smsprotocols/smsstack/wapprot/Src/wapthdr.cpp Tue Feb 02 01:41:59 2010 +0200
@@ -0,0 +1,600 @@
+// Copyright (c) 1997-2009 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:
+// This file contains the implementation of the TWapTextMessage.
+// TWapTextMessage encodes and decodes 7-bit WAP text headers
+//
+//
+
+/**
+ @file
+*/
+
+#include <e32std.h>
+#include "wapthdr.h"
+#include "ws_main.h"
+
+const TInt TWapTextMessage::KHeaderCount = 6;
+
+_LIT8(KSCKHeaderLong, "//SCKL"); // standard NBS header for 16-bit adresses
+_LIT8(KSCKHeaderShort,"//SCK"); // standard NBS header for 8-bit adresses
+
+
+/**
+ * Indices into different types header for each of the header elements
+ * (dest port, source port, reference, total segments, current segment)
+ */
+const TWapTextMessage::TIndexInfo TWapTextMessage::KElemIndexes[TWapTextMessage::KHeaderCount] =
+{
+// Long header ("//SCKL") indices
+// destination port (, other header)
+ { 1,{ 6, 10, 0, 0, 0, 0} },
+// destination port, source port (, other header)
+ { 2,{ 6, 10, 14, 0, 0, 0} },
+// destination port, source port,
+// reference, total segments, current segment(, other header)
+ { 5,{ 6, 10, 14, 16, 18, 20}},
+
+// Short header ("//SCK") indices
+// destination port (, other header)
+ { 1, { 5, 7, 0, 0, 0, 0}},
+// destination port, source port (, other header)
+ { 2, { 5, 7, 9, 0, 0, 0}},
+// destination port, source port,
+// reference, total segments, current segment(, other header)
+ { 5,{ 5, 7, 9, 11, 13, 15}},
+};
+
+
+/**
+ * C'tor
+ *
+ * @param aWapMessage WAP message to decode/encode
+ * @note simply use KNullDesC8, if you are going to encode.
+ */
+TWapTextMessage::TWapTextMessage(const TDesC8& aWapMessage)
+ :iIsWapTextMessage(EFalse)
+ ,iWAPMessage(aWapMessage)
+ ,iIs16Bit(EFalse)
+ ,iDestinationPort(-1)
+ ,iSourcePort(-1)
+ ,iReference(0)
+ ,iTotalSegments(0)
+ ,iSegmentNumber(0)
+ ,iOtherHeader(0)
+ ,iOtherHeaderLength(0)
+ ,iData(0)
+ ,iDataLength(0)
+ ,iRefOtherHeader(KNullDesC8)
+ ,iRefData(KNullDesC8)
+ {
+ } // TWapTextMessage::TWapTextMessage
+
+
+/**
+ * Panic is raised, if the header with other header and terminating
+ * ' ' is > 159 characters. Then 1 byte is left for payload !
+ * what will be the array element type ?
+ */
+void TWapTextMessage::EncodeSegmentsL(CArrayPtr<HBufC8>& aSegmentArray)
+ {
+ TBuf8<KMaxSmsChars> header; // buffer for a modifiable header
+ TInt headerLength = 0;
+ TInt segmentNumberIndex = 0; // index of segment number field in the header
+ TBuf8<2> hexSegmentNumber;
+ TInt dataSegmented = 0;
+
+ LOGWAPPROT1("TWapTextMessage::EncodeSegmentsL()");
+
+ iSegmentNumber = 0;
+ do
+ {
+ //
+ // Create the segment and add it to the array...
+ //
+ HBufC8* segment = HBufC8::NewL(KMaxSmsChars); // 160 characters
+ CleanupStack::PushL(segment);
+ TPtr8 ptr(segment->Des());
+ aSegmentArray.AppendL(segment);
+ CleanupStack::Pop(); // segment
+
+ //
+ // Calculate length of header and copy it...
+ //
+ if (iSegmentNumber==0)
+ {
+ headerLength = CreateHeader(header, segmentNumberIndex);
+ }
+
+ ptr.Copy(header);
+ if (iTotalSegments>255)
+ {
+ User::Leave(KErrOverflow);
+ }
+
+ //
+ // Set segment number...
+ //
+ if (segmentNumberIndex != 0)
+ {
+ hexSegmentNumber.NumFixedWidthUC(iSegmentNumber+1, EHex, 2); // two bytes wide
+ ptr.Insert(segmentNumberIndex, hexSegmentNumber);
+ }
+
+ //
+ // Count any escaped characters we can be sure that the converted data
+ // size fits inside the remaining length (e.g. so that non-7bit characters
+ // when converted by the SMS Stack will still fit).
+ //
+ TInt segmentSize = iRefData.Length() - dataSegmented;
+
+ if (segmentSize > KMaxSmsChars - headerLength)
+ {
+ segmentSize = KMaxSmsChars - headerLength;
+ }
+
+ while (segmentSize > 1)
+ {
+ TPtrC8 segmentData(iRefData.Mid(dataSegmented, segmentSize));
+ TInt non7bitCharEscapes = 0;
+
+ //
+ // Count all non-7bit characters that will be escaped (many non-7bit
+ // characters are not escaped, but converted to "?"). The ones
+ // that are known to be escaped are list below:
+ //
+ // 12 [Form Feed].
+ // 91 "["
+ // 92 "\"
+ // 93 "]"
+ // 94 "^"
+ // 123 "{"
+ // 124 "|"
+ // 125 "}"
+ // 126 "~"
+ //
+ for (TInt ch = 0; ch < segmentSize; ch++)
+ {
+ if (segmentData[ch] == 12 ||
+ (segmentData[ch] >= 91 && segmentData[ch] <= 94) ||
+ (segmentData[ch] >= 123 && segmentData[ch] <= 126))
+ {
+ non7bitCharEscapes++;
+ }
+ }
+
+ //
+ // Can it fit? If so store it, otherwise reduce the size...
+ //
+ if (segmentData.Length() + non7bitCharEscapes <= KMaxSmsChars - headerLength)
+ {
+ ptr.Append(segmentData);
+ break;
+ }
+
+ segmentSize--;
+ }
+
+ dataSegmented += segmentSize;
+ iSegmentNumber++;
+ }
+ while (dataSegmented < iRefData.Length());
+
+ __ASSERT_DEBUG(iTotalSegments == aSegmentArray.Count(), Panic(KPanicEncodingError));
+ } // TWapTextMessage::EncodeSegmentsL
+
+
+/**
+ * Returns true, if the short message starts with
+ * WAP text message header set by SetWapTextMessage.
+ */
+TBool TWapTextMessage::Parse()
+ {
+ TInt waplength = iWAPMessage.Length();
+ LOGWAPPROT2("TWapTextMessage::Parse [%d bytes]", waplength);
+ if(waplength != 0)
+ {
+ // check whether long or short header
+ TInt iBaseIndex = -1;
+
+ // minimum length is 8 "//SCKxx "
+ if(waplength >= 8)
+ {
+ TPtrC8 HeaderIdPart(iWAPMessage.Left(6));
+ if(!HeaderIdPart.Compare(KSCKHeaderLong))
+ {
+ iBaseIndex = 0;
+ iIs16Bit = ETrue; // Yes, the ports are 16 bit wide
+ }
+ else
+ HeaderIdPart.Set(iWAPMessage.Left(5));
+
+ if(iBaseIndex == (-1) && !HeaderIdPart.Compare(KSCKHeaderShort) )
+ iBaseIndex = 3;
+ // else no match
+ }
+
+ if(iBaseIndex >= 0)
+ {
+ // check which of the TIndexInfos match
+ for(TInt i=iBaseIndex; i<iBaseIndex+3; i++)
+ {
+ // Get length (index) of text header variant
+ TInt lastIndex = KElemIndexes[i].iIndexes[KElemIndexes[i].iLastIndex];
+ if (iWAPMessage.Length() <= lastIndex)
+ {
+ // no hope about match, because other variants are longer
+ iIsWapTextMessage = EFalse;
+ break;
+ }
+
+ TInt LastChar = iWAPMessage[lastIndex];
+ if (LastChar == '/' || LastChar == ' ' || LastChar == '\n')
+ {
+ // reinitialize, because following maybe absent
+ iTotalSegments = 1;
+ iSegmentNumber = 1;
+ iIsWapTextMessage = ParseWapTextHeader(KElemIndexes[i]);
+ break;
+ }
+
+ }
+
+ if (!iIsWapTextMessage)
+ {
+ LOGWAPPROT1("WARNING! illegal incoming WAP message");
+ }
+ }
+ }
+
+ return iIsWapTextMessage;
+ } // TWapTextMessage::Parse
+
+
+/**
+ * Parses a string of hex characters representing a number
+ *
+ * @param aInValue descriptor containing the number
+ * @param aBigEndian true if number is big endian
+ * @param aRadix Radixbase; 16, 10 etc
+ * @return TInt the parsed number
+ * @leave Panics with KPanicInvalidParseNumber error code, if not a
+ * number. Maximum width of the hex value can be 4.
+ *
+ * TODO use TLex instead
+ */
+TInt TWapTextMessage::ParseNumber(const TDesC8& aInValue,
+ TBool aBigEndian,
+ TInt aRadix)
+ {
+ LOGWAPPROT2("TWapTextMessage::ParseNumber [%S]", &aInValue);
+ // least significant byte first
+ TInt Values[4] = {0,0,0,0};
+ TInt Temp = 0;
+ TInt length = aInValue.Length();
+ TInt i = 0;
+ TInt Value = 0;
+
+ __ASSERT_DEBUG(length<5,Panic(KPanicInvalidParseNumber));
+ if( length >= 5 )
+ return KErrNotFound;
+ for(i=0; i<length; i++)
+ {
+ Temp = aInValue[i];
+ if (Temp>='0' && Temp<='9')
+ Temp-='0';
+ else if (Temp>='A' && Temp<='Z')
+ Temp = Temp - 'A'+10;
+ else if (Temp>='a' && Temp<='z')
+ Temp = Temp - 'a'+10;
+ else
+ return KErrNotFound;
+ if (aBigEndian)
+ Values[(length-1)-i]=Temp;
+ else
+ Values[i]=Temp;
+ }
+
+ // build the value
+ Value=Values[0];
+ TInt Base=1;
+ for(i=1; i<length; i++)
+ {
+ Base*=aRadix;
+ Value+=(Base)*Values[i];
+ }
+
+ return Value;
+ } // TWapTextMessage::ParseNumber
+
+
+/**
+ * parse the WAP text header
+ *
+ * use ElemIndexes to retrieve the index
+ * an starting position of an element in iWapMessage
+ * Length of element is calculated by
+ * subtracting current index value from the next one
+ * except for KOtherHeader and user data, of course
+ */
+TBool TWapTextMessage::ParseWapTextHeader(const TIndexInfo& aIndexArray)
+ {
+ LOGWAPPROT2("TWapTextMessage::ParseWapTextHeader: %S", &iWAPMessage );
+
+ TInt ParsedNumber = 0;
+
+ // parse the header
+ TInt ElemIndexCount=aIndexArray.iLastIndex+1;
+ for(TInt i=0; i<ElemIndexCount; i++)
+ {
+ if (i<ElemIndexCount-1)
+ {
+ // all the elems have a length defined in advance
+ if (iWAPMessage.Length() >= aIndexArray.iIndexes[i+1])
+ {
+ // the header fits into the wap datagram
+ TPtrC8 Elem(iWAPMessage.Mid(aIndexArray.iIndexes[i],
+ aIndexArray.iIndexes[i+1]-
+ aIndexArray.iIndexes[i]));
+
+ ParsedNumber = ParseNumber(Elem,ETrue,16);
+ if( ParsedNumber == KErrNotFound )
+ return EFalse;
+ switch(i)
+ {
+ case KIndexDestinationPort:
+ iDestinationPort = ParsedNumber;
+
+ break;
+ case KIndexSourcePort:
+ iSourcePort = ParsedNumber;
+ break;
+ case KIndexReferenceNumber:
+ iReference = ParsedNumber;
+ break;
+ case KIndexTotalSegments:
+ iTotalSegments = ParsedNumber;
+ break;
+ case KIndexSegmentNumber:
+ iSegmentNumber = ParsedNumber;
+ break;
+ default:
+ LOGWAPPROT2("Hm. unhandled WAP index [%d]", i );
+ break;
+ }
+ }
+ }
+ else
+ {
+ // elems have not a length defined in advance
+ iOtherHeader = 0;
+ iOtherHeaderLength = 0;
+
+ // Search the terminating character ' '
+ iData = iWAPMessage.Locate(' ');
+ TInt dataTmp = iWAPMessage.Locate('\n');
+
+ if (iData == KErrNotFound)
+ {
+ if (dataTmp == KErrNotFound)
+ return EFalse;
+ else
+ iData = dataTmp;
+ }
+ else if (dataTmp != KErrNotFound)
+ iData = Min(iData, dataTmp);
+
+ // check the existence of other header
+ // at least "// " should be there
+ if ( iWAPMessage.Length() > aIndexArray.iIndexes[i]+2
+ && iWAPMessage[aIndexArray.iIndexes[i]] == '/'
+ && iWAPMessage[aIndexArray.iIndexes[i]+1] == '/')
+ {
+ iOtherHeader = aIndexArray.iIndexes[i];
+ iOtherHeaderLength=iData-iOtherHeader;
+ }
+
+ // data: check if any characters after ' '
+ iDataLength = 0;
+ iData++;
+ if (iWAPMessage.Length() > iData)
+ {
+ iDataLength = iWAPMessage.Length() - iData;
+ }
+
+ // That's it
+ } // end of other header and data
+ }// end of for loop
+ return ETrue;
+ } // TWapTextMessage::ParseWapTextHeader
+
+
+/**
+ * Length of header is returned
+ * Sets internally the iTotalSegments
+ * Does not set the segment number into the aFixedHeader
+ *
+ * Length of complete header is returned.
+ * On return the header is not complete, if SAR is needed, because the segment
+ * number is not set. Thus aFixedHeader.Length() != (return value of this function) is true.
+ * The segment number can be set by inserting it into aSegmentNumberIndex position
+ * If SAR is not needed aSegmentNumberIndex = 0 and
+ * aFixedHeader.Length() == (return value of this function) is true
+ */
+TInt TWapTextMessage::CreateHeader(TDes8& aFixedHeader, TInt& aSegmentNumberIndex)
+ {
+ LOGWAPPROT1("TWapTextMessage::CreateHeader");
+
+ // Index into KElemIndexes indicating which header elements are present
+ TInt elemIndex;
+ // Index into Indexes, for current header element
+ TInt minorIndex=KIndexDestinationPort;
+ TBuf8<4> hexNumber;
+
+ // Segment number length is set, if SAR is needed
+ TInt segmentNumberLength = 0;
+ aSegmentNumberIndex = 0;
+
+ // Determine whether long or short form is used
+ if (iIs16Bit || iSourcePort > 255 || iDestinationPort>255)
+ {
+ elemIndex = 0;
+ aFixedHeader.Copy(KSCKHeaderLong);
+ }
+ else
+ {
+ elemIndex = 3;
+ aFixedHeader.Copy(KSCKHeaderShort);
+ }
+
+ // Set destination port
+ hexNumber.NumFixedWidthUC(iDestinationPort,EHex,
+ KElemIndexes[elemIndex].iIndexes[minorIndex+1]-KElemIndexes[elemIndex].iIndexes[minorIndex]);
+ aFixedHeader.Append(hexNumber);
+
+ // Don't set the source port,
+ // 1) if it is not set or it same as destination port and
+ // 2) data (and other header) fits in one segment
+ if (!((iSourcePort==-1 || iDestinationPort==iSourcePort)
+ && CalculateTotalSegments(KElemIndexes[elemIndex].iIndexes[minorIndex+1])==1))
+ {
+ // Source port is present
+ elemIndex++;
+ minorIndex++;
+ if (iSourcePort==-1)
+ iSourcePort = iDestinationPort;
+
+ // Set source port
+ hexNumber.NumFixedWidthUC(iSourcePort,EHex,
+ KElemIndexes[elemIndex].iIndexes[minorIndex+1]-KElemIndexes[elemIndex].iIndexes[minorIndex]);
+ aFixedHeader.Append(hexNumber);
+
+ // Add the SAR info when source port is set
+ elemIndex++;
+
+ // Set reference
+ minorIndex++;
+ hexNumber.NumFixedWidthUC(iReference,EHex,
+ KElemIndexes[elemIndex].iIndexes[minorIndex+1]-KElemIndexes[elemIndex].iIndexes[minorIndex]);
+ aFixedHeader.Append(hexNumber);
+
+ // Set fragment count
+ minorIndex++;
+ CalculateTotalSegments(KElemIndexes[elemIndex].iIndexes[KElemIndexes[elemIndex].iLastIndex]);
+ hexNumber.NumFixedWidthUC(iTotalSegments,EHex,
+ KElemIndexes[elemIndex].iIndexes[minorIndex+1]-KElemIndexes[elemIndex].iIndexes[minorIndex]);
+ aFixedHeader.Append(hexNumber);
+
+ // Return the index for segment number in the header
+ minorIndex++;
+ aSegmentNumberIndex = KElemIndexes[elemIndex].iIndexes[minorIndex];
+ segmentNumberLength = 2;
+ }
+
+ aFixedHeader.Append(iRefOtherHeader);
+ aFixedHeader.Append(_L(" "));
+
+ return aFixedHeader.Length()+segmentNumberLength;
+ } // TWapTextMessage::CreateHeader
+
+
+/**
+ * Calculates count of segments to send a used data (based on iRefData)
+ * The values is assigned to iTotalSegments
+ * The affect of terminating ' ' is taken into inside the method
+ */
+TInt TWapTextMessage::CalculateTotalSegments(TInt aFixedLength)
+ {
+ LOGWAPPROT2("TWapTextMessage::CalculateTotalSegments [aFixedLength=%d]", aFixedLength);
+
+ // '+1': length of terminating ' '
+ TInt length = aFixedLength + iRefOtherHeader.Length() + 1;
+ TInt remain = KMaxSmsChars - length;
+ TInt dataSegmented = 0;
+
+ __ASSERT_DEBUG(remain > 0, Panic(KPanicTextHeaderTooLong));
+
+ iTotalSegments = 0;
+ do
+ {
+ iTotalSegments++;
+
+ //
+ // Count any escaped characters we can be sure that the converted data
+ // size fits inside the remaining length (e.g. so that non-7bit characters
+ // when converted by the SMS Stack will still fit).
+ //
+ TInt segmentSize = iRefData.Length() - dataSegmented;
+
+ if (segmentSize > remain)
+ {
+ segmentSize = remain;
+ }
+
+ while (segmentSize > 1)
+ {
+ TPtrC8 segmentData(iRefData.Mid(dataSegmented, segmentSize));
+ TInt non7bitCharEscapes = 0;
+
+ //
+ // Count all non-7bit characters that will be escaped (many non-7bit
+ // characters are not escaped, but converted to "?"). The ones
+ // that are known to be escaped are list below:
+ //
+ // 12 [Form Feed].
+ // 91 "["
+ // 92 "\"
+ // 93 "]"
+ // 94 "^"
+ // 123 "{"
+ // 124 "|"
+ // 125 "}"
+ // 126 "~"
+ //
+ for (TInt ch = 0; ch < segmentSize; ch++)
+ {
+ if (segmentData[ch] == 12 ||
+ (segmentData[ch] >= 91 && segmentData[ch] <= 94) ||
+ (segmentData[ch] >= 123 && segmentData[ch] <= 126))
+ {
+ non7bitCharEscapes++;
+ }
+ }
+
+ //
+ // Can it fit? If so store it, otherwise reduce the size...
+ //
+ if (segmentData.Length() + non7bitCharEscapes <= remain)
+ {
+ break;
+ }
+
+ segmentSize--;
+ }
+
+ dataSegmented += segmentSize;
+ }
+ while (dataSegmented < iRefData.Length());
+
+ //
+ // At least one fragment is needed...
+ //
+ if (iTotalSegments == 0)
+ {
+ iTotalSegments = 1;
+ }
+
+ return iTotalSegments;
+ } // TWapTextMessage::CalculateTotalSegments
+
+// EOF - WAPTHDR.CPP