commsfwtools/preparedefaultcommsdatabase/Tools/ced/src/input.cpp
changeset 0 dfb7c4ff071f
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/commsfwtools/preparedefaultcommsdatabase/Tools/ced/src/input.cpp	Thu Dec 17 09:22:25 2009 +0200
@@ -0,0 +1,585 @@
+// Copyright (c) 2006-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:
+//
+
+/**
+ @file 
+ @internalComponent
+*/
+
+#include "input.h"
+#include "filedump.h"
+
+namespace
+{
+TUint32 DoHash(const HBufC& aText)
+    {
+    const TDesC& ref = aText;
+    return DefaultHash::Des16(ref);
+    }
+
+TBool AreTheKeysIdentical(const HBufC& aKey1, const HBufC& aKey2)
+    {
+    return (aKey1 == aKey2);
+    }
+} //anonymous namespace
+
+
+
+CInputFileParser* CInputFileParser::FactoryLC(TBool aIsXML, TDesC& aFile, CFileDump* aLog)
+    {
+    CInputFileParser* p = NULL;
+    
+    if (aIsXML)
+        {
+        p = new(ELeave) CXMLFileParser(aFile, aLog);
+        }
+    else
+        {
+        p = new(ELeave) CCfgFileParser(aFile, aLog);
+        }
+
+	CleanupStack::PushL(p);
+	return p;
+    }
+
+
+CInputFileParser::CInputFileParser(TDesC& aFile, CFileDump* aLog) :
+    iFile(aFile),
+    iLog(aLog),
+    iTable(NULL)
+    {
+    }
+
+/**
+*/
+TBool CInputFileParser::IsMeshCompatibleL()
+	{
+	iLog->Msg(_L("MESHINFO: Checking if input file <%S> is mesh compatible"), &iFile);
+	
+    InitialiseL();
+
+    const TText** pTable = iTable;
+    
+	TBuf<MAX_BUFFER_LEN> table            = *pTable;
+	TBool                isMeshCompatible = EFalse;
+	while (table.Compare(TPtrC(NO_MORE_RECORDS)) != 0)
+		{
+		iLog->Msg(_L(" "));
+		iLog->Msg(_L("Parsing %S Table"), &table);
+		
+		if (CheckMeshTemplateL(table) || CheckMeshInsertsL(table))
+        {
+    		iLog->Msg(_L("MESHINFO: Found mesh table <%S>, the configuration file is assumed to be mesh-compatible"), &table);
+			isMeshCompatible = ETrue;
+			break;
+			}					
+		table = *(++pTable);
+		}	
+	return isMeshCompatible;
+	}
+
+
+void CInputFileParser::Exit(TInt aErr)
+    {
+	iLog->Msg(_L("MESHERR: Configuration file [%S] could not be opened"), &iFile);
+	iLog->Msg(_L("==================="));
+	iLog->Msg(_L("ERROR"));
+	User::Leave(aErr);
+    }
+
+
+CCfgFileParser::CCfgFileParser(TDesC& aFile, CFileDump* aLog) :
+    CInputFileParser(aFile, aLog)
+    {
+    }
+
+
+CCfgFileParser::~CCfgFileParser()
+    {
+    iCfg.CloseConfigFile();
+    }
+
+
+void CCfgFileParser::InitialiseL()
+    {
+    iTable = const_cast<const TText**>(tableMeshMarkerArray);
+    if (!iCfg.OpenConfigFile(iFile))
+		{
+		Exit(KErrNotFound);
+		}
+    }
+    
+    
+TBool CCfgFileParser::CheckMeshTemplateL(TDesC& aTable)
+    {
+	return iCfg.OpenTemplateBlock(aTable);
+    }
+    
+    
+TBool CCfgFileParser::CheckMeshInsertsL(TDesC& aTable)
+    {
+	return iCfg.OpenAddBlock(aTable);
+    }
+
+
+CXMLFileParser::CXMLFileParser(TDesC& aFile, CFileDump* aLog) :
+    CInputFileParser(aFile, aLog),
+    iPtr(NULL, 0)
+    {
+    }
+
+
+CXMLFileParser::~CXMLFileParser()
+    {
+    delete iPtr.Ptr();
+    }
+
+
+void CXMLFileParser::InitialiseL()
+    {
+    iTable = const_cast<const TText**>(tableXMLMeshMarkerArray);
+	TRAPD(ret, OpenXMLFileL());
+	if (ret != KErrNone)
+		{
+		Exit(ret);
+		}
+    }
+    
+    
+void CXMLFileParser::OpenXMLFileL()
+    {
+    // Shameless copy of 'CIniData::ConstructL()'
+    
+	// Connect to file server
+	//
+	TAutoClose<RFs> fs;
+	User::LeaveIfError(fs.iObj.Connect());
+	fs.PushL();
+
+
+	// Open file
+	//
+	TAutoClose<RFile> file;
+	TInt size;
+	User::LeaveIfError(file.iObj.Open(fs.iObj, iFile, EFileStreamText | EFileRead));
+	file.PushL();
+
+
+	// Get file size and read in
+	//
+	User::LeaveIfError(file.iObj.Size(size));
+	TText* data = (TText*)User::AllocL(size);
+	iPtr.Set(data, TUint(size)/sizeof(TText), TUint(size)/sizeof(TText));
+	TPtr8 dest((TUint8*)data, 0, size);
+	User::LeaveIfError(file.iObj.Read(dest));
+	TUint8* ptr = (TUint8*)data;
+
+
+	// This is orderred as FEFF assuming the processor is Little Endian
+	// The data in the file is FFFE.		PRR 28/9/98
+	//
+	if (size >= (TInt)sizeof(TText) && iPtr[0]==0xFEFF)
+		{
+		// TODO: strip out UNICODE spaces.
+		
+		// UNICODE Text file so lose the FFFE
+		//
+		Mem::Copy(ptr, ptr+sizeof(TText), size-sizeof(TText));
+		iPtr.Set(data, TUint(size)/sizeof(TText)-1, TUint(size)/sizeof(TText)-1);
+		}
+	else if(size)
+		{
+		// NON-UNICODE so convert to UNICODE
+		//
+		TText* newdata = (TText*)User::AllocL(size * sizeof(TText));
+		iPtr.Set(newdata, size, size);
+		TInt i;
+		TInt actualLength = 0;
+		for (i = 0; i < size ; ++i)
+			{
+			// Lose the spaces (at the cost of having allocated a buffer slightly to big...).
+			// This makes the subsequent string searches so much easier and more efficient.
+			//
+			if (!TChar(ptr[i]).IsSpace())
+			    {
+    			iPtr[actualLength++] = ptr[i];
+    			}
+			}
+		iPtr.Set(newdata, actualLength, size);
+		delete data;
+		}
+
+	file.Pop();
+	fs.Pop();
+    }
+
+
+// Assemble all the XML validation related strings together.
+//
+// In essence, a file is considered mesh compatible (has already been updated with mesh tables) if the record
+// names in 'dbdef.h::tableXMLMeshMarkerArray' exist in stringsof the form "operation="add">" or 
+// "operation="template">"
+//
+_LIT(KTemplate, "template");
+_LIT(KAdd, "add");
+_LIT(KRecordInsertFormat, "<%Soperation=\"%S\">");           
+
+
+TBool CXMLFileParser::CheckMeshTemplateL(TDesC& aTable)
+    {
+	return (SearchXMLFile(KTemplate, aTable));
+    }
+    
+    
+TBool CXMLFileParser::CheckMeshInsertsL(TDesC& aTable)
+    {
+	return SearchXMLFile(KAdd, aTable);
+    }
+
+
+TBool CXMLFileParser::SearchXMLFile(const TDesC& aOpType, const TDesC& aTable)
+	{
+	TBuf<MAX_BUFFER_LEN> xmlTableName;
+	xmlTableName.Format(KRecordInsertFormat, &aTable, &aOpType);
+	
+	// No folding or collation.
+	//
+    return (iPtr.Find(xmlTableName) >= 0);
+	}
+
+//------------------------ LinkByTagResolver ---------------------------
+
+
+LinkByTagResolver* LinkByTagResolver::NewL(CfgFile* aIniData, CFileDump* aLogger)
+    {
+    LinkByTagResolver* self = LinkByTagResolver::NewLC(aIniData, aLogger);
+    CleanupStack::Pop(self);
+    return self;
+    }
+
+LinkByTagResolver* LinkByTagResolver::NewLC(CfgFile* aIniData, CFileDump* aLogger)
+    {
+    LinkByTagResolver* self = new(ELeave) LinkByTagResolver(aIniData, aLogger);
+    CleanupStack::PushL(self);
+    self->ConstructL();
+    return self;
+    }
+
+//the ctor...
+LinkByTagResolver::LinkByTagResolver(CfgFile* aIniData, CFileDump* aLogger)
+    : iLinkByTagRecIdPairs(0)
+    , iConfigFile(aIniData)
+    , iLogger(aLogger)
+    {
+    }
+
+//the dtor
+LinkByTagResolver::~LinkByTagResolver()
+    {
+    
+    TPtrHashMapIter<HBufC, HBufC > iter(*iLinkByTagRecIdPairs);
+    
+    for (TInt i = 0; i < iLinkByTagRecIdPairs->Count(); ++i)
+        {
+        iter.NextValue();
+        
+        const HBufC* cKey = iter.CurrentKey();
+        const HBufC* cValue = iter.CurrentValue();
+        
+        delete cKey;
+        delete cValue;
+        
+        cKey = NULL;
+        cValue = NULL;
+        }
+    
+    iLinkByTagRecIdPairs->Close();
+    delete iLinkByTagRecIdPairs;
+    iLinkByTagRecIdPairs = NULL;
+    
+    }
+
+void LinkByTagResolver::ConstructL()
+    {
+    //the hash function for hashing the table
+    const THashFunction32<HBufC > theHashFunc(&DoHash);
+    
+    //the key identity relation to campare the keys
+    const TIdentityRelation<HBufC > theIdentityRelFunc(&AreTheKeysIdentical);
+    
+    //create the hashmap on the heap
+    iLinkByTagRecIdPairs = new(ELeave) RPtrHashMap<HBufC, HBufC >(theHashFunc, theIdentityRelFunc);
+    
+    FillUpHashMapL();
+    }
+
+void LinkByTagResolver::FillUpHashMapL()
+    {
+    TInt i = 0;
+    TPtrC actTable = TPtrC(TablesWithLinkRecords[i]);
+    
+    
+    while (actTable != TPtrC(NO_MORE_RECORDS))
+        {
+        //first search for template of the given table
+        if (iConfigFile->OpenTemplateBlock(actTable))
+        //got it, search for the possible link fields in the record
+            {
+            ExemineFieldsL(i);
+            }
+        
+        //and now for ADD sections...
+        if (iConfigFile->OpenAddBlock(actTable))
+        //got it, search for the possible link fields in the record
+            {
+            ExemineFieldsL(i);
+            }
+		
+        actTable.Set(TPtrC(TablesWithLinkRecords[++i]));
+        }
+        //if everything went OK, we insert two empt string at the end of the RPtrHashMap
+        //to be able to return an empty string instead of leave in the case if the given
+        //search string not found...
+        /*TBuf<0> temp;
+        HBufC* key = temp.Alloc();
+        HBufC* value = temp.Alloc();*/
+        
+        HBufC* key = HBufC::New(0);
+        HBufC* value = HBufC::New(0);
+        iLinkByTagRecIdPairs->Insert(key, value);
+    }
+
+void LinkByTagResolver::ExemineFieldsL(const TInt aTableIndex)
+    {
+    TInt i = 0;
+    TBuf<MAX_BUFFER_LEN> resolvedLink;
+    HBufC* tempForHashSearch;
+    //TBuf<MAX_BUFFER_LEN> tempForHashSearch;
+    
+    //the fileds form the config file from the section
+    TPtrC actField = TPtrC(LinkRecordsArray[aTableIndex][i]);
+    //the link setting from the file
+    TPtrC setting;
+    //the resolved link to Table.RecId format
+    TPtrC link(resolvedLink);
+                        
+    TBool firstRec = ETrue;
+    while (firstRec || iConfigFile->StepToNextBlock())
+        {
+        i = 0;
+        actField.Set(TPtrC(LinkRecordsArray[aTableIndex][i]));
+        
+        while (actField != TPtrC(NO_MORE_RECORDS))
+            {
+            if (KErrNone == iConfigFile->GetSetting(actField, setting))
+            //ok, got a field from the section
+                {
+                if (SearchForLink(setting))
+                    {
+                    //just for optimization - if the linking is already in the hashmap
+                    //don't resolve it once again... tempForHashSearch should be empty!!!
+                    tempForHashSearch = setting.Alloc();
+                    CleanupStack::PushL(tempForHashSearch);
+                    
+                    if (NULL == iLinkByTagRecIdPairs->Find(*tempForHashSearch))
+                        {
+                        //save the state of the CIniFile object...
+                        /**
+                           This is needed here because in the following sections the pointers in the
+                           CIniFile object will shift and the next call of StepToNextBlock could bring
+                           some unexpected results...
+                        */
+                        TInt aBlockState = iConfigFile->file->BlockState;
+                    	TInt aBlockStart = iConfigFile->file->blockStart;
+                    	TInt aBlockEnd = iConfigFile->file->blockEnd;
+                    	TInt aScanStart = iConfigFile->file->scanStart;
+                        TPtr aSection = iConfigFile->file->section;
+                	    TPtr aBlock = iConfigFile->file->block;
+                	    
+                	    resolvedLink.Zero();
+                        TRAPD(err,ResolveLinkToRecIdL(setting, resolvedLink));
+                        if (err != KErrNone)
+                        	{
+                        	iLogger->Error(_L("ERROR: [%d] Failed to resolve LinkByTag: [%S] - database will be incomplete"), err, &setting);
+                        	User::Leave(err);
+                        	}
+                        
+                        //restore the state...
+                        iConfigFile->file->BlockState = aBlockState;
+                        iConfigFile->file->blockStart = aBlockStart;
+                        iConfigFile->file->blockEnd = aBlockEnd;
+                        iConfigFile->file->scanStart = aScanStart;
+                        iConfigFile->file->section.Set(aSection);
+                        iConfigFile->file->block.Set(aBlock);
+                        
+                        //these pointers will be deleted in the dtor!!!!!
+                        HBufC* key = setting.Alloc();
+                        HBufC* value = resolvedLink.Alloc();
+                        
+                        
+                        
+                        /*TBuf<MAX_BUFFER_LEN>* key = new(ELeave) TBuf<MAX_BUFFER_LEN>(setting);
+                        TBuf<MAX_BUFFER_LEN>* value = new(ELeave) TBuf<MAX_BUFFER_LEN>(linkToResolve);*/
+                        
+                        iLogger->Msg(_L("LinkByTag resolved: [%S] to [%S]"), &setting, &resolvedLink);
+                        
+                        //the key and value are on the heap. What here happens is that 
+                        //the 2 pointers pointing to the heap cells are copied into the 
+                        //RPtrHasMap.
+                        iLinkByTagRecIdPairs->Insert(key, value);
+                        }
+                        
+                        CleanupStack::PopAndDestroy(tempForHashSearch);
+                        //tempForHashSearch.Zero();
+                    }
+                }
+            actField.Set(TPtrC(LinkRecordsArray[aTableIndex][++i]));
+            }
+            
+        firstRec = EFalse;
+        }
+    }
+
+/**
+ if the param is 'Link.TableName.someId' format returns the position of the first
+ '.' which is after the 'Link' word. Else returns 0
+*/
+TInt LinkByTagResolver::SearchForLink(const TPtrC& aSetting)
+    {
+    _LIT(linkTag, "Link");
+    
+    //almost the same code as in DBAccess::SetLinkedRecord
+    const TUint KTableColumnSeperator = '.';
+	TInt pos = aSetting.Locate(TChar(KTableColumnSeperator));
+	
+	if (pos != KErrNotFound) 
+	    {
+	    TBuf<KCommsDbSvrMaxColumnNameLength> buffer = aSetting.Left(pos);
+	    
+	    if(buffer == TPtrC(linkTag))
+	        {
+	        return pos;
+	        }
+	    }
+	
+	return 0;
+    }
+
+
+void LinkByTagResolver::ResolveLinkToRecIdL(const TPtrC& aSetting, TBuf<MAX_BUFFER_LEN>& aResolvedLink)
+    {
+    TInt i = SearchForLink(aSetting);
+    TPtrC tableName = aSetting.Mid(i+1); //now the tableName is TableName.someId
+    
+    //the Id setting from the linked record
+    TPtrC idTagSetting;
+    TPtrC recordId;
+    
+    _LIT(idTag, "Id");
+    _LIT(commdID, "COMMDB_ID ");
+    
+    //now search for the next '.'
+    const TUint KTableColumnSeperator = '.';
+	TInt pos = tableName.Locate(TChar(KTableColumnSeperator));
+	if (pos != KErrNotFound)
+	    {
+	    TPtrC idTagFromLink = tableName.Right(tableName.Length()-pos-1);
+	    tableName.Set(tableName.Left(pos));
+	    
+	    //ok, got the table name and the idTag. Now the tableName should be searched for.
+	    //As this cannot be a template record we use just the 'OpenAddBlock' method.
+
+	    TBool idTagFound = EFalse;	    
+        if (iConfigFile->OpenAddBlock(tableName))
+        //got it, search for the 'Id' fields in the record
+            {
+            TBool firstRec = ETrue;
+            
+    	    while ( firstRec || (!idTagFound && iConfigFile->StepToNextBlock()) )
+                {
+                if (KErrNone == iConfigFile->GetSetting(idTag, idTagSetting))
+                    {
+                    if (idTagFromLink == idTagSetting)
+                    //found the record with the given Id field. Read the record id of it
+                        {
+                        if (KErrNone == iConfigFile->GetSetting(commdID, recordId))
+                            {
+                            idTagFound = ETrue;
+                            
+                            aResolvedLink.Append(tableName);
+                            aResolvedLink.Append('.');
+                            aResolvedLink.Append(recordId);
+                            }
+                        }
+                    }
+                firstRec = EFalse;
+                }
+            }
+            
+	    if (!idTagFound)
+	        {
+	        //The linking should be valid
+	        User::Leave(KErrNotFound);
+	        }
+	    }
+	else
+	    {
+	    //The linking should be valid
+	    User::Leave(KErrNotFound);
+	    }
+    }
+
+const HBufC* LinkByTagResolver::ResolvedIdForTagLink(const TPtrC& aLinkingString/*, TDesC& aTheResolvedPair*/)
+    {
+    HBufC* tempForHashSearch = aLinkingString.Alloc();
+    CleanupStack::PushL(tempForHashSearch);
+    
+    //this will point to an element in the RPtrHashMap, so not needed to push
+    //it on the CleanupStack
+    HBufC* resolvedLink;
+    
+    if ( NULL == (resolvedLink = iLinkByTagRecIdPairs->Find(*tempForHashSearch)) )
+    /**
+    hm... Normaly we should leave here but this would cause the rewrite of the 
+    DBAccess::SetLinkedRecord method which is a non leaving method. On the 
+    other side TRAPPing would be very expensive as this method is called from 
+    a loop...
+    So we return the last element of the RPtrHashMap which will be an empty 
+    descriptior.
+    */
+        {
+        TPtrHashMapIter<HBufC, HBufC > iter(*iLinkByTagRecIdPairs);
+        
+        //iterating at the end of the hashMap...
+        for (TInt i = 0; i < iLinkByTagRecIdPairs->Count(); ++i)
+            {
+            iter.NextValue();
+            }
+            
+        //return the empty string...
+        //return const_cast<HBufC*>(iter.CurrentKey())->Des();
+        return const_cast<HBufC*>(iter.CurrentKey());
+        
+        //aTheResolvedPair(const_cast<HBufC*>(iter.CurrentKey())->Des());
+        }
+        
+    CleanupStack::PopAndDestroy(tempForHashSearch);
+    
+    //return resolvedLink->Des();
+    return resolvedLink;
+    //aTheResolvedPair(resolvedLink->Des());
+    }
+
+//EOF