diff -r 000000000000 -r dfb7c4ff071f commsfwtools/preparedefaultcommsdatabase/Tools/ced/src/input.cpp --- /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 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(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(tableXMLMeshMarkerArray); + TRAPD(ret, OpenXMLFileL()); + if (ret != KErrNone) + { + Exit(ret); + } + } + + +void CXMLFileParser::OpenXMLFileL() + { + // Shameless copy of 'CIniData::ConstructL()' + + // Connect to file server + // + TAutoClose fs; + User::LeaveIfError(fs.iObj.Connect()); + fs.PushL(); + + + // Open file + // + TAutoClose 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 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 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 theHashFunc(&DoHash); + + //the key identity relation to campare the keys + const TIdentityRelation theIdentityRelFunc(&AreTheKeysIdentical); + + //create the hashmap on the heap + iLinkByTagRecIdPairs = new(ELeave) RPtrHashMap(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 resolvedLink; + HBufC* tempForHashSearch; + //TBuf 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* key = new(ELeave) TBuf(setting); + TBuf* value = new(ELeave) TBuf(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 buffer = aSetting.Left(pos); + + if(buffer == TPtrC(linkTag)) + { + return pos; + } + } + + return 0; + } + + +void LinkByTagResolver::ResolveLinkToRecIdL(const TPtrC& aSetting, TBuf& 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 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(iter.CurrentKey())->Des(); + return const_cast(iter.CurrentKey()); + + //aTheResolvedPair(const_cast(iter.CurrentKey())->Des()); + } + + CleanupStack::PopAndDestroy(tempForHashSearch); + + //return resolvedLink->Des(); + return resolvedLink; + //aTheResolvedPair(resolvedLink->Des()); + } + +//EOF