--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/genericservices/s60compatibilityheaders/commonengine/src/textresolver.cpp Tue Feb 02 02:01:42 2010 +0200
@@ -0,0 +1,640 @@
+// Copyright (c) 2002-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+//
+
+
+
+#include <barsread.h> // TResourceReader
+#include <bautils.h> // BaflUtils
+#include "textresolver.h"
+#include <errorres.rsg>
+#include <uikon/eikdefconst.h>
+
+
+const TInt KUnknownError( 0 );
+const TInt KBlankError( -2 );
+
+const TInt KRIMask(0x00000fff);
+_LIT(KErrorResResourceFileName, "z:\\resource\\errors\\ERRORRES.RSC");
+_LIT(KRDSupport, "c:\\resource\\ErrRD");
+_LIT(KTextResolverPanic, "TextResolver");
+
+
+GLDEF_C void Panic(TInt aPanic)
+ {
+ User::Panic(KTextResolverPanic, aPanic);
+ }
+
+
+CTextResolver::CTextResolver()
+ {
+ }
+
+CTextResolver::CTextResolver(CCoeEnv& aEnv)
+ :iCoe(&aEnv)
+ {
+ }
+/**
+ * Two-phase constructor method that is used to create a new instance
+ * of the CTextResolver class. The implementation uses the passed
+ * CCoeEnv instance to access the resource files.
+ *
+ * @param aEnv the CCoeEnv instance to be used to access the resource
+ * files.
+ * @return a pointer to a new instance of the CTextResolver class.
+ */
+EXPORT_C CTextResolver* CTextResolver::NewL(CCoeEnv& aEnv)
+ {
+ CTextResolver* self = CTextResolver::NewLC(aEnv);
+ CleanupStack::Pop(self);
+ return self;
+ }
+
+ /**
+ * Constructor creates a new instance of CTextResolver. The
+ * implementation uses the passed CCoeEnv instance to access the
+ * resource files. Leaves the object on the cleanup stack.
+ *
+ * @param aEnv the CCoeEnv instance to be used to access the resource
+ * files.
+ * @return a pointer to a new instance of the CTextResolver class.
+ */
+EXPORT_C CTextResolver* CTextResolver::NewLC(CCoeEnv& aEnv)
+ {
+ CTextResolver* self = new (ELeave) CTextResolver(aEnv);
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ return self;
+ }
+
+ /**
+ * Constructor creates a new instance of CTextResolver. Resource files
+ * are accessed through the RResourceFile API.
+ *
+ * @return a pointer to a new instance of the CTextResolver class.
+ */
+EXPORT_C CTextResolver* CTextResolver::NewL()
+ {
+ CTextResolver* self = CTextResolver::NewLC();
+ CleanupStack::Pop(self);
+ return self;
+ }
+
+ /**
+ * Constructor creates a new instance of CTextResolver.Resource files
+ * are accessed through the RResourceFile API. Leaves the object on
+ * the cleanup stack.
+ *
+ * @return a pointer to a new instance of the CTextResolver class.
+ */
+EXPORT_C CTextResolver* CTextResolver::NewLC()
+ {
+ CTextResolver* self = new (ELeave) CTextResolver();
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ return self;
+ }
+
+//
+// ---------------------------------------------------------
+// CTextResolver::ConstructL
+//
+// Symbian OS default constructor, initializes variables and cache
+// ---------------------------------------------------------
+//
+void CTextResolver::ConstructL()
+ {
+ // if no coe is present, connect new filesession.
+ if (!iCoe)
+ {
+ User::LeaveIfError(iFs.Connect());
+
+ TFileName resFile(KErrorResResourceFileName);
+ BaflUtils::NearestLanguageFile(iFs, resFile);
+ iResFile.OpenL(iFs, resFile);
+ }
+
+ iRDSupport = BaflUtils::FileExists(iCoe ? iCoe->FsSession() : iFs, KRDSupport);
+ }
+
+/**
+* Destructor
+*/
+EXPORT_C CTextResolver::~CTextResolver()
+ {
+ Reset();
+ iResFile.Close();
+
+ // if no coe is present, close filesession.
+ if (!iCoe)
+ iFs.Close();
+
+ delete iTitleText;
+ delete iTextBuffer;
+ delete iContextSeparator;
+ }
+
+/**
+* Resolves the given error code and returns the error text for the
+* resolved error. Resolved text can be of any length. This version
+* is for "normal" use.
+*
+* @param aError The error code to be resolved.
+* @param aContext Optional context for error numbers. If the aContext
+* parameter is not passed to the function, it uses the default value
+* ECtxAutomatic.
+* @return the error text for the resolved error. "System error" (in
+* English localisation) is returned when error code is not known. For
+* unknown errors blank error flag (flags are defined in
+* textresolver.hrh) is also set to hide errors without proper
+* explanation. There is no limit on how long the resolved string
+* can be.
+*/
+EXPORT_C const TDesC& CTextResolver::ResolveErrorString(TInt aError, TErrorContext aContext)
+ {
+ TUint flags(0);
+ TInt id(0);
+ return ResolveErrorString(aError,id,flags,aContext);
+ }
+
+/**
+* Resolves the given error code and returns the error text for the
+* resolved error. Resolved text can be of any length. This version
+* is for advanced use
+*
+* @param aError The error code to be resolved.
+* @param aTextId ID of the returned text.
+* @param aFlags The priority of the returned error. The priority is
+* defined by the this module! Flags are defined in textresolver.hrh.
+* @param aContext Optional context for error numbers. If the aContext
+* parameter is not passed to the function, it uses the default value
+* ECtxAutomatic.
+* @return the error text for the resolved error. "System error" (in
+* English localisation) is returned when error code is not known. For
+* unknown errors blank error flag (flags are defined in
+* textresolver.hrh) is also set to hide errors without proper
+* explanation. There is no limit on how long the resolved string
+* can be.
+*/
+EXPORT_C const TDesC& CTextResolver::ResolveErrorString(TInt aError, TInt& aTextId, TUint& aFlags, TErrorContext aContext)
+ {
+ aFlags = 0;
+ if (iCoe) // Use the resource loaded using the CCoeEnv to read the resource file
+ {
+ TRAPD(err, DoResolveErrorStringL(aError, aTextId, aFlags));
+ if (err)
+ {
+ if ((!AddContextAndSeparator(aContext)))
+ {
+ // Even the resource file opening failed, return OOM flag
+ aFlags |= EErrorResOOMFlag;
+ return KNullDesC;
+ }
+ return *iTextBuffer;
+ }
+
+ if(aFlags&ETextResolverUnknownErrorFlag) // Error code not supported. No error text found.
+ {
+ // Error is not recognised
+ aTextId = R_ERROR_RES_GENERAL; // Read and return an "unknown error" text from the
+ // Nokia-specific version of the errorres.rss file
+ TPtr appTextPtr = iTitleText->Des();
+ TPtr textPtr = iTextBuffer->Des();
+ iCoe->ReadResource(appTextPtr, R_BASE);
+ iCoe->ReadResource(textPtr, R_ERROR_RES_GENERAL);
+ }
+ }
+ else // No CCoeEnv available
+ {
+ aTextId = 0;
+ TRAPD(err, DoRawReadOfSystemErrorResourcesToArraysL(aError, aTextId));
+ if(err)
+ {
+ // Cleaning needed since object not destroyed
+ Reset();
+
+ if (aTextId != R_ERROR_RES_NO_MEMORY || !AddContextAndSeparator(aContext))
+ {
+ // Even the resource file opening failed, return OOM flag
+ aFlags |= EErrorResOOMFlag;
+ return KNullDesC;
+ }
+
+ return *iTextBuffer;
+ }
+
+ aTextId = ResourceForError(aError);
+ switch (aTextId)
+ {
+ case KBlankError:
+ {
+ aFlags |= ETextResolverBlankErrorFlag;
+ break;
+ }
+ case KUnknownError:
+ {
+ // Error is not recognised
+ aTextId = R_ERROR_RES_GENERAL;
+
+ delete iTitleText;
+ iTitleText = AllocReadUnicodeString(iResFile, R_BASE);
+ aFlags |= ETextResolverUnknownErrorFlag;
+ // No break here; Fall through to default case to resolve text for the general error
+ }
+ default:
+ {
+ // --- Error recognised by the resolver, so get the text ---
+ delete iTextBuffer;
+ iTextBuffer = AllocReadUnicodeString(iResFile, aTextId);
+ break;
+ }
+ };
+ }
+
+ if(aFlags&ETextResolverBlankErrorFlag) // Error code supported, but no error text found.
+ {
+ delete iTextBuffer;
+ iTextBuffer = NULL; // Return no error text at all
+ }
+
+ if (!AddContextAndSeparator(aContext))
+ {
+ aFlags |= EErrorResOOMFlag;
+ return KNullDesC;
+ }
+
+ if (iRDSupport && iTextBuffer)
+ {
+ HBufC* tempBuffer = iTextBuffer->ReAlloc(iTextBuffer->Length()+14);
+
+ // if allocation succeeds, append error id. Otherwise iTextBuffer stays as it is
+ if (tempBuffer)
+ {
+ iTextBuffer = tempBuffer;
+ iTextBuffer->Des().Append(' ');
+ iTextBuffer->Des().Append('(');
+ iTextBuffer->Des().AppendNum(aError);
+ iTextBuffer->Des().Append(')');
+ }
+ }
+ else if (aFlags & ETextResolverUnknownErrorFlag)
+ { // We hide the errors we cannot give proper explanation,
+ //i.e. "System Error" will not be shown.
+ aFlags |= ETextResolverBlankErrorFlag;
+ }
+
+ if (iTextBuffer)
+ return *iTextBuffer;
+ else
+ return KNullDesC;
+ }
+
+TInt CTextResolver::ResourceForError(TInt aError)
+ {
+ ASSERT(!iCoe);
+ const TInt errorCount = iStartError->Count();
+
+ delete iTitleText;
+ iTitleText = NULL;
+
+ for (TInt cc = 0; cc < errorCount; ++cc)
+ {
+ const TInt starterror = (*iStartError)[cc];
+ const TInt endError = starterror-(*iErrorTexts)[cc]->Count()+1;
+
+ if (aError >= endError && aError <= starterror)
+ {
+ ASSERT(!iTitleText);
+ iTitleText = AllocReadUnicodeString(iResFile, (*iAppTexts)[cc]);
+
+ const TInt errorIndex = -(aError-starterror);
+ const TInt flags = (*iFlags)[cc]->At(errorIndex);
+
+ if (flags & ETextResolverPanicErrorFlag)
+ {
+ // --- Some errors are never meant to get to the UI level ---
+ // --- Those of them that do, result in a panic ---
+ Panic(aError);
+ }
+
+ else if (flags & ETextResolverBlankErrorFlag)
+ {
+ // --- Error code can be ignored from the users' perspective ---
+ // --- Return blank error text ---
+ return KBlankError;
+ }
+
+ else if (flags & ETextResolverUnknownErrorFlag)
+ {
+ // --- Error not recognised by TextResolver ---
+ // --- Will be passed on to UIKON for interpretation ---
+ return KUnknownError;
+ }
+
+ return (*iErrorTexts)[cc]->At(errorIndex);
+ }
+ }
+
+ return KUnknownError;
+ }
+
+
+/**
+Read the system error texts from errorres.rss only, without using the Uikon CEikErrorResolver.
+This will not pick up any appliation specific errors.
+*/
+void CTextResolver::DoRawReadOfSystemErrorResourcesToArraysL(TInt& aError, TInt& aTextId)
+ {
+ ASSERT(!iCoe);
+ TResourceReader reader;
+ ReadLocalizedSeparatorCharacterFromResourceAndPrepareResourceReaderLC(reader);
+
+ // Lets handle KErrNoMemory as a special case, this this way we can maybe avoid extra "Resolving Errors"
+ if (aError == KErrNoMemory)
+ {
+ ASSERT(!iTextBuffer && !iTitleText);
+ aTextId = R_ERROR_RES_NO_MEMORY;
+ iTextBuffer = AllocReadUnicodeString(iResFile, aTextId);
+ iTitleText = AllocReadUnicodeString(iResFile, R_BASE);
+ User::Leave(KErrNoMemory);
+ }
+
+ if(iStartError && iErrorTexts && iFlags && iAppTexts)
+ {
+ CleanupStack::PopAndDestroy(); // rBuffer
+ return; // Already all done
+ }
+
+ // The resource data is used differenciate between the old and new resource formats
+ // (i.e, resources using title text and one's without using title text)
+ // This API only support the new format, so just check that it is on the new format
+ const TInt dummy = reader.ReadInt16();
+ const TInt version = reader.ReadInt16();
+ __ASSERT_ALWAYS(dummy == 0 && version == 2, User::Leave(KErrNotSupported));
+
+ // Read into the error arrays
+ const TInt arrayCount = reader.ReadInt16();
+
+ ASSERT(!iStartError && !iErrorTexts && !iFlags && !iAppTexts);
+ iStartError = new(ELeave) CArrayFixFlat<TInt>(arrayCount);
+ iErrorTexts = new(ELeave) CArrayPtrSeg<CErrorResourceIdArray>(arrayCount);
+ iFlags = new(ELeave) CArrayPtrSeg<CErrorResourceFlagArray>(arrayCount);
+ iAppTexts = new(ELeave) CArrayFixFlat<TInt>(arrayCount);
+
+ for (TInt cc = 0; cc < arrayCount; ++cc)
+ {
+ // Read in error array
+ iAppTexts->AppendL(reader.ReadInt32()); // Application indicators
+ iStartError->AppendL(reader.ReadInt32());
+
+ const TInt listId = reader.ReadInt32();
+
+ TResourceReader reader2;
+ HBufC8* rBuffer = iResFile.AllocReadL(listId & KRIMask); // Remove offset from id
+ reader2.SetBuffer(rBuffer);
+ CleanupStack::PushL(rBuffer);
+
+ const TInt count = reader2.ReadInt16();
+ CArrayFixFlat<TInt>* array = new(ELeave) CErrorResourceIdArray(count);
+ CleanupStack::PushL(array);
+
+ CArrayFixFlat<TInt>* flagarray = new(ELeave) CErrorResourceFlagArray(count);
+ CleanupStack::PushL(flagarray);
+
+ for (TInt dd = 0; dd < count; ++dd)
+ {
+ const TInt flags = reader2.ReadInt8();
+ flagarray->AppendL(flags);
+ // Append resource id for this error text
+ array->AppendL(reader2.ReadInt32());
+ }
+
+ iFlags->AppendL(flagarray);
+ CleanupStack::Pop(flagarray);
+
+ iErrorTexts->AppendL(array);
+ CleanupStack::Pop(array);
+
+ CleanupStack::PopAndDestroy(rBuffer);
+ }
+
+ CleanupStack::PopAndDestroy(); // reader's rBuffer
+ }
+
+// ---------------------------------------------------------
+// CTextResolver::Reset()
+//
+// Reset the member variables
+// ---------------------------------------------------------
+//
+void CTextResolver::Reset()
+ {
+ if (iBaseResourceFileOffset)
+ {
+ iCoe->DeleteResourceFile(iBaseResourceFileOffset);
+ iBaseResourceFileOffset = 0;
+ }
+
+ if (iErrorTexts)
+ {
+ iErrorTexts->ResetAndDestroy();
+ delete iErrorTexts;
+ iErrorTexts = NULL;
+ }
+
+ if (iFlags)
+ {
+ iFlags->ResetAndDestroy();
+ delete iFlags;
+ iFlags = NULL;
+ }
+
+ delete iStartError;
+ iStartError = NULL;
+
+ delete iAppTexts;
+ iAppTexts = NULL;
+ }
+
+/**
+ErrorResolver resource files in the ?:/resource/errors/ folder must always begin with
+an array of error texts. The Nokia-specific version of the errorres.rss file also
+contains the localized titel/text separator character at the end of the file.
+This method reads the separator character from file using the CCoeEnv provided.
+*/
+void CTextResolver::ReadLocalizedSeparatorCharacterFromResourceL(CCoeEnv& aCoeEnv)
+ {
+ ASSERT(&aCoeEnv);
+
+ if (!iBaseResourceFileOffset)
+ {
+ TFileName filename(KErrorResResourceFileName);
+ BaflUtils::NearestLanguageFile(aCoeEnv.FsSession(), filename);
+
+ iBaseResourceFileOffset = aCoeEnv.AddResourceFileL(filename);
+
+ ASSERT(!iContextSeparator);
+ iContextSeparator = aCoeEnv.AllocReadResourceL(R_LOCALIZED_CONTEXT_SEPARATOR);
+ }
+ }
+
+/**
+ErrorResolver resource files in the ?:/resource/errors/ folder must always begin with
+an array of error texts. The Nokia-specific version of the errorres.rss file also
+contains the localized titel/text separator character at the end of the file.
+This method reads the separator character from file WITHOUT using a CCoeEnv.
+*/
+void CTextResolver::ReadLocalizedSeparatorCharacterFromResourceAndPrepareResourceReaderLC(TResourceReader& aResReader)
+ {
+ ASSERT(!iCoe);
+ ASSERT(!iBaseResourceFileOffset);
+
+ HBufC8* rBuffer = iResFile.AllocReadL(R_ERROR_RES_BASE_LIST & KRIMask); // Remove offset from id
+ aResReader.SetBuffer(rBuffer);
+ CleanupStack::PushL(rBuffer);
+
+ if(!iContextSeparator)
+ iContextSeparator = AllocReadUnicodeString(iResFile, R_LOCALIZED_CONTEXT_SEPARATOR);
+
+ // Leave rBuffer on CleanupStack
+ }
+
+// returns NULL if out of memory
+HBufC* CTextResolver::AllocReadUnicodeString(RResourceFile& aResFile, TInt aTextId)
+ {
+ // Reading Unicode string w/o CCoe
+ HBufC8* tempBuffer = NULL;
+ HBufC* retBuffer = NULL;
+
+ TRAPD(err, tempBuffer = aResFile.AllocReadL((KRIMask & aTextId))); // Remove offset from id
+ if (!err)
+ {
+ __ASSERT_DEBUG((tempBuffer->Length()%2)==0,Panic(aTextId));
+
+ // do bitwise shift to halve the length for mapping the tempBuffer to unicode.
+ TInt newLen = tempBuffer->Length()>>1;
+ TPtrC tempPointer((TText*)tempBuffer->Ptr(), newLen);
+
+ retBuffer = tempPointer.Alloc();
+ delete tempBuffer;
+ }
+
+ return retBuffer;
+ }
+
+TBool CTextResolver::AddContextAndSeparator(TErrorContext aContext)
+ {
+ TBool retval(EFalse);
+
+ if (iTextBuffer && iTitleText && iContextSeparator) // If we got all the parts we need...
+ {
+ //... then put them together according to the aContext argument
+
+ // Context checked after validity of string buffers is checked,
+ // because EFalse return value is required if any of those is NULL.
+ if (aContext == ECtxNoCtxNoSeparator)
+ retval = ETrue;
+ else
+ {
+ HBufC* tempBuffer = iTextBuffer->ReAlloc(iTextBuffer->Length()+iContextSeparator->Length()+iTitleText->Length()+1);
+
+ // If allocation succeeds, insert context. Otherwise iTextBuffer stays as it is.
+ if (tempBuffer)
+ {
+ iTextBuffer = tempBuffer;
+
+ // Add the title ("context") text and separator before the error text
+
+ _LIT(KNewLineChar, "\n");
+ iTextBuffer->Des().Insert(0, KNewLineChar);
+ iTextBuffer->Des().Insert(0, *iContextSeparator);
+
+ if (aContext != ECtxNoCtx)
+ iTextBuffer->Des().Insert(0,*iTitleText);
+
+ retval = ETrue;
+ }
+ }
+ }
+ return retval;
+ }
+
+void CTextResolver::AllocBuffersL()
+ {
+ delete iTitleText;
+ iTitleText = NULL;
+ delete iTextBuffer;
+ iTextBuffer = NULL;
+
+ iTitleText = HBufC::NewL(KEikErrorResolverMaxTextLength);
+ iTextBuffer = HBufC::NewL(KEikErrorResolverMaxTextLength);
+ }
+
+void CTextResolver::DoResolveErrorStringL(TInt aError, TInt& aTextId, TUint& aFlags)
+ {
+ ASSERT(iCoe);
+ AllocBuffersL();
+
+ TPtr errTextPtr = iTextBuffer->Des();
+ TPtr errTitlePtr = iTitleText->Des();
+
+ CEikonEnv::TErrorValidity errValidity = static_cast<CEikonEnv*>(iCoe)->DoGetErrorTextAndTitle(errTextPtr, aError, aTextId, aFlags, errTitlePtr, ETrue);
+
+ if (errValidity == CEikonEnv::EErrorNumInvalid)
+ Panic(aError);
+
+ // If either the iTextBuffer or iTitleText buffers were too small,
+ // they will contain the required length coded as digits into the buffer
+ TLex sizeRealloc(*iTextBuffer);
+ TInt sizeRequiredForTextBuffer = 0;
+ TInt sizeRequiredForTitleBuffer = 0;
+
+ // Try reading the size required, if any
+ sizeRealloc.Val(sizeRequiredForTextBuffer);
+ sizeRealloc = *iTitleText;
+ sizeRealloc.Val(sizeRequiredForTitleBuffer);
+
+ // If sizes were found, realloc and get the error text again
+ if (sizeRequiredForTextBuffer || sizeRequiredForTitleBuffer)
+ {
+ if (sizeRequiredForTextBuffer)
+ {
+ delete iTextBuffer;
+ iTextBuffer = NULL;
+ iTextBuffer = HBufC::NewL(sizeRequiredForTextBuffer);
+ }
+
+ if (sizeRequiredForTitleBuffer)
+ {
+ delete iTitleText;
+ iTitleText = NULL;
+ iTitleText = HBufC::NewL(sizeRequiredForTitleBuffer);
+ }
+
+ TPtr errTextPtr(iTextBuffer->Des());
+ TPtr errTitlePtr(iTitleText->Des());
+ errValidity = static_cast<CEikonEnv*>(iCoe)->DoGetErrorTextAndTitle(errTextPtr, aError, aTextId, aFlags, errTitlePtr, ETrue);
+ if (!iTextBuffer->Length())
+ {
+ delete iTextBuffer;
+ iTextBuffer = NULL;
+ }
+ }
+
+ ReadLocalizedSeparatorCharacterFromResourceL(*iCoe);
+ }
+
+// End of File
+
+