sl@0: /* sl@0: * Copyright (c) 1999-2009 Nokia Corporation and/or its subsidiary(-ies). sl@0: * All rights reserved. sl@0: * This component and the accompanying materials are made available sl@0: * under the terms of "Eclipse Public License v1.0" sl@0: * which accompanies this distribution, and is available sl@0: * at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: * sl@0: * Initial Contributors: sl@0: * Nokia Corporation - initial contribution. sl@0: * sl@0: * Contributors: sl@0: * sl@0: * Description: sl@0: * sl@0: */ sl@0: sl@0: sl@0: #include "TXTSTD.H" sl@0: #include "ParseLst.h" sl@0: #include "OstTraceDefinitions.h" sl@0: #ifdef OST_TRACE_COMPILER_IN_USE sl@0: #include "ParseLstTraces.h" sl@0: #endif sl@0: sl@0: sl@0: sl@0: //++ sort out definitive hash includes sl@0: sl@0: sl@0: CParserList::CParserItem::CParserItem(MParser* aParser, const TUint aTagIndex) sl@0: : iParser(aParser), sl@0: iTagIndex(aTagIndex) sl@0: { sl@0: } sl@0: sl@0: sl@0: // Panic the process with UikParse as the category. sl@0: void CParserList::Panic(TParserListPanic aPanic) const sl@0: { sl@0: OstTraceExt2( TRACE_FATAL, DUP1_CPARSERLIST_PANIC, "CParserList::Panic;this=%x;aPanic=%x", (unsigned int)this, ( TUint )&( aPanic ) ); sl@0: _LIT(panicStr, "ParseLst"); sl@0: User::Panic(panicStr, aPanic); sl@0: } sl@0: sl@0: sl@0: CParserList::CParserList() sl@0: : iParserList(4) sl@0: { sl@0: iHighestIndex = 0; sl@0: iNumberInList = 0; sl@0: } sl@0: sl@0: sl@0: CParserList::~CParserList() sl@0: { sl@0: iParserList.ResetAndDestroy(); // Reset the list and destroy the CParserItems sl@0: iParserList.Close(); // but leave the parsers and free the resources sl@0: } sl@0: sl@0: sl@0: // Add parser to appropriate list sl@0: void CParserList::ActivateAParserL(MParser* aParser, const TBool aDefaultParser) sl@0: { sl@0: // Check the index isn't rolling over sl@0: // N.B. This is somewhat unlikely. Since index is effectively a 29-bit sl@0: // uint (I'm using the top 3 bits as flags) this allows 268435456 parsers sl@0: // to be installed. (Assuming we deinstall almost as many, as we went sl@0: // along, to avoid OOM.) At 50 per sec that's 20 years continuous action! sl@0: if (iHighestIndex >= EMaxParserIndex) sl@0: { sl@0: OstTrace0( TRACE_DUMP, CPARSERLIST_ACTIVATEAPARSERL, "EParserIndexRollover" ); sl@0: } sl@0: __ASSERT_DEBUG((iHighestIndex < EMaxParserIndex), Panic(EParserIndexRollover)); sl@0: if (!aParser) sl@0: { sl@0: OstTrace0( TRACE_DUMP, DUP1_CPARSERLIST_ACTIVATEAPARSERL, "EParserNullPtr" ); sl@0: } sl@0: __ASSERT_DEBUG(aParser, Panic(EParserNullPtr)); sl@0: TUint parserIndex = iHighestIndex + 1; sl@0: // Adjust flags to describe parser sl@0: if (aParser->ReformatOnRecognise()) sl@0: parserIndex |= static_cast( EReformatOnRecogniseFlag ); sl@0: if (aParser->ReformatOnRollover()) sl@0: parserIndex |= EReformatOnRolloverFlag; sl@0: if (aDefaultParser) sl@0: parserIndex |= EDefaultParserFlag; sl@0: // Create a parser item sl@0: TInt result; sl@0: CParserItem* parserItem = new (ELeave) CParserItem(aParser, parserIndex); sl@0: ++iHighestIndex; sl@0: if (aDefaultParser) sl@0: { sl@0: CleanupStack::PushL(parserItem); sl@0: result = iParserList.Append(parserItem); sl@0: if (result) // We couldn't get it in the main list sl@0: User::Leave(result); sl@0: CleanupStack::Pop(); sl@0: } sl@0: else sl@0: { sl@0: // Look for the end of the specific parsers and the start of the default set sl@0: TInt count; sl@0: for (count = 0; count < iNumberInList; count++) sl@0: { sl@0: if (DefaultParser(iParserList[count]->TagIndex())) sl@0: break; sl@0: } sl@0: CleanupStack::PushL(parserItem); sl@0: result = iParserList.Insert(parserItem, count); sl@0: if (result) // We couldn't get it in the main list sl@0: User::Leave(result); sl@0: CleanupStack::Pop(); sl@0: } sl@0: iNumberInList++; sl@0: } sl@0: sl@0: sl@0: // Activate an individual parser sl@0: void CParserList::ActivateParserL(MParser* aParser) sl@0: { sl@0: ActivateAParserL(aParser, EFalse); sl@0: } sl@0: sl@0: sl@0: // N.B. We can't just delete CParserList and zero TLS when we get back sl@0: // to a list with no specific or default parsers because there could be sl@0: // an EText left with a local ptr to it. sl@0: void CParserList::DeactivateParser(MParser* aParser) sl@0: { sl@0: if (!iNumberInList) sl@0: { sl@0: OstTrace0( TRACE_DUMP, CPARSERLIST_DEACTIVATEPARSER, "EParserNoneActive" ); sl@0: } sl@0: __ASSERT_DEBUG(iNumberInList, Panic(EParserNoneActive)); sl@0: if (!aParser) sl@0: { sl@0: OstTrace0( TRACE_DUMP, DUP1_CPARSERLIST_DEACTIVATEPARSER, "EParserNullPtr" ); sl@0: } sl@0: __ASSERT_DEBUG(aParser, Panic(EParserNullPtr)); sl@0: // Run thru list till find entry we need sl@0: TInt count; sl@0: for (count = 0; count < iNumberInList; count++) sl@0: { sl@0: if (iParserList[count]->Parser() == aParser) sl@0: { sl@0: delete iParserList[count]; sl@0: iParserList.Remove(count); sl@0: break; sl@0: } sl@0: } sl@0: if (count >= iNumberInList) sl@0: { sl@0: OstTrace0( TRACE_DUMP, DUP2_CPARSERLIST_DEACTIVATEPARSER, "EParserInstanceNotActive" ); sl@0: } sl@0: __ASSERT_DEBUG((count < iNumberInList), Panic(EParserInstanceNotActive)); sl@0: iNumberInList--; sl@0: } sl@0: sl@0: sl@0: // Activate a parser as one of the default set sl@0: void CParserList::ActivateDefaultParserL(MParser* aParser) sl@0: { sl@0: ActivateAParserL(aParser, ETrue); sl@0: } sl@0: sl@0: sl@0: //++ Put comment here sl@0: void CParserList::DeactivateParserDefaults() sl@0: { sl@0: if (iNumberInList) sl@0: { sl@0: // Take them out of the list sl@0: while (iNumberInList && DefaultParser(iParserList[iNumberInList - 1]->TagIndex())) sl@0: { sl@0: // Tell the parser to free itself sl@0: iParserList[iNumberInList - 1]->Parser()->Release(); sl@0: // Delete the item that refers to it sl@0: delete iParserList[iNumberInList - 1]; sl@0: // Remove the entry from the list sl@0: iParserList.Remove(iNumberInList - 1); sl@0: iNumberInList--; sl@0: } sl@0: } sl@0: } sl@0: sl@0: sl@0: // Called by EText to scan an area of text sl@0: TBool CParserList::ParseThisText(CRichText& aTextObj,TInt aStartScan,TInt aScanLength,TInt& aStartOfTags,TInt& aLength) sl@0: { sl@0: TBool foundSomething = EFalse; sl@0: TCharFormatX format; sl@0: TCharFormatXMask varies; sl@0: TPtrC ptr; sl@0: TInt endRange; sl@0: sl@0: // Scan either side of the range in case part of some tagged text was deleted. sl@0: if (aStartScan > 0) sl@0: { sl@0: aStartScan--; sl@0: aScanLength++; sl@0: } sl@0: if (aStartScan + aScanLength < aTextObj.DocumentLength()) sl@0: aScanLength++; sl@0: sl@0: if (iNumberInList && aScanLength) sl@0: { sl@0: aStartOfTags = aStartScan + aScanLength; sl@0: aLength = 0; sl@0: for (TInt count = 0; count < iNumberInList; count++) sl@0: { sl@0: // For each parser in the list sl@0: TUint tagIndex = iParserList[count]->TagIndex(); sl@0: TInt pos; sl@0: MParser* parser = iParserList[count]->Parser(); sl@0: TInt localStartScan = aStartScan; sl@0: TInt localScanLength = aScanLength; sl@0: // Start by removing existing tags for this parser. This ensures sl@0: // that old tags that have been invalidated by subsequent editing sl@0: // are removed. Any that are still valid will be replaced. sl@0: aTextObj.GetExtendedCharFormat(format, varies, localStartScan, aScanLength); sl@0: sl@0: if (format.iParserTag || varies.AttribIsSet(EAttParserTag)) sl@0: { sl@0: // At least some of the object contains a non-zero tag - go through it sl@0: // Are we starting part way through a tag? sl@0: aTextObj.GetExtendedCharFormat(format, varies, localStartScan, 1); sl@0: if (format.iParserTag == tagIndex) sl@0: { sl@0: // The first char of this range has the current parsers tag sl@0: // so we need to check backwards for the start of that tag sl@0: for (pos = localStartScan; pos > 0; pos--) sl@0: { sl@0: aTextObj.GetExtendedCharFormat(format, varies, pos - 1, 1); sl@0: if (format.iParserTag != tagIndex) sl@0: break; sl@0: } sl@0: // Since we are going to remove a tag starting from here sl@0: // we need to allow this area to be rescanned sl@0: localScanLength += localStartScan - pos; sl@0: localStartScan = pos; sl@0: } sl@0: // What about off the end? sl@0: aTextObj.GetExtendedCharFormat(format, varies, localStartScan + localScanLength - 1, 1); sl@0: if (format.iParserTag == tagIndex) sl@0: { sl@0: // The last char of this range has the current parsers tag sl@0: // so we need to check forwards for the end of that tag sl@0: pos = localStartScan + localScanLength; sl@0: TInt end = aTextObj.DocumentLength(); sl@0: while (pos < end) sl@0: { sl@0: aTextObj.GetTextAndExtendedFormat(ptr, format, pos); sl@0: if (format.iParserTag != tagIndex) sl@0: break; sl@0: pos += ptr.Length(); sl@0: } sl@0: // Adjust scan length sl@0: localScanLength = pos - localStartScan; sl@0: } sl@0: pos = localStartScan; sl@0: while (pos < localStartScan + localScanLength) sl@0: { sl@0: // Run along the scan range sl@0: aTextObj.GetTextAndExtendedFormat(ptr, format, pos); sl@0: if (format.iParserTag == tagIndex) sl@0: { sl@0: // Remove this tag sl@0: format.iParserTag = 0; sl@0: varies.ClearAll(); sl@0: varies.SetAttrib(EAttParserTag); sl@0: TRAPD(leaveCode, aTextObj.ApplyExtendedCharFormatL(format, varies, pos, ptr.Length())); sl@0: if (leaveCode==KErrNone) sl@0: foundSomething = ETrue; // We are removing a tag sl@0: if (aLength) sl@0: { sl@0: if (pos < aStartOfTags) sl@0: { sl@0: aLength += aStartOfTags - pos; sl@0: aStartOfTags = pos; sl@0: } sl@0: if (pos + ptr.Length() > aStartOfTags + aLength) sl@0: aLength = pos + ptr.Length() - aStartOfTags; sl@0: } sl@0: else sl@0: { sl@0: aStartOfTags = pos; sl@0: aLength = ptr.Length(); sl@0: } sl@0: } sl@0: pos += ptr.Length(); sl@0: } sl@0: } sl@0: endRange = localStartScan + localScanLength; sl@0: sl@0: // For this parser, run through text looking for changes sl@0: TBool allowBack = ETrue; sl@0: for (;;) // Run forever sl@0: { sl@0: TInt localStartTag = aTextObj.DocumentLength(); sl@0: TInt localTagLength = 0; sl@0: TInt result = parser->ParseThisText(aTextObj, allowBack, localStartScan, localScanLength, localStartTag, localTagLength); sl@0: if (!result) sl@0: break; sl@0: if (!allowBack && (localStartTag < localStartScan)) sl@0: { sl@0: OstTrace0( TRACE_DUMP, CPARSERLIST_PARSETHISTEXT, "EParserIgnoringAllowFlag" ); sl@0: } sl@0: __ASSERT_DEBUG(allowBack || (localStartTag >= localStartScan), Panic(EParserIgnoringAllowFlag)); sl@0: TInt startNewTag = localStartTag; sl@0: TInt lengthNewTag = localTagLength; sl@0: aTextObj.GetExtendedCharFormat(format, varies, localStartTag, localTagLength); sl@0: if (format.iParserTag || varies.AttribIsSet(EAttParserTag)) sl@0: { sl@0: // At least some of this area contains a non-zero tag - go through it sl@0: pos = localStartTag; sl@0: TBool higher = EFalse; sl@0: while (pos < localStartTag + localTagLength) sl@0: { sl@0: aTextObj.GetTextAndExtendedFormat(ptr, format, pos); sl@0: if (format.iParserTag && (MaskedTag(format.iParserTag) < MaskedTag(tagIndex))) sl@0: { sl@0: // A higher precedence tag is already here so we can't sl@0: // insert our tag - let's see how far it goes sl@0: TUint tag = format.iParserTag; // Stash tag before overwriting it sl@0: TInt len = aTextObj.DocumentLength(); sl@0: while (pos < len) sl@0: { sl@0: aTextObj.GetTextAndExtendedFormat(ptr, format, pos); sl@0: if (format.iParserTag != tag) sl@0: break; sl@0: pos += ptr.Length(); sl@0: } sl@0: result = EFalse; sl@0: startNewTag = pos; sl@0: lengthNewTag = 0; sl@0: break; sl@0: } sl@0: // If there aren't any higher precedence tags in here then this sl@0: // will save us having to go through again if there aren't any sl@0: // lower precedence tags either sl@0: if (MaskedTag(format.iParserTag) >= MaskedTag(tagIndex)) sl@0: higher = ETrue; sl@0: pos += ptr.Length(); sl@0: } sl@0: if (higher) sl@0: { sl@0: // There are lower or equal precedence tags in this range sl@0: // Do they extend back off the start? sl@0: aTextObj.GetExtendedCharFormat(format, varies, localStartTag, 1); sl@0: if (format.iParserTag) sl@0: { sl@0: // need to check backwards sl@0: TUint tag = format.iParserTag; // Stash tag before overwriting it sl@0: for (pos = localStartTag; pos > 0; pos--) sl@0: { sl@0: aTextObj.GetExtendedCharFormat(format, varies, pos - 1, 1); sl@0: if (format.iParserTag != tag) sl@0: break; sl@0: } sl@0: localTagLength += localStartTag - pos; sl@0: localStartTag = pos; sl@0: } sl@0: // What about off the end? sl@0: pos = localStartTag + localTagLength; sl@0: aTextObj.GetExtendedCharFormat(format, varies, pos - 1, 1); sl@0: if (format.iParserTag) sl@0: { sl@0: // need to check forwards sl@0: TUint tag = format.iParserTag; // Stash tag before overwriting it sl@0: TInt len = aTextObj.DocumentLength(); sl@0: while (pos < len) sl@0: { sl@0: aTextObj.GetTextAndExtendedFormat(ptr, format, pos); sl@0: if (format.iParserTag != tag) sl@0: break; sl@0: pos += ptr.Length(); sl@0: } sl@0: localTagLength = pos - localStartTag; sl@0: } sl@0: sl@0: // Remove all tags in this area - they all have lower precedence sl@0: format.iParserTag = 0; sl@0: varies.ClearAll(); sl@0: varies.SetAttrib(EAttCharLanguage); sl@0: TRAPD(leaveCode, aTextObj.ApplyExtendedCharFormatL(format, varies, localStartTag, localTagLength)); sl@0: if (leaveCode==KErrNone) sl@0: foundSomething = ETrue; // We are removing a tag sl@0: } sl@0: } sl@0: sl@0: if (result) sl@0: { sl@0: // Format tag this area with tagIndex sl@0: format.iParserTag = tagIndex; sl@0: varies.ClearAll(); sl@0: varies.SetAttrib(EAttParserTag); sl@0: // Use the original length, not the possibly expanded version sl@0: TRAPD(leaveCode, aTextObj.ApplyExtendedCharFormatL(format, varies, startNewTag, lengthNewTag)); sl@0: if (leaveCode==KErrNone) sl@0: foundSomething = ETrue; // We are applying a tag sl@0: if (aLength) sl@0: { sl@0: if (localStartTag < aStartOfTags) sl@0: { sl@0: aLength += aStartOfTags - localStartTag; sl@0: aStartOfTags = localStartTag; sl@0: } sl@0: if (localStartTag + localTagLength > aStartOfTags + aLength) sl@0: aLength = localStartTag + localTagLength - aStartOfTags; sl@0: } sl@0: else sl@0: { sl@0: aStartOfTags = localStartTag; sl@0: aLength = localTagLength; sl@0: } sl@0: } sl@0: // Jump over sl@0: localScanLength -= startNewTag + lengthNewTag - localStartScan; sl@0: localStartScan = startNewTag + lengthNewTag; // Adjust start of next scan run sl@0: if (localStartScan >= endRange) // Have we reached the end of the range yet? sl@0: break; sl@0: allowBack = EFalse; sl@0: } sl@0: } sl@0: } sl@0: sl@0: return foundSomething; sl@0: } sl@0: sl@0: sl@0: // given a tag, fetch a ptr to the parser - or null sl@0: MParser* CParserList::ParserWithThisTag(const TUint aTagIndex) const sl@0: { sl@0: MParser* parser = NULL; sl@0: for (TInt count = 0; count < iNumberInList; count++) sl@0: { sl@0: if (aTagIndex == iParserList[count]->TagIndex()) sl@0: { sl@0: parser = iParserList[count]->Parser(); sl@0: break; sl@0: } sl@0: } sl@0: return parser; sl@0: } sl@0: sl@0: // given a ptr to a parser, fetch a tag - or zero sl@0: TUint CParserList::TagForThisParser(const MParser *const aParser) const sl@0: { sl@0: TUint tagIndex = 0; sl@0: for (TInt count = 0; count < iNumberInList; count++) sl@0: { sl@0: if (aParser == iParserList[count]->Parser()) sl@0: { sl@0: tagIndex = iParserList[count]->TagIndex(); sl@0: break; sl@0: } sl@0: } sl@0: if (!tagIndex) sl@0: { sl@0: OstTrace0( TRACE_DUMP, CPARSERLIST_TAGFORTHISPARSER, "EParserNoSuchTag" ); sl@0: } sl@0: __ASSERT_DEBUG(tagIndex, Panic(EParserNoSuchTag)); sl@0: return tagIndex; sl@0: } sl@0: sl@0: sl@0: CParserData::CParserData(TInt aEndParse): sl@0: iStartParse(0), sl@0: iEndParse(aEndParse) sl@0: { sl@0: // Get parser data sl@0: iActiveParserList = (CParserList*)Dll::Tls(); sl@0: iLastKnownCursor = -1; sl@0: if (iActiveParserList) sl@0: iActiveParserList->iRefCount++; sl@0: } sl@0: sl@0: sl@0: CParserData::~CParserData() sl@0: { sl@0: if (iActiveParserList) sl@0: { sl@0: iActiveParserList->iRefCount--; sl@0: if ((iActiveParserList->iRefCount == 0) && (iActiveParserList->iNumberInList == 0)) sl@0: { sl@0: Dll::FreeTls(); sl@0: delete iActiveParserList; sl@0: } sl@0: } sl@0: } sl@0: sl@0: sl@0: // Merge the specified range, which may have changed length, into the current range. sl@0: // aOldLength is the # of chars deleted and to be removed from the range sl@0: // aNewLength is the # of chars inserted and to be added to the range sl@0: void CParserData::MergeRange(TInt aStart,TInt aOldLength,TInt aNewLength) sl@0: { sl@0: if (iStartParse == -1) // no current range sl@0: { sl@0: iStartParse = aStart; sl@0: iEndParse = aStart + aNewLength; sl@0: } sl@0: else sl@0: { sl@0: if (aStart < iStartParse) sl@0: iStartParse = aStart; sl@0: if (aStart + aOldLength > iEndParse) sl@0: iEndParse = aStart + aOldLength; sl@0: iEndParse += aNewLength - aOldLength; sl@0: } sl@0: }