diff -r 000000000000 -r 3553901f7fa8 smsprotocols/smsstack/wapprot/Src/wapthdr.cpp --- /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 +#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& aSegmentArray) + { + TBuf8 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= 5 ) + return KErrNotFound; + for(i=0; i='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= 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