applayerprotocols/wappushsupport/WbxmlLib/WbConverter.cpp
changeset 0 b16258d2340f
equal deleted inserted replaced
-1:000000000000 0:b16258d2340f
       
     1 // Copyright (c) 1997-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 //
       
    15 
       
    16 #include <charconv.h>
       
    17 
       
    18 // #define __OUTPUT_WMLC	// Debug Stuff - uncomment to get wmlc output.
       
    19 
       
    20 #include <wbconverter.h>
       
    21 #include "WbToken.h"
       
    22 #include <mwbxmlconverterobserver.h>
       
    23 #include "WbEnum.h"
       
    24 #include "ByteList.h"
       
    25 
       
    26 #include <s32file.h>
       
    27 
       
    28 // Wap specific error codes defined here
       
    29 #include <wapengstd.h>
       
    30 
       
    31 //
       
    32 // Library routines
       
    33 //
       
    34 
       
    35 #ifndef EKA2
       
    36 GLDEF_C TInt E32Dll(TDllReason /*aReason*/)
       
    37 {
       
    38 	return (KErrNone);
       
    39 }
       
    40 #endif
       
    41 
       
    42 GLDEF_C void Panic (TWbxmlPanic aPanic)
       
    43 {
       
    44 	_LIT(KWbPanic,"WbxmlConverter");
       
    45 	User::Panic(KWbPanic ,aPanic);
       
    46 }
       
    47 
       
    48 //
       
    49 // class CWbxmlConverter - external API
       
    50 //
       
    51 
       
    52 const TInt KOutputBufferLength=1024;
       
    53 
       
    54 CWbxmlConverter::CWbxmlConverter(RFs& aFs)
       
    55 : iFs(aFs)
       
    56 {
       
    57 	__DECLARE_NAME(_S("CWbxmlConverter"));
       
    58 }
       
    59 
       
    60 EXPORT_C CWbxmlConverter* CWbxmlConverter::NewL(RFs& aFs, MWbxmlConverterObserver* aObserver)
       
    61 {
       
    62 	CWbxmlConverter* instance = NewLC(aFs, aObserver);
       
    63 	CleanupStack::Pop();
       
    64 	return instance;
       
    65 }
       
    66 
       
    67 EXPORT_C CWbxmlConverter* CWbxmlConverter::NewLC(RFs& aFs, MWbxmlConverterObserver* aObserver)
       
    68 {
       
    69 	CWbxmlConverter* instance = new (ELeave) CWbxmlConverter(aFs);
       
    70 	CleanupStack::PushL(instance);
       
    71 	instance->ConstructL(aObserver, NULL);
       
    72 	return instance;
       
    73 }
       
    74 
       
    75 EXPORT_C CWbxmlConverter* CWbxmlConverter::NewL(RFs& aFs, MWbxmlConverterObserver* aObserver, const TDesC* aCharacterEncoding)
       
    76 {
       
    77 	CWbxmlConverter* instance = new (ELeave) CWbxmlConverter(aFs);
       
    78 	CleanupStack::PushL(instance);
       
    79 	instance->ConstructL(aObserver, aCharacterEncoding);
       
    80 	CleanupStack::Pop();
       
    81 	return instance;
       
    82 }
       
    83 
       
    84 CWbxmlConverter::~CWbxmlConverter()
       
    85 {
       
    86 	delete[] iStringTable;
       
    87 	delete iPublicIdStr;
       
    88 	delete iByteList;
       
    89 	delete iCharsetConverter;
       
    90 	delete iOutputBuffer;
       
    91 
       
    92 	if( iTagStack )
       
    93 	{
       
    94 		iTagStack->Reset();
       
    95 		delete iTagStack;
       
    96 	}
       
    97 	
       
    98 	if (iTagArray)
       
    99 	{
       
   100 		if (iTagArray->Count())
       
   101 			iTagArray->ResetAndDestroy();
       
   102 		delete iTagArray;
       
   103 	}
       
   104 	if (iAttArray)
       
   105 	{
       
   106 		if (iAttArray->Count())
       
   107 			iAttArray->ResetAndDestroy();
       
   108 		delete iAttArray;
       
   109 	}
       
   110 #ifdef __OUTPUT_WMLC
       
   111 	iWmlcFile.Close();
       
   112 	iWmlcFs.Close();
       
   113 #endif
       
   114 }
       
   115 
       
   116 void CWbxmlConverter::ConstructL(MWbxmlConverterObserver* aObserver, const TDesC* aCharacterEncoding)
       
   117 {
       
   118 	iObserver = aObserver;
       
   119 	iState = EConvertVersion;
       
   120 	iByteList = CByteList::NewL();
       
   121 	iParsing = EParseTag;
       
   122 	iOpenQuote = EFalse;
       
   123 
       
   124 	iTagStack = new CArrayFixFlat<TUint16>(7);
       
   125 
       
   126 	iOutputBuffer = HBufC8::NewL(KOutputBufferLength);
       
   127 
       
   128 	iCharsetConverter = CCnvCharacterSetConverter::NewL();
       
   129 	if( aCharacterEncoding != NULL )
       
   130 	{
       
   131 		HBufC8* charset = HBufC8::NewLC(aCharacterEncoding->Length());
       
   132 		charset->Des().Copy(*aCharacterEncoding);
       
   133 		iWbxmlCharset = iCharsetConverter->ConvertStandardNameOfCharacterSetToIdentifierL(*charset, iFs);
       
   134 		CleanupStack::PopAndDestroy();
       
   135 	}
       
   136 #ifdef __OUTPUT_WMLC
       
   137 	_LIT(KWmlcFileName, "c:\\WmlcFile.wmlc");
       
   138 	User::LeaveIfError(iWmlcFs.Connect());
       
   139 	TInt error = iWmlcFile.Replace(iWmlcFs, KWmlcFileName, EFileWrite);
       
   140 	if( error != KErrNone )
       
   141 		User::Leave(EWapErrAccessViolation);
       
   142 #endif
       
   143 }
       
   144 
       
   145 EXPORT_C void CWbxmlConverter::ProcessDataL(HBufC8& aBuffer)
       
   146 {
       
   147 #ifdef __OUTPUT_WMLC
       
   148 	iWmlcFile.Write(aBuffer);
       
   149 #endif
       
   150 	iByteList->AddToListL(aBuffer);
       
   151 	HandleDataL();
       
   152 }
       
   153 
       
   154 EXPORT_C void CWbxmlConverter::CWbxmlConverter_Reserved1()
       
   155 {
       
   156 	// Must exist for Binary Compatibility
       
   157 }
       
   158 
       
   159 EXPORT_C void CWbxmlConverter::CommitL()
       
   160 {
       
   161 	HandleDataL();
       
   162 
       
   163 	// Document should be finished
       
   164 	if (iState != EConvertFinished)
       
   165 		User::Leave(EWapErrDocumentCorrupted);
       
   166 }
       
   167 
       
   168 
       
   169 EXPORT_C void MWbxmlConverterObserver::MWbxmlConverterObserver_Reserved1()
       
   170 {
       
   171 	// Must exist for Binary Compatibility
       
   172 }
       
   173 
       
   174 
       
   175 void CWbxmlConverter::SetNextStateL(TInt aResult, TConvertState aState)
       
   176 {
       
   177 	switch (aResult)
       
   178 	{
       
   179 	case KErrNone:
       
   180 		iState = aState;
       
   181 		break;
       
   182 	case KErrNotFound:
       
   183 		iByteList->RollBack();
       
   184 		break;
       
   185 	default:
       
   186 		User::Leave(EWapErrDocumentCorrupted);
       
   187 	}
       
   188 	iByteList->Commit();
       
   189 }
       
   190 
       
   191 TInt CWbxmlConverter::ConvertWbxmlVersionL()
       
   192 {
       
   193 	if (iByteList->Byte(&iWbxmlVersion,TRUE) != KErrNone)
       
   194 		return KErrNotFound;
       
   195 
       
   196 	BufferAndOutputL(KWbXmlVersion10);
       
   197 
       
   198 	return KErrNone;
       
   199 }
       
   200 
       
   201 TInt CWbxmlConverter::ConvertPublicIdValueL()
       
   202 {
       
   203 	TUint8 pubIDFirstByte = 0;
       
   204 	if( iByteList->Byte(&pubIDFirstByte,EFalse) != KErrNone )
       
   205 		return KErrNotFound;
       
   206 
       
   207 	if( pubIDFirstByte == 0 )
       
   208 	{
       
   209 		// The public id is in string table, index follows
       
   210 		iByteList->Inc(1);
       
   211 		if( ExtractMultiByte(&iPublicIdIndex,0) != KErrNone )
       
   212 			return KErrNotFound;
       
   213 		iPublicId = 0;
       
   214 	}
       
   215 	else
       
   216 	{
       
   217 		// "Normal" publicId, a multibyte
       
   218 		if (ExtractMultiByte(&iPublicId,0) != KErrNone)
       
   219 			return KErrNotFound;
       
   220 	}
       
   221 
       
   222 	return KErrNone;
       
   223 }
       
   224 
       
   225 TInt CWbxmlConverter::ConvertCharsetL()
       
   226 	{
       
   227 	TUint32 charsetMIB = 0;
       
   228 	// The chrset part of bytecode document was only introduced
       
   229 	// in WML 1.1.
       
   230 	if (iWbxmlVersion >= (TInt8) 0x01)
       
   231 		{
       
   232 		if (ExtractMultiByte(&charsetMIB,0) != KErrNone)
       
   233 			return KErrNotFound;
       
   234 		}
       
   235 
       
   236 	// if the charset wasn't already provided by HTTP, we set it according
       
   237 	// to the bytecode content charset
       
   238 	if( !iWbxmlCharset )
       
   239 		{
       
   240 		if( charsetMIB != 0 )
       
   241 			{
       
   242 			iWbxmlCharset = iCharsetConverter->ConvertMibEnumOfCharacterSetToIdentifierL(charsetMIB, iFs);
       
   243 			}
       
   244 
       
   245 		if( iWbxmlCharset == 0 )
       
   246 			{
       
   247 			// Patch in the most common results
       
   248 			switch(charsetMIB)
       
   249 				{
       
   250 				case 4:
       
   251 					iWbxmlCharset = KCharacterSetIdentifierIso88591;
       
   252 					break;
       
   253 				case 5:
       
   254 					iWbxmlCharset = KCharacterSetIdentifierIso88592;
       
   255 					break;
       
   256 				case 7:
       
   257 					iWbxmlCharset = KCharacterSetIdentifierIso88594;
       
   258 					break;
       
   259 				case 8:
       
   260 					iWbxmlCharset = KCharacterSetIdentifierIso88595;
       
   261 					break;
       
   262 				case 10:
       
   263 					iWbxmlCharset = KCharacterSetIdentifierIso88597;
       
   264 					break;
       
   265 				case 12:
       
   266 					iWbxmlCharset = KCharacterSetIdentifierIso88599;
       
   267 					break;
       
   268 				case 103:	// UTF7
       
   269 					iWbxmlCharset = KCharacterSetIdentifierUtf7;
       
   270 					break;
       
   271 				case 104:
       
   272 					iWbxmlCharset = KCharacterSetIdentifierImapUtf7;
       
   273 					break;
       
   274 				case 0:
       
   275 					// Default case
       
   276 				case 106:	// UTF8
       
   277 					// If the charset from bytecode was 'unknown' (0) or the converter couldn't
       
   278 					// match the mib number to known charset identifiers we use 
       
   279 					// the default charset: UTF-8
       
   280 					iWbxmlCharset = KCharacterSetIdentifierUtf8;
       
   281 					break;
       
   282 				default:
       
   283 					return KErrNotSupported;
       
   284 				}
       
   285 			}
       
   286 		// Now we need to inform our observer what charset we are using
       
   287 		HBufC8* charSetName = iCharsetConverter->ConvertCharacterSetIdentifierToStandardNameL(iWbxmlCharset, iFs);
       
   288 		CleanupStack::PushL(charSetName);
       
   289 		iObserver->HandleWbxmlEncodingUpdateL(charSetName);
       
   290 		CleanupStack::PopAndDestroy();		// charSetName
       
   291 		}
       
   292 	return KErrNone;
       
   293 	}
       
   294 
       
   295 TInt CWbxmlConverter::ConvertStringTableL()
       
   296 {
       
   297 	if (iStringTable == NULL)
       
   298 	{
       
   299 		// Need "static" instance variable for streaming iStringTable!
       
   300 		if( ExtractMultiByte(&iContinue,0) != KErrNone )
       
   301 			return KErrNotFound;
       
   302 
       
   303 		if (iContinue == 0)
       
   304 			return KErrNone;
       
   305 
       
   306 		iStringTable = HBufC8::NewL(iContinue);
       
   307 	}
       
   308 
       
   309 	if (iContinue != 0)
       
   310 	{
       
   311 		// Note: String table is 8bit data
       
   312 		TUint8 byte = 0;
       
   313 		while (iContinue)
       
   314 		{
       
   315 			if ((iByteList->Byte(&byte,TRUE)) != KErrNone)
       
   316 			{
       
   317 				iByteList->Commit();
       
   318 				return KErrNotFound;
       
   319 			}
       
   320 
       
   321 			iStringTable->Des().Append(byte);
       
   322 			iContinue--;
       
   323 		}
       
   324 	}
       
   325 	// Ensure that string table is zero terminated
       
   326 	TInt length = iStringTable->Length();
       
   327 	if( iStringTable->Des()[length-1] != 0 )
       
   328 		{
       
   329 		// Make table one character bigger, and make sure last character is zero terminator
       
   330 		iStringTable = iStringTable->ReAllocL(length + 1);
       
   331 		iStringTable->Des().Append(0);
       
   332 		}
       
   333 	return KErrNone;
       
   334 }
       
   335 
       
   336 TInt CWbxmlConverter::ConvertPublicIdNameL()
       
   337 {
       
   338 	HBufC* fileName = NULL;
       
   339 
       
   340 	switch (iPublicId)
       
   341 	{
       
   342 	case KWbxmlIdIndex:
       
   343 		// Meaning: Followed by string table index for public id
       
   344 		User::Leave(EWapErrUnknownDocument);
       
   345 		break;
       
   346 	case KWbxmlIdUnknown:
       
   347 		// Meaning: unknown or missing
       
   348 		// WML spec says that unknown DTD is handled as well as possible
       
   349 		// so we presume it's supposed to be WML 1.1
       
   350 		fileName = FindTokenFileL(KWbTokenDatabaseWml11);
       
   351 		CleanupStack::PushL(fileName);
       
   352 		OpenTokenFileL(*fileName);
       
   353 		CleanupStack::PopAndDestroy(); // fileName
       
   354 
       
   355 		// Waste the publicID string received from the token file
       
   356 		delete iPublicIdStr;
       
   357 		// ...and replace it with the one from the string table
       
   358 		{
       
   359 			TPtrC8 remainderFromIndex = iStringTable->Des().Mid(iPublicIdIndex);
       
   360 			TInt idLen = remainderFromIndex.Locate('\0');
       
   361 			// We trust that the string table is properly constructed and
       
   362 			// contains the terminating null...
       
   363 			if( idLen == KErrNotFound )
       
   364 				return KErrNotFound;		// Ah well, Our trust was misplaced!
       
   365 			TPtrC8 publicIdString = remainderFromIndex.Left(idLen);
       
   366 			HBufC16* convertedBuffer = CharsetConvertDataL(publicIdString);
       
   367 			CleanupStack::PushL(convertedBuffer);
       
   368 			if( convertedBuffer == NULL )
       
   369 			{
       
   370 			// Conversion failed!!!
       
   371 				CleanupStack::PopAndDestroy(); // convertedBuffer
       
   372 				return KErrCorrupt;
       
   373 			}
       
   374 			iPublicIdStr = HBufC8::NewL(convertedBuffer->Length());
       
   375 			iPublicIdStr->Des().Copy(*convertedBuffer);
       
   376 			CleanupStack::PopAndDestroy(); // convertedBuffer
       
   377 		}
       
   378 		break;
       
   379 	case KWbxmlIdWta10:
       
   380 		// Meaning: "-//WAPFORUM//DTD WTA 1.0//EN" (WTA Event 1.0)
       
   381 		// WTA is not supported
       
   382 		User::Leave(EWapErrUnknownDocument);
       
   383 		break;
       
   384 	case KWbxmlIdWml11:
       
   385 		// Meaning: "-//WAPFORUM//DTD WML 1.1//EN" (WML 1.1)
       
   386 		fileName = FindTokenFileL(KWbTokenDatabaseWml11);
       
   387 		CleanupStack::PushL(fileName);
       
   388 		OpenTokenFileL(*fileName);
       
   389 		CleanupStack::PopAndDestroy(); // fileName
       
   390 		break;
       
   391 	case KWbxmlIdWml12:
       
   392 		// Meaning: "-//WAPFORUM//DTD WML 1.1//EN" (WML 1.2)
       
   393 		fileName = FindTokenFileL(KWbTokenDatabaseWml12);
       
   394 		CleanupStack::PushL(fileName);
       
   395 		OpenTokenFileL(*fileName);
       
   396 		CleanupStack::PopAndDestroy(); // fileName
       
   397 		break;
       
   398 	case KWbxmlIdSI:
       
   399 		// Meaning: "-//WAPFORUM//DTD SI 1.0//EN" (Push Service Indication 1.0)
       
   400 		fileName = FindTokenFileL(KWbTokenDatabaseSI10);
       
   401 		CleanupStack::PushL(fileName);
       
   402 		OpenTokenFileL(*fileName);
       
   403 		CleanupStack::PopAndDestroy(); // fileName
       
   404 		break;
       
   405 	case KWbxmlIdSL:
       
   406 		// Meaning: "-//WAPFORUM//DTD SL 1.0//EN" (Push Service Load 1.0)
       
   407 		fileName = FindTokenFileL(KWbTokenDatabaseSL10);
       
   408 		CleanupStack::PushL(fileName);
       
   409 		OpenTokenFileL(*fileName);
       
   410 		CleanupStack::PopAndDestroy(); // fileName
       
   411 		break;
       
   412 	default:
       
   413 		// Meaning: 0x05 - 0x7F recerved
       
   414 		// WML spec says that unknown DTD is handled as well as possible
       
   415 		// so we presume it's supposed to be WML 1.1
       
   416 		fileName = FindTokenFileL(KWbTokenDatabaseWml11);
       
   417 		CleanupStack::PushL(fileName);
       
   418 		OpenTokenFileL(*fileName);
       
   419 		CleanupStack::PopAndDestroy(); // fileName
       
   420 		break;
       
   421 	}
       
   422 
       
   423 	switch (iPublicId)
       
   424 		{
       
   425 	case KWbxmlIdWml11:
       
   426 		BufferAndOutputL(KWbPublicIdStartWml);
       
   427 		BufferAndOutputL(*iPublicIdStr); // ...you get HBufC8&
       
   428 		BufferAndOutputL(KWbPublicIdEnd11);
       
   429 		break;
       
   430 	case KWbxmlIdSI:
       
   431 		BufferAndOutputL(KWbPublicIdStartSi);
       
   432 		BufferAndOutputL(*iPublicIdStr); // ...you get HBufC8&
       
   433 		BufferAndOutputL(KWbPublicIdEndSI10);
       
   434 		break;
       
   435 	case KWbxmlIdSL:
       
   436 		BufferAndOutputL(KWbPublicIdStartSl);
       
   437 		BufferAndOutputL(*iPublicIdStr); // ...you get HBufC8&
       
   438 		BufferAndOutputL(KWbPublicIdEndSL10);
       
   439 		break;
       
   440 	case KWbxmlIdWml12:
       
   441 	default:
       
   442 		BufferAndOutputL(KWbPublicIdStartWml);
       
   443 		BufferAndOutputL(*iPublicIdStr); // ...you get HBufC8&
       
   444 		BufferAndOutputL(KWbPublicIdEnd12);
       
   445 		break;
       
   446 		}
       
   447 	
       
   448 	return KErrNone;
       
   449 }
       
   450 
       
   451 
       
   452 void CWbxmlConverter::HandleDataL()
       
   453 {
       
   454 	TInt result = KErrNone;
       
   455 
       
   456 	do
       
   457 	{
       
   458 		switch (iState)
       
   459 		{
       
   460 		case EConvertVersion:
       
   461 			result = ConvertWbxmlVersionL();
       
   462 			SetNextStateL(result,EConvertPublicIdValue);
       
   463 			break;
       
   464 		case EConvertPublicIdValue:
       
   465 			result = ConvertPublicIdValueL();
       
   466 			SetNextStateL(result,EConvertCharset);
       
   467 			break;
       
   468 		case EConvertCharset:
       
   469 			result = ConvertCharsetL();
       
   470 			SetNextStateL(result,EConvertStringTable);
       
   471 			break;
       
   472 		case EConvertStringTable:
       
   473 			result = ConvertStringTableL();
       
   474 			SetNextStateL(result,EConvertPublicIdName);
       
   475 			break;
       
   476 		case EConvertPublicIdName:
       
   477 			result = ConvertPublicIdNameL();
       
   478 			SetNextStateL(result,EConvertData);
       
   479 			break;
       
   480 		case EConvertData:
       
   481 			result = ConvertDataL();
       
   482 			SetNextStateL(result,EConvertFinished);
       
   483 			break;
       
   484 		case EConvertFinished:
       
   485 			if(iOutputBuffer!=NULL && iOutputBuffer->Length())
       
   486 				{
       
   487 				// Buffer still has some data : Lose ownership to the observer
       
   488 				TInt returnValue = iObserver->HandleWbxmlOutputL(iOutputBuffer);	
       
   489 				if( returnValue != KErrNone )
       
   490 					User::Leave(returnValue);
       
   491 				iOutputBuffer = NULL;
       
   492 				}
       
   493 			return;
       
   494 		default:
       
   495 			iState = EConvertError;
       
   496 			return;
       
   497 		}
       
   498 	}
       
   499 	while (result == KErrNone && iState != EConvertFinished);
       
   500 }
       
   501 
       
   502 TInt CWbxmlConverter::ConvertDataL()
       
   503 {
       
   504 	// Continue streaming in the middle of string
       
   505 	if (iContinue != 0)
       
   506 	{
       
   507 		switch (iContinue)
       
   508 		{
       
   509 		case EGotoStreaming:
       
   510 			if (ConvertDataStreamingL() != KErrNone)
       
   511 				return KErrNotFound;
       
   512 			break;
       
   513 		case EGotoString:
       
   514 			if (ConvertDataStringL() != KErrNone)
       
   515 				return KErrNotFound;
       
   516 			break;
       
   517 		case EGotoOpaque:
       
   518 			if (ConvertOpaqueDataL() != KErrNone)
       
   519 				return KErrNotFound;
       
   520 			break;
       
   521 		}
       
   522 		iContinue = 0;
       
   523 	}
       
   524 
       
   525 	TUint32 multiByte = 0;
       
   526 	TUint8 byte = 0;
       
   527 
       
   528 	FOREVER
       
   529 	{
       
   530 		byte = (TUint8) -1;
       
   531 		if (iByteList->Byte(&byte,TRUE) != KErrNone)
       
   532 		{
       
   533 			// HACK: At the end of all data inc(1) fails and we get KErrNotFound
       
   534 			if (iTagIndex != 1 || byte != 1)
       
   535 			{
       
   536 				// it was real error
       
   537 				return KErrNotFound;
       
   538 			}
       
   539 
       
   540 		}
       
   541 
       
   542 		switch (byte)
       
   543 		{
       
   544 		case 0x00: // SWITCH_PAGE
       
   545 			// NOTE: not supported, not used in WML 1.1
       
   546 			// bytecode SWITCH_PAGE not implemented
       
   547 			iByteList->Commit();
       
   548 			break;
       
   549 
       
   550 		case 0x01: // END
       
   551 			if (iParsing == EParseTag || iParsing == EParseNot)
       
   552 			{
       
   553 				if (iParsing == EParseNot)
       
   554 				{
       
   555 					iParsing = EParseTag;
       
   556 				}
       
   557 
       
   558 				if (iTagIndex)
       
   559 				{
       
   560 					iTagIndex--;
       
   561 					TUint16 stackEntry = iTagStack->At(iTagIndex);
       
   562 					if( stackEntry != KWbxmlSkipLiteralEndTagMagicToken )
       
   563 					{
       
   564 						BufferAndOutputL(KWbTagStartClose);
       
   565 						BufferAndOutputL(*(iTagArray->At(stackEntry&~0xc0)->iBuf));
       
   566 						BufferAndOutputL(KWbTagEndWithContent);
       
   567 					}
       
   568 					iTagStack->Delete(iTagIndex);
       
   569 
       
   570 					// Done, get out
       
   571 					if (iTagIndex == 0)
       
   572 					{
       
   573 						iByteList->Commit();
       
   574 						return KErrNone;
       
   575 					}
       
   576 				}
       
   577 				else
       
   578 				{
       
   579 					// Corrupted bytecode
       
   580 					User::Leave(EWapErrDocumentCorrupted);
       
   581 				}
       
   582 			}
       
   583 			else if (iParsing == EParseAttrs)
       
   584 			{
       
   585 				iParsing = EParseTag;
       
   586 
       
   587 				if( !iRestrictedOutput )
       
   588 				{
       
   589 					if (iOpenQuote)
       
   590 					{
       
   591 						BufferAndOutputL(KWbQuote);
       
   592 						iOpenQuote = EFalse;
       
   593 					}
       
   594 					BufferAndOutputL(hasContent?KWbTagEndWithContent():KWbTagEndWithoutContent());
       
   595 				}
       
   596 				else
       
   597 					iRestrictedOutput = EFalse;
       
   598 			}
       
   599 			else
       
   600 			{
       
   601 				// default case to catch impossible errors
       
   602 				// Corrupted bytecode
       
   603 				User::Leave(EWapErrDocumentCorrupted);
       
   604 			}
       
   605 			iByteList->Commit();
       
   606 			
       
   607 			// This will be true when a message is defined with attributes
       
   608 			// but no data
       
   609 			if (iTagIndex == 0)
       
   610 				{
       
   611 				return KErrNone;
       
   612 				}
       
   613 			break;
       
   614 
       
   615 		case 0x02: // ENTITY
       
   616 			if (ExtractMultiByte(&multiByte,0) != KErrNone)
       
   617 				return KErrNotFound;
       
   618 			OutputL(multiByte);
       
   619 			iByteList->Commit();
       
   620 			break;
       
   621 
       
   622 		case 0x40: // EXT_I_0
       
   623 		case 0x41: // EXT_I_1
       
   624 		case 0x42: // EXT_I_2
       
   625 			iVariable = byte;
       
   626 			BufferAndOutputL(KWbVariableStart);
       
   627 			if (ConvertDataStreamingL() != KErrNone)
       
   628 			{
       
   629 				iContinue = EGotoStreaming;
       
   630 				return KErrNotFound;
       
   631 			}
       
   632 			iByteList->Commit();
       
   633 			break;
       
   634 
       
   635 		case 0x03: // INLINE STRING
       
   636 			if (iParsing == EParseTag)
       
   637 			{
       
   638 				iParsing = EParseNot;
       
   639 			}
       
   640 
       
   641 			if (ConvertDataStreamingL() != KErrNone)
       
   642 			{
       
   643 				iContinue = EGotoStreaming;
       
   644 				return KErrNotFound;
       
   645 			}
       
   646 			iByteList->Commit();
       
   647 			break;
       
   648 
       
   649 		case 0x80: // EXT_T_0
       
   650 		case 0x81: // EXT_T_1
       
   651 		case 0x82: // EXT_T_2
       
   652 			iVariable = byte;
       
   653 			BufferAndOutputL(KWbVariableStart);
       
   654 			if (ConvertDataStringL() != KErrNone)
       
   655 			{
       
   656 				iContinue = EGotoString;
       
   657 				return KErrNotFound;
       
   658 			}
       
   659 			iByteList->Commit();
       
   660 			break;
       
   661 
       
   662 		case 0x83: // STR_T
       
   663 			if (ConvertDataStringL() != KErrNone)
       
   664 			{
       
   665 				iContinue = EGotoString;
       
   666 				return KErrNotFound;
       
   667 			}
       
   668 			iByteList->Commit();
       
   669 			break;
       
   670 
       
   671 		case 0x43: // PI
       
   672 			// not supported, not used in WML 1.1
       
   673 			// bytecode PI not implemented
       
   674 			iByteList->Commit();
       
   675 			break;
       
   676 
       
   677 		// We will ignore all the uknown tags and their attributes encoded as literals
       
   678 		// (LITERAL, LITERAL_C and LITERAL_CA). The content of these elements is, however,
       
   679 		// treated normally (unless it contains literals, too :)
       
   680 		case 0x04: // LITERAL
       
   681 			iByteList->Commit();
       
   682 			break;
       
   683 		case 0xC3: // OPAQUE
       
   684 			if (ConvertOpaqueDataL() != KErrNone)
       
   685 			{
       
   686 				iContinue = EGotoOpaque;
       
   687 				return KErrNotFound;
       
   688 			}
       
   689 			iByteList->Commit();
       
   690 			break;
       
   691 		case 0x44: // LITERAL_C
       
   692 		case 0xC4: // LITERAL_CA
       
   693 			iRestrictedOutput = ETrue;
       
   694 			// FLOWTHROUGH
       
   695 		default:
       
   696 			{
       
   697 			if (iParsing == EParseTag || iParsing == EParseNot)
       
   698 			{
       
   699 				if (iParsing == EParseNot)
       
   700 				{
       
   701 					iParsing = EParseTag;
       
   702 				}
       
   703 
       
   704 				if( !iRestrictedOutput )
       
   705 				{
       
   706 					BufferAndOutputL(KWbTagStart);
       
   707 
       
   708 					// tag name
       
   709 					BufferAndOutputL(*(iTagArray->At(byte&0x3F)->iBuf));
       
   710 				}
       
   711 
       
   712 				hasAttrs = (TUint8) (byte & 0x80);
       
   713 				hasContent = (TUint8) (byte & 0x40);
       
   714 
       
   715 				if (hasContent)
       
   716 				{
       
   717 					iTagIndex++;
       
   718 					if( iRestrictedOutput )
       
   719 						iTagStack->AppendL( KWbxmlSkipLiteralEndTagMagicToken );
       
   720 					else
       
   721 						iTagStack->AppendL( TUint16(byte) );
       
   722 				}
       
   723 
       
   724 				if (hasAttrs)
       
   725 					iParsing = EParseAttrs;
       
   726 				else if( !iRestrictedOutput )
       
   727 					BufferAndOutputL(hasContent ? KWbTagEndWithContent() : KWbTagEndWithoutContent() );
       
   728 
       
   729 				if( iRestrictedOutput && !hasAttrs )
       
   730 				// The content will be processed as usual. However, if we had attributes
       
   731 				// we shall discard them, too
       
   732 					iRestrictedOutput = EFalse;
       
   733 			}
       
   734 
       
   735 			// Attr names and values
       
   736 			else if( !iRestrictedOutput )
       
   737 			{
       
   738 					
       
   739 
       
   740 				// starting new attribute
       
   741 				if (byte<128)
       
   742 				{
       
   743 					if (iOpenQuote)
       
   744 					{
       
   745 						BufferAndOutputL(KWbQuote);
       
   746 						iOpenQuote = EFalse;
       
   747 					}
       
   748 
       
   749 					// attribute name requires starting space, value not
       
   750 					BufferAndOutputL(KWbSpace);
       
   751 				}
       
   752 
       
   753 				if( byte >= iAttArray->Count() )
       
   754 					User::Leave(EWapErrDocumentCorrupted);
       
   755 
       
   756 				// AttrName can be either 'ALIGN="CENTER"' or 'ALIGN="'
       
   757 				// format and followed by several AttrValues or strings.
       
   758 				// We have to scan AttrName to know when quotes are open
       
   759 				// so that we close them no more and no less than once.
       
   760 				// NOTE: quotes in strings are data, not attr escaping.
       
   761 				
       
   762 				if (OutputCheckQuoteL(*(iAttArray->At(byte)->iBuf)))
       
   763 					iOpenQuote = ETrue;
       
   764 			}
       
   765 			iByteList->Commit();
       
   766 			break;
       
   767 			}
       
   768 
       
   769 		} // switch (byte)
       
   770 
       
   771 	} // FOREVER
       
   772 }
       
   773 
       
   774 // Output Opaque data
       
   775 TInt CWbxmlConverter::ConvertOpaqueDataL()
       
   776 	{
       
   777 	iByteList->Commit();
       
   778 
       
   779 	TUint32 multiByte = 0;
       
   780 	if (ExtractMultiByte(&multiByte,0) != KErrNone)
       
   781 		return KErrNotFound;
       
   782 
       
   783 	TUint32 count = multiByte;
       
   784 	TUint8 byte = 0;
       
   785 	const TInt KBufferSegment = 20;
       
   786 	HBufC8* buffer = HBufC8::NewLC(KBufferSegment);
       
   787 
       
   788 	while (count != 0)
       
   789 	{
       
   790 		if (iByteList->Byte(&byte,TRUE) != KErrNone)
       
   791 		{
       
   792 			CleanupStack::PopAndDestroy(); // buffer
       
   793 			return KErrNotFound;
       
   794 		}
       
   795 
       
   796 		buffer->Des().Append(&byte,1);
       
   797 		if( buffer->Des().MaxLength() == buffer->Length() )
       
   798 		{
       
   799 			buffer = buffer->ReAllocL(buffer->Length() + KBufferSegment);
       
   800 			CleanupStack::Pop(); // the old buffer
       
   801 			CleanupStack::PushL(buffer);
       
   802 		}
       
   803 		count--;
       
   804 	}
       
   805 
       
   806 	HBufC16* convertedBuffer = FormatDateStringL(*buffer);
       
   807 	CleanupStack::PopAndDestroy(); // buffer
       
   808 	CleanupStack::PushL(convertedBuffer);
       
   809 
       
   810 	if( convertedBuffer == NULL )
       
   811 	{
       
   812 	// We could not convert the document!
       
   813 	// but no one checks the return value
       
   814 	// so I don't care... :(
       
   815 		CleanupStack::PopAndDestroy();  // convertedBuffer
       
   816 		iByteList->Commit();			// We can do nothing more with this data so dump it
       
   817 		return KErrCorrupt;
       
   818 	}
       
   819 
       
   820 	buffer = HBufC8::NewL(convertedBuffer->Length());
       
   821 	buffer->Des().Copy(*convertedBuffer);
       
   822 	CleanupStack::PopAndDestroy(); // convertedBuffer
       
   823 	CleanupStack::PushL(buffer);
       
   824 
       
   825 	BufferAndOutputL(*buffer);
       
   826 
       
   827 	iByteList->Commit();
       
   828 	CleanupStack::PopAndDestroy(); // buffer
       
   829 
       
   830 	FinishStringL();
       
   831 	iByteList->Commit();
       
   832 	return KErrNone;
       
   833 	}
       
   834 
       
   835 // OutputL bytes from streamed inline data
       
   836 TInt CWbxmlConverter::ConvertDataStreamingL()
       
   837 {
       
   838 	iByteList->Commit();
       
   839 
       
   840 	TUint8 byte = 0;
       
   841 	const TInt KBufferSegment = 20;
       
   842 	HBufC8* buffer = HBufC8::NewLC(KBufferSegment);
       
   843 
       
   844 	// Todo: optimization check how much data is already available and OutputL all at the same time
       
   845 	FOREVER
       
   846 	{
       
   847 		if (iByteList->Byte(&byte,TRUE) != KErrNone)
       
   848 		{
       
   849 			CleanupStack::PopAndDestroy(); // buffer
       
   850 			return KErrNotFound;
       
   851 		}
       
   852 
       
   853 		if (byte == 0)
       
   854 			break;
       
   855 
       
   856 		buffer->Des().Append(&byte,1);
       
   857 		if( buffer->Des().MaxLength() == buffer->Length() )
       
   858 		{
       
   859 			buffer = buffer->ReAllocL(buffer->Length() + KBufferSegment);
       
   860 			CleanupStack::Pop(); // the old buffer
       
   861 			CleanupStack::PushL(buffer);
       
   862 		}
       
   863 	}
       
   864 
       
   865 	HBufC16* convertedBuffer = CharsetConvertDataL(*buffer);
       
   866 	CleanupStack::PopAndDestroy(); // buffer
       
   867 	CleanupStack::PushL(convertedBuffer);
       
   868 	if( convertedBuffer == NULL )
       
   869 	{
       
   870 	// We could not convert the document!
       
   871 	// but no one checks the return value
       
   872 	// so I don't care... :(
       
   873 		CleanupStack::PopAndDestroy();  // convertedBuffer
       
   874 		iByteList->Commit();			// We can do nothing more with this data so dump it
       
   875 		return KErrCorrupt;
       
   876 	}
       
   877 
       
   878 	convertedBuffer = ReplaceCharacterEntitiesL(convertedBuffer);
       
   879 	CleanupStack::Pop(); // convertedBuffer, which might have been reallocated
       
   880 	CleanupStack::PushL(convertedBuffer); // the new converted buffer
       
   881 
       
   882 	buffer = HBufC8::NewL(convertedBuffer->Length());
       
   883 	buffer->Des().Copy(*convertedBuffer);
       
   884 	CleanupStack::PopAndDestroy(); // convertedBuffer
       
   885 	CleanupStack::PushL(buffer);
       
   886 
       
   887 	BufferAndOutputL(*buffer);
       
   888 
       
   889 	iByteList->Commit();
       
   890 	CleanupStack::PopAndDestroy(); // buffer
       
   891 
       
   892 	FinishStringL();
       
   893 	iByteList->Commit();
       
   894 	return KErrNone;
       
   895 }
       
   896 
       
   897 // OutputL bytes from internal stringtable
       
   898 TInt CWbxmlConverter::ConvertDataStringL()
       
   899 {
       
   900 	if( iStringTable == NULL )
       
   901 		// There can not be string table references withing a document that hasn't got a string table!
       
   902 		User::Leave(EWapErrDocumentCorrupted);
       
   903 
       
   904 	iByteList->Commit();
       
   905 
       
   906 	TUint32 multiByte = 0;
       
   907 	if (ExtractMultiByte(&multiByte,0) != KErrNone)
       
   908 		return KErrNotFound;
       
   909 
       
   910 	TInt count = 0;
       
   911 	while (iStringTable->Ptr()[multiByte + count] != 0)
       
   912 		count++;
       
   913 
       
   914 	if (!count)
       
   915 		return KErrNone;
       
   916 
       
   917 	if (TUint ((*iStringTable).Length()) < multiByte + count)
       
   918 		return KErrCorrupt;
       
   919 
       
   920 	TPtrC8 referedString = (*iStringTable).Mid(multiByte,count);
       
   921 	HBufC16* convertedBuffer = CharsetConvertDataL(referedString);
       
   922 	CleanupStack::PushL(convertedBuffer);
       
   923 	if( convertedBuffer == NULL )
       
   924 	{
       
   925 	// We could not convert the document!
       
   926 	// but no one checks the return value
       
   927 	// so I don't care... :(
       
   928 		CleanupStack::PopAndDestroy(); // convertedBuffer
       
   929 		iByteList->Commit();			// We can do nothing more with this data so dump it
       
   930 		return KErrCorrupt;
       
   931 	}
       
   932 
       
   933 	convertedBuffer = ReplaceCharacterEntitiesL(convertedBuffer);
       
   934 	CleanupStack::Pop(); // convertedBuffer, which might have been reallocated
       
   935 	CleanupStack::PushL(convertedBuffer); // the new converted buffer
       
   936 
       
   937 	HBufC8* buffer = HBufC8::NewL(convertedBuffer->Length());
       
   938 	buffer->Des().Copy(*convertedBuffer);	// to 8-bit buffer...
       
   939 	CleanupStack::PopAndDestroy(); // convertedBuffer
       
   940 	CleanupStack::PushL(buffer);
       
   941 	BufferAndOutputL(*buffer);
       
   942 	CleanupStack::PopAndDestroy(); // buffer
       
   943 
       
   944 	FinishStringL();
       
   945 	iByteList->Commit();
       
   946 
       
   947 	return KErrNone;
       
   948 }
       
   949 
       
   950 TInt CWbxmlConverter::OpenTokenFileL(HBufC& aFileName)
       
   951 {
       
   952 	// Design note: we should ask library user to give us token file
       
   953 	// but since this is used only by WML 1.1, it's not our problem.
       
   954 	// Anyway, that's why interface is HBufC& aFileName.
       
   955 
       
   956 	if (iTagArray)
       
   957 	{
       
   958 		if (iTagArray->Count())
       
   959 			iTagArray->ResetAndDestroy();
       
   960 		delete iTagArray;
       
   961 		iTagArray = NULL;
       
   962 	}
       
   963 	if (iAttArray)
       
   964 	{
       
   965 		if (iAttArray->Count())
       
   966 			iAttArray->ResetAndDestroy();
       
   967 		delete iAttArray;
       
   968 		iAttArray = NULL;
       
   969 	}
       
   970 
       
   971 	//
       
   972 
       
   973 	RFileReadStream stream;
       
   974 	if (stream.Open(iFs,aFileName,EFileShareReadersOnly) != KErrNone)
       
   975 	{
       
   976 		User::Leave(EWapErrUnknownDocument);
       
   977 	}
       
   978 	else
       
   979 	{
       
   980 		CleanupClosePushL(stream);
       
   981 
       
   982 		HBufC8* strBuffer = HBufC8::NewL(256);
       
   983 		CleanupStack::PushL(strBuffer);
       
   984 		TInt i;
       
   985 		CWbxmlToken* token;
       
   986 
       
   987 		//
       
   988 		// PublicId
       
   989 		TRAPD(error,ReadTokenFileL(stream,*strBuffer));
       
   990 		if (error != KErrNone)
       
   991 			{
       
   992 			User::Leave(EWapErrUnknownDocument);
       
   993 			}
       
   994 
       
   995 		iPublicIdStr = strBuffer->AllocL();
       
   996 
       
   997 		//
       
   998 		// Tag tokens
       
   999 		iTagArray = new (ELeave) CArrayPtrFlat<CWbxmlToken>(0x40);
       
  1000 		for (i = 0; i < 0x40; i++)
       
  1001 		{
       
  1002 			TRAP(error,ReadTokenFileL(stream,*strBuffer));
       
  1003 			if (error == KErrNone)
       
  1004 			{
       
  1005 				token = new (ELeave) CWbxmlToken;
       
  1006 				CleanupStack::PushL(token);
       
  1007 				token->SetTextL(*strBuffer);
       
  1008 				iTagArray->AppendL(token);
       
  1009 				CleanupStack::Pop(token);
       
  1010 			}
       
  1011 			else
       
  1012 			{
       
  1013 				User::Leave(EWapErrUnknownDocument);
       
  1014 			}
       
  1015 		}
       
  1016 		
       
  1017 		//
       
  1018 		// Attribute names
       
  1019 		iAttArray = new (ELeave) CArrayPtrFlat<CWbxmlToken>(256);
       
  1020 		for (i = 0; i < 256; i++)
       
  1021 		{
       
  1022 			TRAP(error,ReadTokenFileL(stream,*strBuffer));
       
  1023 			if (error == KErrEof)
       
  1024 				break;
       
  1025 			if (error == KErrNone)
       
  1026 			{
       
  1027 				token = new (ELeave) CWbxmlToken;
       
  1028 				CleanupStack::PushL(token);
       
  1029 				token->SetTextL(*strBuffer);
       
  1030 				iAttArray->AppendL(token);
       
  1031 				CleanupStack::Pop(token);
       
  1032 			}
       
  1033 			else
       
  1034 			{
       
  1035 				User::Leave(EWapErrUnknownDocument);
       
  1036 			}
       
  1037 		}
       
  1038 		
       
  1039 		CleanupStack::PopAndDestroy(2); // strBuffer and stream
       
  1040 	}
       
  1041 
       
  1042 	// reset iTagIndex, was used temporarily as offset variable
       
  1043 	iTagIndex = 0;
       
  1044 
       
  1045 	return KErrNone;
       
  1046 }
       
  1047 
       
  1048 void CWbxmlConverter::ReadTokenFileL(RFileReadStream& aStream, HBufC8& aBuffer)
       
  1049 	{
       
  1050 	// Read data from aFile into aBuffer. Skip linebreak(s), not into aBuffer
       
  1051 	TBuf8<1> data;
       
  1052 	TInt startOffset = iTagIndex;
       
  1053 	TPtr8 ptr = aBuffer.Des();
       
  1054 	
       
  1055 	// Note: Reusing class instance variable iTagIndex as file offset
       
  1056 	aStream.Source()->SeekL(MStreamBuf::ERead,EStreamBeginning,iTagIndex);
       
  1057 	FOREVER
       
  1058 		{
       
  1059 		aStream.ReadL(data,1);
       
  1060 		if (data[0] == '\r' || data[0] == '\n')
       
  1061 			{
       
  1062 			aStream.Source()->SeekL(MStreamBuf::ERead,EStreamBeginning,startOffset);
       
  1063 			aStream.ReadL(ptr,iTagIndex-startOffset);
       
  1064 			break;
       
  1065 			}
       
  1066 		iTagIndex++;
       
  1067 		}
       
  1068 	
       
  1069 // Consume linebreaks, which btw might be missing at last row
       
  1070 	FOREVER
       
  1071 		{
       
  1072 		aStream.ReadL(data,1);
       
  1073 		if (data[0] != '\r' && data[0] != '\n')
       
  1074 			break;
       
  1075 		iTagIndex++;
       
  1076 		}
       
  1077 	}
       
  1078 
       
  1079 // Note: check wbxml specification for multibyte definition
       
  1080 TInt CWbxmlConverter::ExtractMultiByte(TUint32* aMultiByte, TInt aSkipHeader)
       
  1081 {
       
  1082 	if (iByteList->Inc(aSkipHeader) != KErrNone)
       
  1083 		return KErrNotFound;
       
  1084 
       
  1085 	TUint8 byte = 0;
       
  1086 	*aMultiByte = 0;
       
  1087 	do
       
  1088 	{
       
  1089 		*aMultiByte <<= 7;
       
  1090 		if (iByteList->Byte(&byte,TRUE) != KErrNone)
       
  1091 			return KErrNotFound;
       
  1092 
       
  1093 		*aMultiByte |= byte & ~0x80;
       
  1094 	} while (byte & 0x80);
       
  1095 
       
  1096 	return KErrNone;
       
  1097 }
       
  1098 
       
  1099 void CWbxmlConverter::FinishStringL()
       
  1100 {
       
  1101 	switch (iVariable)
       
  1102 	{
       
  1103 	case 0x00: // was not a variable
       
  1104 		break;
       
  1105 	case 0x40: // variable substitution - escaped
       
  1106 	case 0x80: // variable reference to string table - escaped
       
  1107 		BufferAndOutputL(KWbVariableEscaped);
       
  1108 		break;
       
  1109 	case 0x41: // variable substitution - unescaped
       
  1110 	case 0x81: // variable reference to string table - unescaped
       
  1111 		BufferAndOutputL(KWbVariableUnescaped);
       
  1112 		break;
       
  1113 	case 0x42: // variable substitution - no transformation
       
  1114 	case 0x82: // variable reference to string table - no transformation
       
  1115 		// FLOWTHROUGH
       
  1116 	default:
       
  1117 		BufferAndOutputL(KWbVariableNormal);
       
  1118 		break;
       
  1119 	}
       
  1120 	iVariable = 0;
       
  1121 }
       
  1122 
       
  1123 HBufC16* CWbxmlConverter::FormatDateStringL(TDesC8& aData)
       
  1124 // Return value NULL indicates failed conversion!
       
  1125 // Ownership of the resulting string is passed up to caller.
       
  1126 {
       
  1127 	const TInt KDateTimePart = 7;
       
  1128 	enum TDateTimeParts {EYearTop, EYearBot, EMon, EDay, EHour, EMin, ESec};
       
  1129 	TInt dateData[KDateTimePart];
       
  1130 
       
  1131 	for (TInt i = 0; i < KDateTimePart; i++)
       
  1132 		dateData[i] = 0;
       
  1133 	
       
  1134 	TInt offSet = 0;
       
  1135 	TInt dataLen = aData.Length();
       
  1136 
       
  1137 	while (offSet < KDateTimePart && dataLen > 0)
       
  1138 		{
       
  1139 		dateData[offSet] = aData[offSet];
       
  1140 		offSet++;
       
  1141 		dataLen--;
       
  1142 		}
       
  1143 
       
  1144 	_LIT(KDateFormat,"%2x%02x-%02x-%02xT%02x:%02x:%02xZ");
       
  1145 	const TInt KDateFormatLen = 20;
       
  1146 
       
  1147 	TBuf16<KDateFormatLen> dateBuf;
       
  1148 	dateBuf.Format(KDateFormat, dateData[EYearTop], 
       
  1149 								dateData[EYearBot], 
       
  1150 								dateData[EMon], 
       
  1151 								dateData[EDay], 
       
  1152 								dateData[EHour], 
       
  1153 								dateData[EMin], 
       
  1154 								dateData[ESec]);
       
  1155 	return( dateBuf.AllocL() );	
       
  1156 }
       
  1157 
       
  1158 HBufC16* CWbxmlConverter::CharsetConvertDataL(TDesC8& aData)
       
  1159 // Return value NULL indicates failed conversion!
       
  1160 // Ownership of the resulting string is passed up to caller.
       
  1161 {
       
  1162 	if( iCharsetConverter->PrepareToConvertToOrFromL(iWbxmlCharset,iFs) == CCnvCharacterSetConverter::ENotAvailable )
       
  1163 		return( NULL );
       
  1164 
       
  1165 	HBufC* convertedString = HBufC::NewLC(aData.Length());
       
  1166 	TInt state = CCnvCharacterSetConverter::KStateDefault;
       
  1167 	TPtr16 convertedStringDes = convertedString->Des();
       
  1168 	TInt convertResult = iCharsetConverter->ConvertToUnicode(convertedStringDes, aData, state);
       
  1169 	CleanupStack::Pop(); // convertedString
       
  1170 
       
  1171 	if (convertResult)
       
  1172 	{
       
  1173 		delete convertedString;
       
  1174 		convertedString = NULL;
       
  1175 	}
       
  1176 
       
  1177 	return( convertedString );	
       
  1178 }
       
  1179 
       
  1180 
       
  1181 HBufC* CWbxmlConverter::ReplaceCharacterEntitiesL(HBufC* aString)
       
  1182 	{
       
  1183 	_LIT(KDollarRef, "$$");
       
  1184 	_LIT(KAmpersandRef, "&amp;");
       
  1185 	_LIT(KLesserRef, "&lt;");
       
  1186 	_LIT(KGreaterRef, "&gt;");
       
  1187 	_LIT(KQuoteRef, "&quot;");
       
  1188 	_LIT(KAposRef, "&apos;");
       
  1189 	_LIT(KNonBreakingSpaceRef, "&nbsp;");
       
  1190 	_LIT(KShyRef, "&shy;");
       
  1191 	
       
  1192 	// Calculate the need for extra characters to be allocated.
       
  1193 	// The additions to lengthExtension are subtracted by one, since the original
       
  1194 	// chacracter will be overwritten.
       
  1195 	TInt i=0;
       
  1196 	TInt lengthExtension = 0;	// The amount of extra characters needed
       
  1197 	const TText* stringPtr=aString->Ptr();
       
  1198 	const TDesC* ext=NULL;
       
  1199 	for( i=0; i < aString->Length(); i++)
       
  1200 		{
       
  1201 		switch( *stringPtr++ )
       
  1202 			{
       
  1203 			case '$':
       
  1204 				ext = &KDollarRef;
       
  1205 				break;
       
  1206 			case '&':
       
  1207 				ext = &KAmpersandRef;
       
  1208 				break;
       
  1209 			case '<':
       
  1210 				ext = &KLesserRef;
       
  1211 				break;
       
  1212 			case '>':
       
  1213 				ext = &KGreaterRef;
       
  1214 				break;
       
  1215 			case '"':
       
  1216 				ext = &KQuoteRef;
       
  1217 				break;
       
  1218 			case 39:
       
  1219 				ext = &KAposRef;
       
  1220 				break;
       
  1221 			case 160:
       
  1222 				ext = &KNonBreakingSpaceRef;
       
  1223 				break;
       
  1224 			case 173:
       
  1225 				ext = &KShyRef;
       
  1226 				break;
       
  1227 			default:
       
  1228 				// Normal character cause no added length
       
  1229 				break;
       
  1230 			}
       
  1231 		if(ext)
       
  1232 			{
       
  1233 			lengthExtension+=ext->Length()-1;
       
  1234 			ext=NULL;
       
  1235 			}
       
  1236 		}
       
  1237 	
       
  1238 	if( lengthExtension == 0 )
       
  1239 		return aString;
       
  1240 	
       
  1241 	if( aString->Des().MaxLength() < aString->Length()+lengthExtension )
       
  1242 		aString = aString->ReAllocL(aString->Length()+lengthExtension);
       
  1243 	
       
  1244 	// Do the replacement thing...
       
  1245 
       
  1246 	stringPtr=aString->Ptr();
       
  1247 	ext=NULL;
       
  1248 
       
  1249 	for( i=0; i < aString->Length(); i++, stringPtr++)
       
  1250 		{
       
  1251 		switch( *stringPtr )
       
  1252 			{
       
  1253 			case '$':
       
  1254 				ext=&KDollarRef;
       
  1255 				break;
       
  1256 			case '&':
       
  1257 				ext=&KAmpersandRef;
       
  1258 				break;
       
  1259 			case '<':
       
  1260 				ext=&KLesserRef;
       
  1261 				break;
       
  1262 			case '>':
       
  1263 				ext=&KGreaterRef;
       
  1264 				break;
       
  1265 			case '"':
       
  1266 				ext=&KQuoteRef;
       
  1267 				break;
       
  1268 			case 39:
       
  1269 				ext=&KAposRef;
       
  1270 				break;
       
  1271 			case 160:
       
  1272 				ext=&KNonBreakingSpaceRef;
       
  1273 				break;
       
  1274 			case 173:
       
  1275 				ext=&KShyRef;
       
  1276 				break;
       
  1277 			default:
       
  1278 				ext=NULL;
       
  1279 				break;
       
  1280 			}
       
  1281 		
       
  1282 		if( ext != NULL )
       
  1283 			{
       
  1284 			aString->Des().Delete(i,1);
       
  1285 			aString->Des().Insert(i,*ext);
       
  1286 			i += ext->Length()-1;  // one will be added to the counter at the end of the loop
       
  1287 			stringPtr += ext->Length()-1;  // one will be added to the counter at the end of the loop
       
  1288 			}
       
  1289 		}
       
  1290 	
       
  1291 	return( aString );
       
  1292 	}
       
  1293 
       
  1294 // Entity output
       
  1295 void CWbxmlConverter::OutputL(TUint32 aSource) const
       
  1296 {
       
  1297 	TBuf8<4> buf;
       
  1298 	const TDesC8* data=NULL;
       
  1299 	// This is the dodgy bit : we need to buffer these correctly
       
  1300 	// We are WML specific, so we DO know about these special cases
       
  1301 	switch(aSource)
       
  1302 	{
       
  1303 	case '$':
       
  1304 		{
       
  1305 		// Can this be added here, too??? JOM 231199
       
  1306 		data = &KEntityDollar;
       
  1307 		}
       
  1308 		break;
       
  1309 	case '&': // ampersand &#38;&#38;
       
  1310 		{
       
  1311 		data = &KEntityAmp;
       
  1312 		}
       
  1313 		break;
       
  1314 	case '<': // less than &#38;&#60;
       
  1315 		{
       
  1316 		data = &KEntityLt;
       
  1317 		}
       
  1318 		break;
       
  1319 	case '>': // greater than &#62;
       
  1320 		{
       
  1321 		data = &KEntityGt;
       
  1322 		}
       
  1323 		break;
       
  1324 	case '"': // quotation mark &#34;
       
  1325 		{
       
  1326 		data = &KEntityQuot;
       
  1327 		}
       
  1328 		break;
       
  1329 	case 39: // apostrophe &#39;
       
  1330 		{
       
  1331 		data = &KEntityApos;
       
  1332 		}
       
  1333 		break;
       
  1334 	case 160: // non-breaking space &#160;
       
  1335 		{
       
  1336 		data = &KEntityNbsp;
       
  1337 		}
       
  1338 		break;
       
  1339 	case 173: // soft hyphen &#173;
       
  1340 		{
       
  1341 		data = &KEntityShy;
       
  1342 		}
       
  1343 		break;
       
  1344 	default:
       
  1345 		{
       
  1346 		buf.Append(aSource);
       
  1347 		data = &buf;
       
  1348 		}
       
  1349 	}
       
  1350 	if(data)
       
  1351 		BufferAndOutputL(*data);
       
  1352 }
       
  1353 
       
  1354 TBool CWbxmlConverter::OutputCheckQuoteL(HBufC8& aSource) const
       
  1355 {
       
  1356 	TBool openQuote = EFalse;
       
  1357 
       
  1358 	// Scan for quote symbol
       
  1359 	TInt len = aSource.Length();
       
  1360 	const TText8* stringPtr=aSource.Ptr();
       
  1361 	for (TInt i = 0; i < len; i++)
       
  1362 	{
       
  1363 		if (*stringPtr++ == '"')
       
  1364 			openQuote = !openQuote;
       
  1365 	}
       
  1366 	BufferAndOutputL(aSource);
       
  1367 
       
  1368 	return openQuote;
       
  1369 }
       
  1370 
       
  1371 void CWbxmlConverter::BufferAndOutputL(const TDesC8& aSource) const
       
  1372 	{
       
  1373 	// Append to buffer here and output when full
       
  1374 	if(aSource.Length() + iOutputBuffer->Length() > KOutputBufferLength)
       
  1375 		{
       
  1376 		// Buffer is full : Keep ownership but reset buffer length to zero
       
  1377 		// No point passing ownership as the observer copies the buffer
       
  1378 		// and then deletes it. Passing it by reference means the observer
       
  1379 		// copies it and we can reuse it
       
  1380 		TInt returnValue = iObserver->HandleWbxmlOutputL(*iOutputBuffer);
       
  1381 		if( returnValue != KErrNone )
       
  1382 			User::Leave(returnValue);
       
  1383 		TPtr8 ptr(iOutputBuffer->Des());
       
  1384 		ptr.SetLength(0);
       
  1385 		}
       
  1386 	// Check input source is smaller than buffer
       
  1387 	if(aSource.Length() >= KOutputBufferLength)
       
  1388 		{
       
  1389 		// We have to allocate a new buffer here and give ownership to the observer
       
  1390 		HBufC8* tmp = aSource.AllocLC();
       
  1391 		TInt returnValue = iObserver->HandleWbxmlOutputL(tmp);
       
  1392 		if( returnValue != KErrNone )
       
  1393 			User::Leave(returnValue);
       
  1394 		CleanupStack::Pop();
       
  1395 		return;
       
  1396 		}
       
  1397 	// Buffer the current output
       
  1398 	TPtr8 ptr = iOutputBuffer->Des();
       
  1399 	ptr.Append(aSource);
       
  1400 	}
       
  1401 
       
  1402 HBufC* CWbxmlConverter::FindTokenFileL(const TDesC& aTokenFilePath) const
       
  1403 //
       
  1404 // Search drives for file specified by aTokenFilePath, and return the full path.
       
  1405 	{
       
  1406 	TFindFile finder = iFs;
       
  1407 	User::LeaveIfError(finder.FindByDir(aTokenFilePath, KNullDesC()));
       
  1408 
       
  1409 	HBufC* fullPath = NULL;
       
  1410 	fullPath = finder.File().AllocL();
       
  1411 
       
  1412 	return fullPath;
       
  1413 	}
       
  1414 
       
  1415 
       
  1416 //
       
  1417 // End of file
       
  1418 //