smsprotocols/smsstack/gsmu/src/gsmusar.cpp
changeset 0 3553901f7fa8
child 19 630d2f34d719
equal deleted inserted replaced
-1:000000000000 0:3553901f7fa8
       
     1 // Copyright (c) 2000-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 // Implements Segmentation and Reassembly classes
       
    15 // 
       
    16 //
       
    17 
       
    18 /**
       
    19  @file
       
    20 */
       
    21 
       
    22 #include "gsmusar.h"
       
    23 #include "Gsmumain.h"
       
    24 
       
    25 //
       
    26 // CSmsBufferSegmenter - segments and reassembles (unpacked) data to and from CSmsBufferBase
       
    27 //
       
    28 
       
    29 /**
       
    30  *  This factory function creates a CsmsBufferSegmenter instance
       
    31  *  
       
    32  *  @param aAlphabetConverter Pre-configured
       
    33  *  @param aBuffer The message data
       
    34  *  @param aSegmentSize (Default = 0) The size of segment required. If the instance is to be used solely for determining the total length of the converted data with TotalConvertedLengthL() then the segment length need not be supplied, hence defaulting to zero.
       
    35  *  @return CSmsBufferSegmenter instance
       
    36  *  
       
    37  *  @capability None
       
    38  */
       
    39 EXPORT_C CSmsBufferSegmenter* CSmsBufferSegmenter::NewLC(CSmsAlphabetConverter& aAlphabetConverter,const CSmsBufferBase& aBuffer,TInt aSegmentSize)
       
    40 	{
       
    41 	LOGGSMU1("CSmsBufferSegmenter::NewLC()");
       
    42 	
       
    43 	CSmsBufferSegmenter* segmenter=new(ELeave) CSmsBufferSegmenter(aAlphabetConverter,aBuffer,aSegmentSize);
       
    44 	CleanupStack::PushL(segmenter);
       
    45 	segmenter->ConstructL();
       
    46 	return segmenter;
       
    47 	} // CSmsBufferSegmenter::NewLC
       
    48 
       
    49 
       
    50 CSmsBufferSegmenter::CSmsBufferSegmenter(CSmsAlphabetConverter& aAlphabetConverter,const CSmsBufferBase& aBuffer,TInt aSegmentSize)
       
    51 	: iAlphabetConverter(aAlphabetConverter),iSmsBuffer(aBuffer),iSegmentSize(aSegmentSize),iConvertedBufferPtr(NULL,0)
       
    52 	{
       
    53 	// NOP
       
    54 	} // CSmsBufferSegmenter::CSmsBufferSegmenter
       
    55 
       
    56 
       
    57 /**
       
    58  *  2nd phase of constructor. Esures we have an initial buffer.
       
    59  */
       
    60 void CSmsBufferSegmenter::ConstructL()
       
    61 	{
       
    62 	LOGGSMU1("CSmsBufferSegmenter::ConstructL()");
       
    63 
       
    64 	iConvertedBuffer=HBufC8::NewMaxL(iSegmentSize);
       
    65 	iConvertedBufferPtr.Set((TUint8*)iConvertedBuffer->Des().Ptr(),0,iConvertedBuffer->Length());
       
    66 	} // CSmsBufferSegmenter::ConstructL
       
    67 
       
    68 
       
    69 /**
       
    70  *  Destructor - Free resource
       
    71  *  
       
    72  *  @capability None
       
    73  */
       
    74 EXPORT_C CSmsBufferSegmenter::~CSmsBufferSegmenter()
       
    75 	{
       
    76 	delete iConvertedBuffer;
       
    77 	} // CSmsBufferSegmenter::ConstructL
       
    78 
       
    79 
       
    80 /**
       
    81  *  Resets the converted buffer
       
    82  */
       
    83 void CSmsBufferSegmenter::Reset()
       
    84 	{
       
    85 	LOGGSMU1("CSmsBufferSegmenter::Reset()");
       
    86 
       
    87 	iConvertedBufferPtr.Zero();
       
    88 	iElementsExtracted=0;
       
    89 	} // CSmsBufferSegmenter::Reset
       
    90 
       
    91 
       
    92 /**
       
    93  *  A client iteratively calls SegmentNextL() to retrieve each segment until ETrue is returned, indicating
       
    94  *  that the last segment has been reached. The output buffer, aSegmentBuffer, should be large enough to hold
       
    95  *  the number of elements specified by the segment size in the NewLC() constructor otherwise the call will
       
    96  *  Panic. The output buffer is automatically reset before it's filled.
       
    97  *  
       
    98  *  @param aSegmentBuffer The next segment
       
    99  *  @return True if the last segment has been reached
       
   100  *  
       
   101  *  @capability None
       
   102  */
       
   103 EXPORT_C TBool CSmsBufferSegmenter::SegmentNextL(TDes8& aSegmentBuffer,
       
   104 		                                         TInt& aUnconvertedChars, TInt& aDowngradedChars,
       
   105 		                                         TSmsEncoding aEncoding)
       
   106 	{
       
   107 	LOGGSMU2("CSmsBufferSegmenter::SegmentNextL(): iSegmentSize=%d", iSegmentSize);
       
   108 
       
   109 	TBool  ret = DoSegmentNextL(aSegmentBuffer, iSegmentSize,
       
   110 			                    aUnconvertedChars, aDowngradedChars,
       
   111 			                    aEncoding);
       
   112 	LOGGSMU2("CSmsBufferSegmenter::SegmentNextL() returns %d ", ret);
       
   113 
       
   114 	return ret;
       
   115 	} // CSmsBufferSegmenter::SegmentNextL
       
   116 
       
   117 
       
   118 TBool CSmsBufferSegmenter::DoSegmentNextL(TDes8& aSegmentBuffer,TInt aSegmentSize,
       
   119                                           TInt& aUnconvertedChars, TInt& aDowngradedChars,
       
   120                                           TSmsEncoding aEncoding)
       
   121 //
       
   122 // Extracts a "native" segment from the SMS buffer, converts to the required
       
   123 // character set and breaks off the next segment of required size.
       
   124 // Returns true if this was the last segment
       
   125 //
       
   126 	{
       
   127 	LOGGSMU2("CSmsBufferSegmenter::DoSegmentNextL(): aSegmentSize=%d", aSegmentSize);
       
   128 
       
   129 	__ASSERT_ALWAYS(aSegmentSize>0,Panic(KGsmuPanicIllegalSegmentSize));
       
   130 	__ASSERT_ALWAYS(aSegmentBuffer.MaxLength()>=aSegmentSize,Panic(KGsmuPanicSegmentBufferTooSmall));
       
   131 
       
   132 	// Extract from buffer until we have enough chars for a segment or we're at the end
       
   133 	aSegmentBuffer.Zero();
       
   134 	TBuf<CSmsBufferBase::EMaxBufLength> nativeChars;
       
   135 	while ((iConvertedBufferPtr.Length()<aSegmentSize)&&(iElementsExtracted<iSmsBuffer.Length()))
       
   136 		{
       
   137 		TInt elementsToExtract=Min(static_cast<TInt>(CSmsBufferBase::EMaxBufLength),iSmsBuffer.Length()-iElementsExtracted);
       
   138 		iSmsBuffer.Extract(nativeChars,iElementsExtracted,elementsToExtract);
       
   139 
       
   140 		TInt  numberOfUnconvertibleCharacters;
       
   141 		TInt  numberOfDowngradedCharacters;
       
   142 		TPtrC8 smsCharsPtr=iAlphabetConverter.ConvertFromNativeL(nativeChars,
       
   143 				                                                 aEncoding,
       
   144 				                                                 numberOfUnconvertibleCharacters,
       
   145 				                                                 numberOfDowngradedCharacters);
       
   146 		aUnconvertedChars += numberOfUnconvertibleCharacters;
       
   147 		aDowngradedChars  += numberOfDowngradedCharacters;
       
   148 
       
   149 		CheckConvertedBufferAllocL(iConvertedBufferPtr.Length()+smsCharsPtr.Length());
       
   150 		iConvertedBufferPtr.Append(smsCharsPtr);
       
   151 		iElementsExtracted+=elementsToExtract;
       
   152 		}
       
   153 	// Determine number of converted elements to put in this segment
       
   154 	TInt elementsInSegment=ElementsToReturnFromConvertedBufferL(aSegmentSize);
       
   155 	// And copy...
       
   156 	aSegmentBuffer.Copy(iConvertedBufferPtr.Ptr(),elementsInSegment);
       
   157 	iConvertedBufferPtr.Delete(0,elementsInSegment);
       
   158 	// If this is the last segment then ensure no unconverted characters remain
       
   159 	return !MoreL();
       
   160 
       
   161 	} // CSmsBufferSegmenter::DoSegmentNextL
       
   162 
       
   163 
       
   164 TBool CSmsBufferSegmenter::MoreL()
       
   165 	{
       
   166 	LOGGSMU1("CSmsBufferSegmenter::MoreL()");
       
   167 
       
   168 	if ((iElementsExtracted>=iSmsBuffer.Length())&&(iConvertedBufferPtr.Length()==0))
       
   169 		{
       
   170 		if (iAlphabetConverter.UnconvertedNativeCharacters().Length()>0)
       
   171 			{
       
   172 			User::Leave(KErrCorrupt);
       
   173 			}
       
   174 
       
   175 		return EFalse;
       
   176 		}
       
   177 
       
   178 	return ETrue;
       
   179 	} // CSmsBufferSegmenter::MoreL
       
   180 
       
   181 
       
   182 /**
       
   183  *  TotalConvertedLengthL() determines the total length in User Data Elements when the input buffer is converted.
       
   184  *  Depending on the conversion properties returned from the alphabet converter, a complete conversion may need
       
   185  *  to be performed, i.e. this call can be quite expensive.
       
   186  *  
       
   187  *  @return Total converted length
       
   188  *  
       
   189  *  @capability None
       
   190  */
       
   191 EXPORT_C TInt CSmsBufferSegmenter::TotalConvertedLengthL(TSmsEncoding aEncoding)
       
   192 	{
       
   193 	LOGGSMU2("CSmsBufferSegmenter::TotalConvertedLengthL(): aEncoding=%d", aEncoding);
       
   194 	
       
   195 	// Check for shortcut
       
   196 	CSmsAlphabetConverter::TSmsAlphabetConversionProperties conversionProperties;
       
   197 	iAlphabetConverter.ConversionPropertiesL(conversionProperties);
       
   198 	if (conversionProperties.iWidthConversion==CSmsAlphabetConverter::ESmsAlphabetWidthConversionFixed)
       
   199 		return iSmsBuffer.Length()*conversionProperties.iUDElementsPerNativeCharacter;
       
   200 
       
   201 	// No shortcut, have to do piecewise conversion
       
   202 	Reset();
       
   203 
       
   204 	//
       
   205 	// Find the best encoding method to use...
       
   206 	//
       
   207 	TSmsEncoding  aEncodingToUse = FindBestAlternativeEncodingL(aEncoding, iSmsBuffer.Length());
       
   208 	
       
   209 	//
       
   210 	// Segment and count the converted length...
       
   211 	//
       
   212 	TBool complete=EFalse;
       
   213 	TInt totalConvertedLength=0;
       
   214 	TInt unconvertedChars=0;
       
   215 	TInt downgradedChars=0;
       
   216 	TBuf8<CSmsBufferBase::EMaxBufLength> convertedChars;
       
   217 	while (!complete)
       
   218 		{
       
   219 		complete=DoSegmentNextL(convertedChars,convertedChars.MaxLength(),
       
   220 				                unconvertedChars, downgradedChars,
       
   221 				                aEncodingToUse);
       
   222 		totalConvertedLength+=convertedChars.Length();
       
   223 		}
       
   224 	Reset();
       
   225 	return totalConvertedLength;
       
   226 	} // CSmsBufferSegmenter::TotalConvertedLengthL
       
   227 
       
   228 
       
   229 TSmsEncoding CSmsBufferSegmenter::FindBestAlternativeEncodingL(TSmsEncoding aSuggestedEncoding,
       
   230 									  			       		   TInt aMaxBodyLength) const
       
   231 	{
       
   232 	LOGGSMU3("CSmsBufferSegmenter::FindBestAlternativeEncodingL(): aSuggestedEncoding=%d, aMaxBodyLength=%d",
       
   233 			 aSuggestedEncoding, aMaxBodyLength);
       
   234 
       
   235 	TSmsEncoding  encodingToUse = ESmsEncodingNone;
       
   236 	
       
   237 	//
       
   238 	// If this is not 7bit or the alternative encoding is not set then do
       
   239 	// nothing...
       
   240 	//
       
   241 	if (aSuggestedEncoding != ESmsEncodingNone  &&
       
   242 		iAlphabetConverter.Alphabet() == TSmsDataCodingScheme::ESmsAlphabet7Bit)
       
   243 		{
       
   244 		//
       
   245 		// Allocate a buffer and extract the text and ask the converter for
       
   246 		// the best encoding...
       
   247 		//
       
   248 		HBufC*  buffer = HBufC::NewLC(aMaxBodyLength);
       
   249 	    TPtr  bufferPtr = buffer->Des();
       
   250 		TInt  elementsToExtract = Min(aMaxBodyLength, iSmsBuffer.Length() - iElementsExtracted);
       
   251 		
       
   252 		iSmsBuffer.Extract(bufferPtr, iElementsExtracted, elementsToExtract);
       
   253 	
       
   254 		encodingToUse = iAlphabetConverter.FindBestAlternativeEncodingL(bufferPtr,
       
   255 										                				aSuggestedEncoding);
       
   256 		
       
   257 		CleanupStack::PopAndDestroy(buffer);
       
   258 		}
       
   259 
       
   260 	return encodingToUse;
       
   261 	} // CSmsBufferSegmenter::FindBestAlternativeEncodingL
       
   262 
       
   263 
       
   264 /**
       
   265  *  Ensures the segmentation buffer is of the specified length
       
   266  */
       
   267 void CSmsBufferSegmenter::CheckConvertedBufferAllocL(TInt aMaxLength)
       
   268 	{
       
   269 	LOGGSMU2("CSmsBufferSegmenter::CheckConvertedBufferAllocL(): aMaxLength=%d",
       
   270 			 aMaxLength);
       
   271 
       
   272 	if (iConvertedBuffer->Length()<aMaxLength)
       
   273 		{
       
   274 		iConvertedBuffer=iConvertedBuffer->ReAllocL(aMaxLength);
       
   275 		iConvertedBuffer->Des().SetLength(aMaxLength);
       
   276 		iConvertedBufferPtr.Set((TUint8*)iConvertedBuffer->Des().Ptr(),iConvertedBufferPtr.Length(),iConvertedBuffer->Length());
       
   277 		}
       
   278 	} // CSmsBufferSegmenter::CheckConvertedBufferAllocL
       
   279 
       
   280 
       
   281 /**
       
   282  *  Determines the number of converted elements that should be returned in the
       
   283  *  segment - called from DoSegmentNextL
       
   284  */
       
   285 TInt CSmsBufferSegmenter::ElementsToReturnFromConvertedBufferL(TInt aSegmentSize)
       
   286 	{
       
   287 	LOGGSMU2("CSmsBufferSegmenter::CheckConvertedBufferAllocL(): aSegmentSize=%d",
       
   288 			 aSegmentSize);
       
   289 
       
   290 	TInt elementCount=Min(aSegmentSize,iConvertedBufferPtr.Length());
       
   291 	if (iAlphabetConverter.Alphabet()==TSmsDataCodingScheme::ESmsAlphabet7Bit)
       
   292 		{
       
   293 		// For 7-bit, don't break an extended character across a segment
       
   294 		while ((elementCount>0)&&(iConvertedBufferPtr[elementCount-1]==KSms7BitAlphabetEscapeChar))
       
   295 			--elementCount;
       
   296 		if ((elementCount>0)&&(iConvertedBufferPtr[elementCount-1]==KSms7BitAlphabetEscapeChar))
       
   297 			User::Leave(KErrCorrupt);
       
   298 		}
       
   299 	return elementCount;
       
   300 	} // CSmsBufferSegmenter::ElementsToReturnFromConvertedBufferL
       
   301 
       
   302 
       
   303 //------------------------------------------------------------------------------------------------------------
       
   304 
       
   305 
       
   306 /**
       
   307  *  @capability None
       
   308  */
       
   309 EXPORT_C CSmsEMSBufferSegmenter* CSmsEMSBufferSegmenter::NewLC(CSmsAlphabetConverter& aAlphabetConverter,const CSmsBufferBase& aBuffer, TInt aSegmentSize)
       
   310 	{
       
   311 	LOGGSMU2("CSmsBufferSegmenter::NewLC(): aSegmentSize=%d", aSegmentSize);
       
   312 
       
   313 	CSmsEMSBufferSegmenter* self = new (ELeave) CSmsEMSBufferSegmenter(aAlphabetConverter, aBuffer,  aSegmentSize);
       
   314 	CleanupStack::PushL(self);
       
   315 	self->ConstructL();
       
   316 	return self;
       
   317 	} // CSmsEMSBufferSegmenter::NewLC
       
   318 
       
   319 
       
   320 CSmsEMSBufferSegmenter::CSmsEMSBufferSegmenter(CSmsAlphabetConverter& aAlphabetConverter,const CSmsBufferBase& aBuffer,TInt aSegmentSize) :
       
   321 	CSmsBufferSegmenter(aAlphabetConverter, aBuffer, aSegmentSize)
       
   322 	{
       
   323 	// NOP
       
   324 	} // CSmsEMSBufferSegmenter::CSmsEMSBufferSegmenter
       
   325 
       
   326 
       
   327 /**
       
   328  *  Extracts Segment size out of the Sms Buffer and converts it into aSegmentBuffer
       
   329  *  
       
   330  *  @return aSegmentBuffer - Buffer to convert into
       
   331  *  @param aSegement - Size of the FOREIGN segment to extract
       
   332  *  @return ETrue if last segment
       
   333  *  
       
   334  *  @capability None
       
   335  */
       
   336 EXPORT_C TBool CSmsEMSBufferSegmenter::SegmentNextL(TDes8& aSegmentBuffer, TInt aSegmentSize,
       
   337 		                                            TInt& aUnconvertedChars, TInt& aDowngradedChars,
       
   338 		                                            TSmsEncoding aEncoding)
       
   339 	{
       
   340 	LOGGSMU2("CSmsEMSBufferSegmenter::SegmentNext(): aSegmentSize=%d", aSegmentSize);
       
   341 
       
   342 	TBool ret=DoSegmentNextL(aSegmentBuffer, aSegmentSize, aUnconvertedChars, aDowngradedChars,
       
   343 							 aEncoding);
       
   344 
       
   345 	LOGGSMU2("CSmsEMSBufferSegmenter::SegmentNext() returns %d ", ret);
       
   346 
       
   347 	return ret;
       
   348 	} // CSmsEMSBufferSegmenter::SegmentNextL
       
   349 
       
   350 
       
   351 /**
       
   352  *  SegmentL encodes the amount of native chars into a SegmentBuffer
       
   353  *  WARNING: This method can not be used after a SegmentNextL
       
   354  *  
       
   355  *  @return aSegmentBuffer - Buffer to convert into.
       
   356  *  @param aNativeChars - Number of native chars to encode.
       
   357  *  @param aSegmentMax - The Ceiling the encode will not go past.
       
   358  *  @return The number of NATIVE characters added
       
   359  */
       
   360 TInt CSmsEMSBufferSegmenter::SegmentL(TDes8& aSegmentBuffer, TInt aNativeChars, TInt aSegmentMax,
       
   361 		                              TInt& aUnconvertedChars, TInt& aDowngradedChars,
       
   362 		                              TSmsEncoding aEncoding)
       
   363 	{
       
   364 	LOGGSMU3("CSmsEMSBufferSegmenter::SegmentL(): aNativeChars=%d, aSegmentMax=%d",
       
   365 			 aNativeChars, aSegmentMax);
       
   366 
       
   367 	__ASSERT_ALWAYS(iConvertedBufferPtr.Length()==0, User::Leave(KGsmuPanicBufferNotReset));
       
   368 	__ASSERT_ALWAYS(aNativeChars>0,User::Leave(KGsmuPanicIllegalSegmentSize));
       
   369 	__ASSERT_ALWAYS(aSegmentMax>0,User::Leave(KGsmuPanicIllegalSegmentSize));
       
   370 	__ASSERT_ALWAYS(aSegmentBuffer.MaxLength()>=aNativeChars,User::Leave(KGsmuPanicSegmentBufferTooSmall));
       
   371 
       
   372 	// Extract native chars from the buffer and convert
       
   373 	aSegmentBuffer.Zero();
       
   374 	TBuf<CSmsBufferBase::EMaxBufLength> nativeChars;
       
   375 	TInt nativeElemsToExtract=aNativeChars;
       
   376 	nativeElemsToExtract=Min(nativeElemsToExtract,nativeChars.MaxLength());
       
   377 	do
       
   378 		{
       
   379 		iSmsBuffer.Extract(nativeChars,iElementsExtracted, nativeElemsToExtract);
       
   380 
       
   381 		TInt  numberOfUnconvertibleCharacters;
       
   382 		TInt  numberOfDowngradedCharacters;
       
   383 		TPtrC8 smsCharsPtr=iAlphabetConverter.ConvertFromNativeL(nativeChars,
       
   384 				                                                 aEncoding,
       
   385 				                                                 numberOfUnconvertibleCharacters,
       
   386 				                                                 numberOfDowngradedCharacters);
       
   387 		aUnconvertedChars += numberOfUnconvertibleCharacters;
       
   388 		aDowngradedChars  += numberOfDowngradedCharacters;
       
   389 
       
   390 		if (smsCharsPtr.Length()>aSegmentMax)
       
   391 			--nativeElemsToExtract;
       
   392 		else
       
   393 			{
       
   394 			iElementsExtracted += nativeElemsToExtract;
       
   395 			aSegmentBuffer.Copy(smsCharsPtr.Ptr(),smsCharsPtr.Length());
       
   396 			return nativeElemsToExtract;
       
   397 			}
       
   398 		} while (nativeElemsToExtract);
       
   399 
       
   400 		return 0;
       
   401 	} // CSmsEMSBufferSegmenter::SegmentL
       
   402 
       
   403 
       
   404 //------------------------------------------------------------------------------------------------------------
       
   405 
       
   406 
       
   407 /**
       
   408  *  
       
   409  *  Constructor initialise iAlphabetConverter & iSmsBuffer
       
   410  *  
       
   411  *  @capability None
       
   412  */
       
   413 EXPORT_C TSmsBufferReassembler::TSmsBufferReassembler(CSmsAlphabetConverter& aAlphabetConverter,CSmsBufferBase& aBuffer)
       
   414 	: iAlphabetConverter(aAlphabetConverter),iSmsBuffer(aBuffer)
       
   415 	{
       
   416 	// NOP
       
   417 	} // TSmsBufferReassembler::TSmsBufferReassembler
       
   418 
       
   419 
       
   420 /**
       
   421  *  Reassembly is performed by iteratively calling the ReassembleNextL() method until all segments have been
       
   422  *  passed in.  When the last segment is passed, the aIsLast flag should be set to ETrue to validate that no
       
   423  *  unconverted User Data Elements remain, otherwise the method will leave with KErrCorrupt.
       
   424  *  
       
   425  *  @param aSegmentBuffer A segmented buffer
       
   426  *  @param aIsLast Set to true if it's the last segment
       
   427  *  
       
   428  *  @capability None
       
   429  */
       
   430 EXPORT_C void TSmsBufferReassembler::ReassembleNextL(const TDesC8& aSegmentBuffer,
       
   431 													 TSmsEncoding aEncoding,TBool aIsLast)
       
   432 	{
       
   433 	LOGGSMU3("TSmsBufferReassembler::ReassembleNextL(): aEncoding=%d aIsLast=%d",
       
   434 			 aEncoding, aIsLast);
       
   435 
       
   436 	TPtrC nativeChars=iAlphabetConverter.ConvertToNativeL(aSegmentBuffer, aEncoding);
       
   437 	iSmsBuffer.InsertL(iSmsBuffer.Length(),nativeChars);
       
   438 	if ((aIsLast)&&(iAlphabetConverter.UnconvertedUDElements().Length()>0))
       
   439 		{
       
   440 		User::Leave(KErrCorrupt);
       
   441 		}
       
   442 	} // TSmsBufferReassembler::ReassembleNextL