tzpcside/tzcompiler/Source/TZDocument.cpp
changeset 0 2e3d3ce01487
equal deleted inserted replaced
-1:000000000000 0:2e3d3ce01487
       
     1 // Copyright (c) 2004-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 // DST TZ Database Compiler 
       
    15 // 
       
    16 //
       
    17 
       
    18 #include "TzGlobals.h"
       
    19 
       
    20 #include <string>
       
    21 #include <sstream>
       
    22 #include <iostream>
       
    23 
       
    24 #include <algorithm>
       
    25 #include <direct.h>
       
    26 #include <iomanip>
       
    27 #include <sys/stat.h>
       
    28 
       
    29 #include "TZDocument.h"
       
    30 #include "TZScanner.h"
       
    31 #include "TzTables.h"
       
    32 
       
    33 #include "TzHelpers.h"
       
    34 
       
    35 using namespace std;
       
    36 
       
    37 //============================================================================
       
    38 // CTZDocument::CTZDocument
       
    39 // Constructor.
       
    40 //============================================================================
       
    41 CTZDocument::CTZDocument(MScanner& aScanner)
       
    42 :	iScanner(aScanner)
       
    43 	{
       
    44 	//Create the root element
       
    45 	iRoot = new CTZElement();
       
    46 	iRoot->iParent = NULL;
       
    47 	iOpenedElement = iRoot;
       
    48 	
       
    49 	//Create the tables
       
    50 	iRuleSetTable			= new CTzCpRuleSetsTable(*this);
       
    51 	iRuleDefinitionTable	= new CTzCpRuleDefinitionsTable(*this);
       
    52 	iStringTable			= new CTzCpStringTable(*this);
       
    53 	iRegionsTable			= new CTzCpRegionsTable(*this);
       
    54 	iRuleUseTable			= new CTzCpRuleUsesTable(*this);
       
    55 	iZonesTable				= new CTzCpZonesTable(*this);
       
    56 	iStdTimeAlignmentTable	= new CTzCpStdTimeAlignmentsTable(*this);
       
    57 	iLinkTable				= new CTzCpLinksTable(*this);
       
    58 
       
    59 	ReadConfigurationFile();
       
    60 	}
       
    61 //============================================================================
       
    62 // CTZDocument::~CTZDocument
       
    63 // Destructor
       
    64 //============================================================================
       
    65 CTZDocument::~CTZDocument()
       
    66 	{
       
    67 	WriteConfigurationFile();
       
    68 	if (iRoot)
       
    69 		delete iRoot;
       
    70 
       
    71 	delete iRuleSetTable;
       
    72 	delete iRuleUseTable;
       
    73 	delete iRuleDefinitionTable;
       
    74 	delete iStringTable;
       
    75 	delete iRegionsTable;
       
    76 	delete iZonesTable;
       
    77 	delete iStdTimeAlignmentTable;
       
    78 	delete iLinkTable;
       
    79 	}
       
    80 //============================================================================
       
    81 // CTZDocument::Scan
       
    82 // Delegates the actual file scanning to our CTzCpScanner object.
       
    83 // returns KErrNone if succesful, or any TzErrorCode
       
    84 //============================================================================
       
    85 int CTZDocument::Scan(const char* aFileName)
       
    86 	{
       
    87 	return iScanner.Scan(aFileName);
       
    88 	}
       
    89 //============================================================================
       
    90 // CTZDocument::AddRootChildElement
       
    91 // Adds a new element as a child of the root node
       
    92 //============================================================================
       
    93 void CTZDocument::CreateRootChildElement()
       
    94 	{
       
    95 	iOpenedElement	= new CTZElement();
       
    96 	iOpenedElement->iParent = iRoot;
       
    97 	iRoot->NodeList().push_back(iOpenedElement);
       
    98 	}
       
    99 //============================================================================
       
   100 // CTZDocument::AddChildElement
       
   101 // Creates a new CTZElement as a child node of iOpenedElement.
       
   102 // iOpenedElement is then assigned to the new child node
       
   103 //============================================================================
       
   104 void CTZDocument::CreateChildElement()
       
   105 	{
       
   106 	iOpenedElement = iOpenedElement->CreateChildElement();
       
   107 	}
       
   108 
       
   109 //============================================================================
       
   110 // CTZDocument::AddAttribute
       
   111 // Adds an attribute to the current node
       
   112 //============================================================================
       
   113 void CTZDocument::AddAttribute(const char* aValue)
       
   114 	{
       
   115 	iOpenedElement->AddAttribute(aValue);
       
   116 	}
       
   117 //============================================================================
       
   118 // CTZDocument::CloseElement
       
   119 // Back up to the parent node
       
   120 //============================================================================
       
   121 void CTZDocument::CloseElement()
       
   122 	{
       
   123 	if (iOpenedElement != iRoot)
       
   124 		{
       
   125 		iOpenedElement = iOpenedElement->iParent;
       
   126 		}
       
   127 	}
       
   128 
       
   129 //============================================================================
       
   130 // CTZDocument::Assemble
       
   131 // Iterates through the nodes assembling each one into the relevant T-Classes
       
   132 //============================================================================
       
   133 void CTZDocument::AssembleL()
       
   134 	{
       
   135 	cout.width(30);
       
   136 	CTzCpHelpers::PrintStep("Assembling nodes");
       
   137 	
       
   138 	CTZNode* tmpNode;	
       
   139 	
       
   140 	string currentRuleSetName;
       
   141 	string currentZoneName;
       
   142 
       
   143 	int size = iRoot->NodeList().size();
       
   144 	for (int i = 0;i < size; i++)
       
   145 		{
       
   146 		tmpNode		= iRoot->NodeList()[i];
       
   147 		if (tmpNode->CheckNode())
       
   148 			{
       
   149 			if (strcmpi(KOlsonRuleTag,tmpNode->NodeList()[0]->iValue.c_str()) == 0)
       
   150 				AssembleRuleL(*tmpNode);
       
   151 			else if (strcmpi(KOlsonLinkTag,tmpNode->NodeList()[0]->iValue.c_str()) == 0)
       
   152 				iLinkTable->AssembleL(*tmpNode); // Assemble Links
       
   153 			else if (strcmpi(KOlsonZoneTag,tmpNode->NodeList()[0]->iValue.c_str()) == 0)
       
   154 				AssembleZoneL(*tmpNode);
       
   155 			}
       
   156 		}
       
   157 	}
       
   158 
       
   159 void CTZDocument::AssembleRuleL(CTZNode& aNode)
       
   160 	{
       
   161 	//Conditions tested here:
       
   162 	// 1: The 'To' year in a rule is >= the start year from the configuration file
       
   163 	// 2: The 'To' year in a rule is 'max'.
       
   164 	// 3: The 'To' year in a rule is 'only' but the from year is >= the start year from the configuration file
       
   165 	//If none of these conditions are met, just dump this rule (do nothing)
       
   166 
       
   167 	if ((atoi(aNode.NodeList()[ERuleFormatTo]->iValue.c_str()) >= TzGlobals::iStartYear) ||
       
   168 		(aNode.NodeList()[ERuleFormatTo]->iValue == "max") ||
       
   169 		(aNode.NodeList()[ERuleFormatTo]->iValue == "only" && atoi(aNode.NodeList()[ERuleFormatFrom]->iValue.c_str()) >= TzGlobals::iStartYear))
       
   170 		{	
       
   171 		//==========================Rule Set==========================
       
   172 		//Get a RuleSet to add the RuleUse to
       
   173 		CTzCpRuleSet& aRuleSet = iRuleSetTable->AssembleL(aNode);
       
   174 
       
   175 		//=======================RuleDefinition=======================
       
   176 		//Assemble a rule definition from the node
       
   177 		CTzCpRuleDefinition& aRuleDefinition = iRuleDefinitionTable->AssembleL(aNode);
       
   178 		
       
   179 		//=========================RuleLetter=========================
       
   180 		CTzCpString& aRuleLetter =iStringTable->AddString(aNode.NodeList()[ERuleFormatLetter]->iValue);
       
   181 
       
   182 		//==========================RuleUse===========================
       
   183 		CTzCpRuleUse& aRuleUse = iRuleUseTable->AssembleL(aNode);
       
   184 		
       
   185 		aRuleUse.iRuleDefinitionPtr = &aRuleDefinition;
       
   186 		aRuleDefinition.IncrRefCount();
       
   187 
       
   188 		aRuleUse.iRuleLetterPtr = &aRuleLetter; 
       
   189 		aRuleLetter.IncrRefCount();
       
   190 
       
   191 		//Add the RuleUse reference to the RuleSet				
       
   192 		aRuleSet.AddRuleUse(aRuleUse);
       
   193 		aRuleUse.IncrRefCount();
       
   194 		}
       
   195 	}
       
   196 
       
   197 void CTZDocument::AssembleZoneL(CTZNode& aNode)
       
   198 	{
       
   199 	//Get indexes for the region and zone name strings in the string table
       
   200 	string currentZoneName		= aNode.NodeList()[EZoneFormatName]->iValue;
       
   201 
       
   202 	int slashChar		= currentZoneName.find('/',0);
       
   203 
       
   204 	//'Region' is first part of a zone identity. eg 'Europe' in 'Europe/London'
       
   205 	//'Zone'  is second part of a zone identity. eg 'London' in 'Europe/London'
       
   206 	string regionName;
       
   207 	if (slashChar > 0)
       
   208 		{
       
   209 		regionName = currentZoneName.substr(0,slashChar);
       
   210 		}
       
   211 	else
       
   212 		{
       
   213 		regionName = "";
       
   214 		}
       
   215 	CTzCpString& regionNameRef	= iStringTable->AddString(regionName);
       
   216 	CTzCpString& zoneNameRef	= iStringTable->AddString(currentZoneName.substr(slashChar+1));
       
   217 
       
   218 	//Start building the zone
       
   219 	CTzCpZone* newZone	= iZonesTable->GetZone(zoneNameRef,regionNameRef,true);
       
   220 	newZone->IncrRefCount();
       
   221 	regionNameRef.IncrRefCount();
       
   222 	zoneNameRef.IncrRefCount();
       
   223 
       
   224 	//Get the region
       
   225 	CTzCpRegion& aRegion = iRegionsTable->GetRegion(regionNameRef);
       
   226 	//Add the zone to the regions zone index
       
   227 	
       
   228 	aRegion.iRegionalZonesIndex->AddZoneIndex(*newZone);
       
   229 	newZone->IncrRefCount();
       
   230 
       
   231 	//======================Time Alignments=======================
       
   232 	//Process the zones time alignments
       
   233 	//Check date range
       
   234 	if ((EZoneFormatUntilYear >= aNode.NodeList().size()) ||
       
   235 		(atoi(aNode.NodeList()[EZoneFormatUntilYear]->iValue.c_str()) >= TzGlobals::iStartYear))
       
   236 		{
       
   237 		CTzCpString& timeZoneFormatName = iStringTable->AddString(aNode.NodeList()[EZoneFormatFormat]->iValue);
       
   238 
       
   239 		CTzCpStdTimeAlignment& aNewAlignment = iStdTimeAlignmentTable->AddTimeAlignment(timeZoneFormatName);
       
   240 		timeZoneFormatName.IncrRefCount();
       
   241 
       
   242 		aNewAlignment.AssembleL(aNode);
       
   243 		aNewAlignment.iOffsetToTimeZoneFormatName = &timeZoneFormatName;
       
   244 		//Offset to ruleset
       
   245 		aNewAlignment.iRuleSet = iRuleSetTable->GetRuleSet(aNode.NodeList()[EZoneFormatRules]->iValue);
       
   246 		aNewAlignment.iRuleSet->IncrRefCount();
       
   247 
       
   248 		//Add the new time alignment to the zone
       
   249 		newZone->iTimeAlignments.push_back(&aNewAlignment);
       
   250 		aNewAlignment.IncrRefCount();
       
   251 		}
       
   252 	//Do the same for the zones other time alignments
       
   253 	//A node value of "" indicates a child node
       
   254 	int size = aNode.NodeList().size();
       
   255 	for (int j = 0;j < size; j++)
       
   256 		{
       
   257 		CTZNode* tmpNode2 = aNode.NodeList()[j];
       
   258 		if ( tmpNode2->CheckNode() && (tmpNode2->iValue == ""))
       
   259 			{
       
   260 			//Check date range
       
   261 			if ((EZoneFormatUntilYear >= tmpNode2->NodeList().size()) ||
       
   262 			   (atoi(tmpNode2->NodeList()[EZoneFormatUntilYear]->iValue.c_str()) >= TzGlobals::iStartYear))
       
   263 				{
       
   264 				CTzCpString& timeZoneFormatName = iStringTable->AddString(tmpNode2->NodeList()[EZoneFormatFormat]->iValue);
       
   265 				CTzCpStdTimeAlignment& aNewAlignment = iStdTimeAlignmentTable->AddTimeAlignment(timeZoneFormatName);
       
   266 				timeZoneFormatName.IncrRefCount();
       
   267 
       
   268 				aNewAlignment.AssembleL(*tmpNode2);
       
   269 				aNewAlignment.iOffsetToTimeZoneFormatName = &timeZoneFormatName;
       
   270 				//Offset to ruleset
       
   271 				string ruleSetName = aNode.NodeList()[EZoneFormatRules]->iValue;
       
   272 				aNewAlignment.iRuleSet = iRuleSetTable->GetRuleSet(tmpNode2->NodeList()[EZoneFormatRules]->iValue);
       
   273 				aNewAlignment.iRuleSet->IncrRefCount();
       
   274 
       
   275 				//Add the new time alignment to the zone
       
   276 				newZone->iTimeAlignments.push_back(&aNewAlignment);
       
   277 				aNewAlignment.IncrRefCount();
       
   278 				}
       
   279 			}
       
   280 		}
       
   281 	}
       
   282 
       
   283 //============================================================================
       
   284 // CTZDocument::Link
       
   285 // Combines the format string from the stdtimealignment with the ruleuse 
       
   286 // letter.  The resulting string is added to the string table and the offset 
       
   287 // to the string is stored back in the stdtimealignment.
       
   288 // We can expect four different formatting cases eg
       
   289 //	1: GMT/BST	: Seperate the two strings and add to string table
       
   290 //	2: C%sT		: Replace %s with letter string from rule use
       
   291 //	3: GMT		: Add to string table if not already added
       
   292 //	4: -		: Ignore (remove %s)
       
   293 //============================================================================
       
   294 void CTZDocument::Link()
       
   295 	{
       
   296 	CTzCpHelpers::PrintStep("Linking");
       
   297 	string formatString;
       
   298 	
       
   299 	//Iterate through all the STDTimeAlignments
       
   300 	int size = iStdTimeAlignmentTable->TimeAlignments().size();
       
   301 	for (int x = 0; x < size;x++)
       
   302 		{
       
   303 		CTzCpStdTimeAlignment* aTimeAlignment = iStdTimeAlignmentTable->TimeAlignments()[x];
       
   304 		string alignmentString = aTimeAlignment->iOffsetToTimeZoneFormatName->iString;
       
   305 		//Get the ruleset
       
   306 		if (aTimeAlignment->iPersistedEntity.iOffsetToRuleSet != KMaxTUint16)
       
   307 			{
       
   308 			CTzCpRuleSet* aRuleSet = aTimeAlignment->iRuleSet;
       
   309 			if (aRuleSet->RuleUses().size() == 0)
       
   310 				{
       
   311 				//Use the alignment string - there are no rule uses here
       
   312 				CTzCpString& stringRef = iStringTable->AddString(alignmentString);
       
   313 				aTimeAlignment->iOffsetsToTimeZonesShortNames.push_back(&stringRef);
       
   314 				stringRef.IncrRefCount();
       
   315 				}
       
   316 			else
       
   317 				{
       
   318 				int size2 = aRuleSet->RuleUses().size();
       
   319 				for (int z = 0; z < size2; z++)
       
   320 					{
       
   321 					
       
   322 					CTzCpRuleUse* aRuleUse = iRuleUseTable->RuleUses()[z];
       
   323 					
       
   324 					//Test for the following condition:
       
   325 					// Rule Use 'To' field is >= Time alignment 'From' field - AND
       
   326 					// Rule Use 'From' field is <= Time Alignment 'To' field
       
   327 					//We assume that the time alignment start field is the end year of the 
       
   328 					//previous time alignment unless x == 0
       
   329 					int timeAlignmentStartYear = (x == 0) ? 0 : iStdTimeAlignmentTable->TimeAlignments()[x-1]->iPersistedEntity.iUntilYear;
       
   330 					
       
   331 					if ((aRuleUse->iPersistedEntity.iUntilYear >= timeAlignmentStartYear) &&
       
   332 						(aRuleUse->iPersistedEntity.iFromYear <= aTimeAlignment->iPersistedEntity.iUntilYear)) 
       
   333 						{						
       
   334 						string letterString = aRuleUse->iRuleLetterPtr->iString;
       
   335 						int slashPos  = alignmentString.find_first_of('/');
       
   336 						int insertPos = alignmentString.find_first_of('%');
       
   337 						if (slashPos != -1)
       
   338 							{
       
   339 							formatString = alignmentString.substr(0,slashPos);
       
   340 							CTzCpString& formatStringRef = iStringTable->AddString(formatString);
       
   341 							aTimeAlignment->iOffsetsToTimeZonesShortNames.push_back(&formatStringRef);
       
   342 							formatStringRef.IncrRefCount();
       
   343 
       
   344 							formatString= alignmentString.substr(slashPos+1);
       
   345 							CTzCpString& stringRef = iStringTable->AddString(formatString);
       
   346 							aTimeAlignment->iOffsetsToTimeZonesShortNames.push_back(&stringRef);
       
   347 							stringRef.IncrRefCount();
       
   348 							}
       
   349 						
       
   350 						else if (insertPos != -1)
       
   351 							{
       
   352 							formatString = alignmentString.substr(0,insertPos);
       
   353 							
       
   354 							CTzCpString& formatStringRef = iStringTable->AddString(formatString);
       
   355 							aTimeAlignment->iOffsetsToTimeZonesShortNames.push_back(&formatStringRef);
       
   356 							formatStringRef.IncrRefCount();
       
   357 							
       
   358 							if (letterString[0] != '-')
       
   359 								{
       
   360 								formatString += letterString;
       
   361 								}
       
   362 							formatString += alignmentString.substr(insertPos+2);
       
   363 							CTzCpString& stringRef = iStringTable->AddString(formatString);
       
   364 							aTimeAlignment->iOffsetsToTimeZonesShortNames.push_back(&stringRef);
       
   365 							stringRef.IncrRefCount();
       
   366 							}
       
   367 						}
       
   368 					}
       
   369 				}
       
   370 			}
       
   371 		}
       
   372 		
       
   373 	//Iterate through the links - discarding invalid ones
       
   374 	std::vector<CTzCpLink*>::iterator iter = iLinkTable->Links().begin();
       
   375 	while(iter != iLinkTable->Links().end())
       
   376 		{
       
   377 		CTzCpZone* zone = iLinkTable->FindZone((*iter)->iLinkString->iString);
       
   378 		if (zone == NULL)
       
   379 			{
       
   380 			//Cannot find a valid zone for this link - discard
       
   381 			iter = iLinkTable->Links().erase(iter);
       
   382 			}
       
   383 		else
       
   384 			{
       
   385 			(*iter)->iLinkedZoneOffset = zone;
       
   386 			++iter;
       
   387 			}
       
   388 		}
       
   389 	}
       
   390 //============================================================================
       
   391 // CTZDocument:Exclude
       
   392 // Removes unwanted entities from the database. Unwanted regions are specified 
       
   393 // in the compiler configuration file.  Removing a region may cause certain 
       
   394 // database entities to become unreferenced.  Each entity has a reference 
       
   395 // count, the entities will only be persisted if their reference count > 0.
       
   396 //============================================================================
       
   397 void CTZDocument::Exclude()
       
   398 	{
       
   399 	if (! TzGlobals::iIncludeAllRegions)
       
   400 		{
       
   401 		bool keep = false;
       
   402 		int size = iRegionsTable->Regions().size();
       
   403 		for (int x = 0; x < size; ++x)
       
   404 			{
       
   405 			CTzCpRegion& region = *iRegionsTable->Regions()[x];
       
   406 			TzGlobals::iAvailableRegions.push_back(region.iRegionNameRef->iString);
       
   407 
       
   408 			std::vector<string>::iterator it = 
       
   409 				find(TzGlobals::iIncludedRegions.begin(),TzGlobals::iIncludedRegions.end(),region.iRegionNameRef->iString);
       
   410 
       
   411 			if (it == TzGlobals::iIncludedRegions.end())
       
   412 				{
       
   413 				//Need to remove this region from the region table,
       
   414 				//add it to the list of excluded regions and
       
   415 				//decrement all its zones reference counts by 1
       
   416 
       
   417 				TzGlobals::iExcludedRegions.push_back(region.iRegionNameRef->iString);
       
   418 				//Don't decrement the regions reference count - it will be 0 by default
       
   419 				region.iRegionNameRef->DecrRefCount();
       
   420 				region.iRegionalZonesIndex->DecrRefCount();
       
   421 				for (int y = 0; y < region.iRegionalZonesIndex->iZoneIndex.size();++y)
       
   422 					{
       
   423 					region.iRegionalZonesIndex->iZoneIndex[y]->DecrRefCount();
       
   424 					}
       
   425 				}
       
   426 			else
       
   427 				{
       
   428 				//Nothing really references a region, but we give it a reference count because we want to keep it
       
   429 				region.IncrRefCount();
       
   430 				}
       
   431 			}
       
   432 		}
       
   433 	else
       
   434 		{
       
   435 		//Using all the regions.  We should still remove unreferenced database entries though
       
   436 		int size = iRegionsTable->Regions().size();
       
   437 		for (int x = 0; x < size; ++x)
       
   438 			{
       
   439 			CTzCpRegion& region = *iRegionsTable->Regions()[x];
       
   440 			TzGlobals::iAvailableRegions.push_back(region.iRegionNameRef->iString);
       
   441 			region.IncrRefCount();
       
   442 			}
       
   443 		}
       
   444 		
       
   445 	iRegionsTable->RemoveUnreferencedEntities();
       
   446 	iZonesTable->RemoveUnreferencedEntities();
       
   447 	iStdTimeAlignmentTable->RemoveUnreferencedEntities();
       
   448 	iRuleSetTable->RemoveUnreferencedEntities();
       
   449 	iRuleUseTable->RemoveUnreferencedEntities();
       
   450 	iRuleDefinitionTable->RemoveUnreferencedEntities();
       
   451 	iStringTable->RemoveUnreferencedEntities();
       
   452 		
       
   453 	}
       
   454 
       
   455 //============================================================================
       
   456 // CTZDocument::HandleScanError
       
   457 //============================================================================
       
   458 void CTZDocument::HandleScanError(const char* aFileName,int aLine,int aCol,char aChar)
       
   459 	{
       
   460 	stringstream os;
       
   461 	os << "Error in file " << aFileName << " line:\t" << aLine << "\tColumn:\t" << aCol << "\tUnexpected character:\t" << aChar;
       
   462 	iErrors.push_back(os.str());
       
   463 	}
       
   464 //============================================================================
       
   465 // CTZDocument::ExternaliseL
       
   466 // Persist the data model to a file to be included in rom
       
   467 //============================================================================
       
   468 void CTZDocument::ExternaliseL()
       
   469 	{
       
   470 	ofstream aFile(TzGlobals::iOutputFilePath.c_str(),ios::out | ios::binary);
       
   471 	if (aFile.bad())
       
   472 		{
       
   473 		//Can't open file for writing - Abort
       
   474 		throw TzGlobals::ETzAbortCreateDatabaseFile;
       
   475 		}
       
   476 	//Write header space at start of file
       
   477 	aFile.write((char*)&iDbHeader,sizeof(iDbHeader));
       
   478 
       
   479 	//Strings
       
   480 	iStringTable->ExternaliseL(aFile);
       
   481 
       
   482 	// add extra characters to make the file size so far a multiple of 4 
       
   483 	// and avoid potential byte alignment problems
       
   484 	int filePos = aFile.tellp();
       
   485 	if (filePos % 4) 
       
   486 		{
       
   487 		char padChar = 0;
       
   488 		for (int i = 4; i > filePos % 4; i--)
       
   489 			{
       
   490 			aFile.write(&padChar,sizeof(char));
       
   491 			}
       
   492 		}
       
   493 
       
   494 	//RuleDefinitions
       
   495 	iRuleDefinitionTable->ExternaliseL(aFile);
       
   496 	//RuleUses
       
   497 	iRuleUseTable->ExternaliseL(aFile);
       
   498 	//RuleSets
       
   499 	iRuleSetTable->ExternaliseL(aFile);
       
   500 	//StdTimeAlignments
       
   501 	iStdTimeAlignmentTable->ExternaliseL(aFile);
       
   502 	//Zones
       
   503 	iZonesTable->ExternaliseL(aFile);
       
   504 	//Regions
       
   505 	iRegionsTable->ExternaliseL(aFile);
       
   506 	//Links (must be externalised after zones)
       
   507 	iLinkTable->ExternaliseL(aFile);
       
   508 
       
   509 
       
   510 
       
   511 	//After externalising all the tables, the header should now be complete.
       
   512 	//Reset to the beginning of the file and rewrite the header.
       
   513 
       
   514 	iDbHeader.iReserved1		= 0;
       
   515 	iDbHeader.iReserved2		= 0;
       
   516 	iDbHeader.iReserved3		= 0;
       
   517 	iDbHeader.iVersion			= KTzDbVersion;
       
   518 	iDbHeader.iStartYear		= TzGlobals::iStartYear;
       
   519 	iDbHeader.iReserved4		= 0;
       
   520 	iDbHeader.iOffsetToDefaultZone = GetDefaultZoneOffset();
       
   521 	aFile.seekp(0);
       
   522 	aFile.write((char*)&iDbHeader,sizeof(iDbHeader));
       
   523 	aFile.close();
       
   524 	}
       
   525 //============================================================================
       
   526 // CTZDocument::GetDefaultZoneOffset
       
   527 // Finds the default zone specified in the configuration file, and returns the
       
   528 // offset to this zone in the zone table
       
   529 //============================================================================
       
   530 TUint16 CTZDocument::GetDefaultZoneOffset() const
       
   531 	{
       
   532 	
       
   533 	string tmpString;
       
   534 	if (strcmpi("Not Set",TzGlobals::iDefaultZoneName) == 0)
       
   535 		{
       
   536 		tmpString = iZonesTable->Zones()[0]->iRegionNameRef->iString;
       
   537 		tmpString += "/";
       
   538 		tmpString += iZonesTable->Zones()[0]->iZoneNameRef->iString;
       
   539 		cout << "Default zone not set.  Using " << tmpString << " instead." <<endl;
       
   540 		}
       
   541 	else
       
   542 		{
       
   543 		tmpString = TzGlobals::iDefaultZoneName;
       
   544 		cout <<"Setting Default zone to " << TzGlobals::iDefaultZoneName << endl;
       
   545 		}
       
   546 	
       
   547 	//Get default zone
       
   548 	int slashChar		= tmpString.find('/',0);
       
   549 
       
   550 	string regStr;
       
   551 	string zoneStr;
       
   552 	if (slashChar > 0)
       
   553 		{
       
   554 		regStr = tmpString.substr(0,slashChar);
       
   555 		zoneStr = tmpString.substr(slashChar+1);
       
   556 		}
       
   557 	else
       
   558 		{
       
   559 		regStr = "";
       
   560 		zoneStr = tmpString;
       
   561 		}
       
   562 
       
   563 	CTzCpString& regionName	= iStringTable->AddString(tmpString.substr(0,slashChar));
       
   564 	CTzCpString& zoneName	= iStringTable->AddString(tmpString.substr(slashChar+1));
       
   565 	
       
   566 	CTzCpZone* defaultZone	= iZonesTable->GetZone(zoneName,regionName,false);
       
   567 
       
   568 	if (defaultZone != NULL)
       
   569 		{
       
   570 		cout << "Found matching zone\t";
       
   571 		cout << defaultZone->iRegionNameRef->iString << " ";
       
   572 		cout << defaultZone->iZoneNameRef->iString << endl;
       
   573 		}
       
   574 	else
       
   575 		{
       
   576 		CTzCpString& firstZone		= iStringTable->AddString(iZonesTable->Zones()[0]->iZoneNameRef->iString);
       
   577 		CTzCpString& firstRegion	= iStringTable->AddString(iZonesTable->Zones()[0]->iRegionNameRef->iString);
       
   578 		
       
   579 		defaultZone = iZonesTable->GetZone(firstZone,firstRegion,false);
       
   580 		cout << TzGlobals::iDefaultZoneName << " not found.  Using ";
       
   581 		cout << defaultZone->iRegionNameRef->iString;
       
   582 		cout << "/";
       
   583 		cout << defaultZone->iZoneNameRef->iString << " instead" << endl;
       
   584 		}
       
   585 	
       
   586 
       
   587 	return defaultZone->iOffset;
       
   588 	}
       
   589 //============================================================================
       
   590 // CTZDocument::DisplayNodeList
       
   591 // Prints out the node list to console
       
   592 //============================================================================
       
   593 void CTZDocument::DisplayNodeList() const
       
   594 	{
       
   595 	cout <<"Nodelist: "<< endl;
       
   596 	CTZNode* tmpNode;	
       
   597 	CTZNode* tmpNode2;	
       
   598 	
       
   599 	int size = iRoot->NodeList().size();
       
   600 	for (int i = 0;i < size;i++)
       
   601 		{
       
   602 		tmpNode = iRoot->NodeList()[i];
       
   603 		int size2 = tmpNode->NodeList().size();
       
   604 		for (int j = 0; j < size2;j++)
       
   605 			{
       
   606 			tmpNode2 = tmpNode->NodeList()[j];
       
   607 
       
   608 			if (tmpNode2->iValue == "")
       
   609 				{
       
   610 				cout <<  endl << ".";
       
   611 				int size3 = tmpNode2->NodeList().size();
       
   612 				for (int k = 0; k < size3;k++)
       
   613 					{
       
   614 					cout << tmpNode2->NodeList()[k]->iValue << " ";
       
   615 					}
       
   616 				}
       
   617 			else
       
   618 				{
       
   619 				cout <<  tmpNode2->iValue << " ";
       
   620 				}
       
   621 			}
       
   622 		cout << endl;
       
   623 		}
       
   624 	}
       
   625 //============================================================================
       
   626 // CTZDocument::GetCommaSeperatedString
       
   627 // Creates a comma seperated string from a string vector
       
   628 //============================================================================
       
   629 string CTZDocument::GetCommaSeparatedString(vector<string>& aStringVector)
       
   630 	{
       
   631 	string tmpString;
       
   632 	int size = aStringVector.size();
       
   633 	for (int j = 0; j < size;j++)
       
   634 		{
       
   635 		tmpString.append(aStringVector[j]);
       
   636 		if (j < size-1)
       
   637 			{
       
   638 			tmpString.append(",");
       
   639 			}
       
   640 		}
       
   641 	return tmpString;
       
   642 	}
       
   643 //============================================================================
       
   644 // CTZDocument::DisplayRegionsTable
       
   645 // Prints out the regions table to console
       
   646 //============================================================================
       
   647 void CTZDocument::DisplayRegionsTable() const
       
   648 	{
       
   649 	int size = iRegionsTable->Regions().size();
       
   650 	for (int j = 0; j < size;j++)
       
   651 		{
       
   652 		cout << "Region " << j << ": " << iRegionsTable->Regions()[j]->iRegionNameRef->iString << endl;
       
   653 		}
       
   654 	}
       
   655 
       
   656 //============================================================================
       
   657 // CTZDocument::DisplayTimeAlignmentTable
       
   658 // Prints out the Time Alignment table to console
       
   659 //============================================================================
       
   660 void CTZDocument::DisplayTimeAlignmentTable() const
       
   661 	{
       
   662 	int size = iStdTimeAlignmentTable->TimeAlignments().size();
       
   663 	for (int j = 0; j < size;j++)
       
   664 		{
       
   665 		cout << "RuleSets " << j << ": " << iStdTimeAlignmentTable->TimeAlignments()[j]->iOffsetToTimeZoneFormatName->iString << endl;
       
   666 		}
       
   667 	}
       
   668 //============================================================================
       
   669 // CTZDocument::DisplayZonesTable
       
   670 // Prints out the zones table to console
       
   671 //============================================================================
       
   672 void CTZDocument::DisplayZonesTable() const
       
   673 	{
       
   674 	int size = iZonesTable->Zones().size();
       
   675 	for (int j = 0; j < size; j++)
       
   676 		{
       
   677 		cout << "Region " << ": " << iZonesTable->Zones()[j]->iRegionNameRef->iString;
       
   678 		cout << "\tZone: " << iZonesTable->Zones()[j]->iZoneNameRef->iString << endl;
       
   679 		}
       
   680 	}
       
   681 //============================================================================
       
   682 // CTZDocument::DisplayRuleSetTable
       
   683 // Prints out the ruleset table to console
       
   684 //============================================================================
       
   685 void CTZDocument::DisplayRuleSetTable() const
       
   686 	{
       
   687 	int size = iRuleSetTable->RuleSets().size();
       
   688 	for (int j = 0; j < size;j++)
       
   689 		{
       
   690 		cout << "RuleSet " << iRuleSetTable->RuleSets()[j]->Name() << ": " << iRuleSetTable->RuleSets()[j]->RuleUses().size() << " rules\tRef:\t" << iRuleSetTable->RuleSets()[j]->ReferenceCount()<< endl;
       
   691 		int size2 = iRuleSetTable->RuleSets()[j]->RuleUses().size();
       
   692 		for (int k = 0; k < size2;k++)
       
   693 			{
       
   694 			cout << "RuleUse:\tFrom: " << iRuleUseTable->RuleUses()[k]->iPersistedEntity.iFromYear;
       
   695 			cout << "\tTo: " << iRuleUseTable->RuleUses()[k]->iPersistedEntity.iFromYear << endl;
       
   696 			}
       
   697 		}
       
   698 	}
       
   699 //============================================================================
       
   700 // CTZDocument::DisplayRuleDefinitionTable
       
   701 // Prints out the rule definition table to console
       
   702 //============================================================================
       
   703 void CTZDocument::DisplayRuleDefinitionTable() const
       
   704 	{
       
   705 	int size = iRuleDefinitionTable->RuleDefinitions().size();
       
   706 	cout << size << " RULES DEFINED" << endl;
       
   707 	for (int z = 0; z < size; z++)
       
   708 		{
       
   709 		TTzRuleDefinition tmpDef = iRuleDefinitionTable->RuleDefinitions()[z]->iPersistedEntity;
       
   710 		cout << "Rule Definition: Saving: ";
       
   711 		cout << (int)(tmpDef.iStdTimeOffset);
       
   712 		cout << "\tTime: " << (int)(tmpDef.iTimeOfChange) << endl;
       
   713 		}
       
   714 	}
       
   715 //============================================================================
       
   716 // CTZDocument::DisplayStringTable
       
   717 // Prints out the string table to console
       
   718 //============================================================================
       
   719 void CTZDocument::DisplayStringTable() const
       
   720 	{
       
   721 	int size = iStringTable->Strings().size();
       
   722 	for (int x = 0; x < size;x++)
       
   723 		{
       
   724 		cout << iStringTable->Strings()[x]->iString << endl;
       
   725 		}
       
   726 	}
       
   727 //============================================================================
       
   728 // CTZDocument::AssignZoneIds
       
   729 // After all the zones have been assembled, we sort them alphabetically
       
   730 // then assign each zone an id.  The id will be read from the configuration
       
   731 // file if the zone already exists.  If this is a new zone, then the zone id
       
   732 // will be equal to the next available zone id from the configuration file,
       
   733 // and the next available zone id will be incremented.
       
   734 //============================================================================
       
   735 void CTZDocument::AssignZoneIds()
       
   736 	{
       
   737 	const int KMaxTzId = 0x3FFF; //Maximum numeric id that can be assigned to a zone
       
   738 	sort(iZonesTable->Zones().begin(),iZonesTable->Zones().end(),CTzCpZone::SZoneFullNameSort());
       
   739 	string fullZoneName;
       
   740 	int size = iZonesTable->Zones().size();
       
   741 	for (int i = 0; i < size;++i)
       
   742 		{
       
   743 		fullZoneName = iZonesTable->Zones()[i]->iRegionNameRef->iString;
       
   744 		if (fullZoneName.length() > 0)
       
   745 			{
       
   746 			fullZoneName += '/';
       
   747 			}
       
   748 		fullZoneName += iZonesTable->Zones()[i]->iZoneNameRef->iString;
       
   749 		int id = GetPrivateProfileInt("ZoneIdentities",fullZoneName.c_str(), KMaxTUint16, TzGlobals::iZoneIdIniFilePath.c_str());
       
   750 		if (id != KMaxTUint16)
       
   751 			{
       
   752 			iZonesTable->Zones()[i]->iLocationId = id; 
       
   753 			}
       
   754 		else
       
   755 			{
       
   756 			iZonesTable->Zones()[i]->iLocationId = TzGlobals::iNextNumericZoneId; 
       
   757 
       
   758 			if(TzGlobals::iNextNumericZoneId < KMaxTzId)
       
   759 				{
       
   760 				TzGlobals::iNextNumericZoneId			+= 8; 
       
   761 				}
       
   762 			else
       
   763 				{
       
   764 				cout << "ERROR: All available numeric ids have been used" << endl;
       
   765 				throw TzGlobals::ETzAbortCreateDatabaseFile;
       
   766 				}
       
   767 			}
       
   768 		}
       
   769 	}
       
   770 
       
   771 //============================================================================
       
   772 // CTZDocument::VerifyZoneIds
       
   773 // Checks that each zone id from TzIdentities.ini is present in the compiled 
       
   774 // database.  If a zone is missing, a warning message is displayed.  It is not 
       
   775 // an error for a zone to not be included in the database.  Possible causes
       
   776 // include a change in zone name in the Olsen data sources, or compilation
       
   777 // of a custom database using a limited region set.
       
   778 //============================================================================
       
   779 void CTZDocument::VerifyZoneIds()
       
   780 	{
       
   781 	//Get the filesize of TzIdentities.ini
       
   782     struct stat results;
       
   783     int iniFileSizeBytes;
       
   784     if (stat(TzGlobals::iZoneIdIniFilePath.c_str(), &results) == 0)
       
   785 		{
       
   786 		iniFileSizeBytes = results.st_size;
       
   787 		}
       
   788     else
       
   789 		{
       
   790 		//It is very unlikely that the above call will fail, as we have already processed
       
   791 		//the TzIdentities.ini file by this point
       
   792 		cout << "WARNING: Could not retrieve TzIdentities.ini file size.  Missing zone warnings will NOT be generated" << endl;
       
   793 		return;
       
   794 		}
       
   795 
       
   796 	//Create a char[] the same size as TzIdentities.ini to store the zone names
       
   797 	char* zoneBuffer = NULL;   
       
   798 	zoneBuffer = new char[iniFileSizeBytes];
       
   799 	for (int i=0; i<iniFileSizeBytes; i++) 
       
   800 		{
       
   801 		zoneBuffer[i] = 0;    // Initialize all elements to zero.
       
   802 		}
       
   803 
       
   804 	//Retrieve all the zone names from TzIdentities.ini
       
   805 	GetPrivateProfileString("ZoneIdentities",0,"",zoneBuffer,iniFileSizeBytes,TzGlobals::iZoneIdIniFilePath.c_str());
       
   806 
       
   807 	//zoneBuffer now contains all the zone names, seperated by null char
       
   808 	//Split zoneBuffer into seperate zone names
       
   809 	string tmpString;
       
   810 	int numZones = iZonesTable->Zones().size();
       
   811 	int slashChar;
       
   812 	string regStr;
       
   813 	string zoneStr;
       
   814 
       
   815 	for (int x = 0; x < iniFileSizeBytes; ++x)
       
   816 		{
       
   817 		if (zoneBuffer[x] != 0)
       
   818 			{
       
   819 			tmpString += zoneBuffer[x];
       
   820 			}
       
   821 		else
       
   822 			{
       
   823 			//tmpString contains a full zone name. See if it is in the database
       
   824 
       
   825 			slashChar = tmpString.find('/',0);
       
   826 			//Split into Region and Zone
       
   827 			if (slashChar > 0)
       
   828 				{
       
   829 				regStr = tmpString.substr(0,slashChar);
       
   830 				zoneStr = tmpString.substr(slashChar+1);
       
   831 				}
       
   832 			else
       
   833 				{
       
   834 				regStr = "";
       
   835 				zoneStr = tmpString;
       
   836 				}
       
   837 
       
   838 			CTzCpString& regionName	= iStringTable->AddString(regStr);
       
   839 			CTzCpString& zoneName	= iStringTable->AddString(zoneStr);
       
   840 	
       
   841 			if (iZonesTable->GetZone(zoneName,regionName,false) == NULL)
       
   842 				{
       
   843 				cout << "WARNING: Zone " << tmpString.c_str() << " not included in dataset" << endl;
       
   844 				}
       
   845 
       
   846 			tmpString.erase();
       
   847 
       
   848 			//The last key is followed by 2 null chars.
       
   849 			//If we find this we reached the last zone and can stop the search
       
   850 			if (zoneBuffer[x+1] == 0)
       
   851 				{
       
   852 				break;
       
   853 				}
       
   854 			}
       
   855 		}
       
   856 
       
   857 	delete [] zoneBuffer;  // Free memory zoneBuffer char[]
       
   858 	zoneBuffer = NULL;
       
   859 	}
       
   860 
       
   861 //============================================================================
       
   862 // CTzDocument::CopyDatabaseFileToOutputDirectory
       
   863 // Copies the created database file to the location specified in the
       
   864 // configuration file.  If there is no location specified, does nothing
       
   865 //============================================================================
       
   866 void CTZDocument::CopyDatabaseFileToOutputDirectory() const
       
   867 	{
       
   868 	char outputDir[KMaxPathLength];
       
   869 	GetPrivateProfileString("TzCompilerConfiguration","OutputDirectory","",outputDir,KMaxPathLength,TzGlobals::iIniFilePath.c_str());
       
   870 
       
   871 	if (strcmpi("",outputDir))
       
   872 		{
       
   873 		//Check the output directory exists - make it if necessary
       
   874 		string mkdir = "mkdir ";
       
   875 		mkdir += outputDir;
       
   876 		system(mkdir.c_str());	
       
   877 
       
   878 		string copyString;
       
   879 
       
   880 		copyString = "copy ";
       
   881 		copyString += TzGlobals::iOutputFilePath;
       
   882 		copyString += " ";
       
   883 		copyString += outputDir;
       
   884 
       
   885 		cout << copyString.c_str() << endl;
       
   886 		system(copyString.c_str());
       
   887 
       
   888 		}
       
   889 	}
       
   890 //============================================================================
       
   891 // CTZDocument::ReadConfigurationFile
       
   892 // Sets global variables from the configuration file.
       
   893 //============================================================================
       
   894 void CTZDocument::ReadConfigurationFile()
       
   895 	{
       
   896 	//Read the ini file to set up default parameters
       
   897 	char buffer[KMaxPathLength];
       
   898 	getcwd(buffer,KMaxPathLength);
       
   899 	
       
   900 	cout.fill('.');	
       
   901 	cout << setiosflags(ios::left);
       
   902 	std::string dataPath(buffer);
       
   903 	TzGlobals::iZoneIdIniFilePath = dataPath + "\\TZIdentities.ini";
       
   904 
       
   905 	dataPath += "\\Data";
       
   906 	
       
   907 	char includeRegions[KMaxFiles];
       
   908 	char inputDir[KMaxPathLength];
       
   909 	char excludedFiles[KMaxFiles];
       
   910 
       
   911 
       
   912 	TzGlobals::iStartYear = GetPrivateProfileInt("TZCompilerConfiguration","EarliestDateOfInterest",KDefaultStartYear,TzGlobals::iIniFilePath.c_str());
       
   913 	if (TzGlobals::iStartYear < KMinStartYear || TzGlobals::iStartYear > KMaxStartYear)
       
   914 	{
       
   915 		TzGlobals::iStartYear = KDefaultStartYear; //invalid year was provided, set it to default value
       
   916 	}
       
   917 	int len = GetPrivateProfileString("TZCompilerConfiguration","DefaultZone","Not Set",TzGlobals::iDefaultZoneName,KMaxZoneNameLength,TzGlobals::iIniFilePath.c_str());
       
   918 	if (0 == len) //no DefaultZone was provided, set it to "Not Set"
       
   919 	{
       
   920 		strcpy(TzGlobals::iDefaultZoneName, "Not Set");
       
   921 	}
       
   922 	len = GetPrivateProfileString("TZCompilerConfiguration","IncludedRegions","All",includeRegions,KMaxFiles,TzGlobals::iIniFilePath.c_str());
       
   923 	if (0 == len) //no includeRegions was provided, set it to "All" - default value
       
   924 	{
       
   925 		strcpy(includeRegions, "All");
       
   926 	}
       
   927 	TzGlobals::iNextNumericZoneId = GetPrivateProfileInt("NextNumericZoneId","NextNumericZoneId",KFirstZoneNumericId,TzGlobals::iZoneIdIniFilePath.c_str());
       
   928 	GetPrivateProfileString("TzCompilerConfiguration","InputDirectory","",inputDir,KMaxPathLength,TzGlobals::iIniFilePath.c_str());
       
   929 	GetPrivateProfileString("Files","ExcludedFiles","",excludedFiles,KMaxFiles,TzGlobals::iIniFilePath.c_str());
       
   930 
       
   931 	//Set files to exclude
       
   932 	char* token;
       
   933 	token = strtok(excludedFiles,",");
       
   934 
       
   935 	while (token != 0)
       
   936 		{
       
   937 		TzGlobals::iExcludedFiles.push_back(token);
       
   938 		token = strtok(NULL,",");
       
   939 		}
       
   940 
       
   941 	if (strcmp(includeRegions, "All") != 0) //do not include all the regions
       
   942 	{
       
   943 		TzGlobals::iIncludeAllRegions = false;
       
   944 		token = strtok(includeRegions,",");
       
   945 
       
   946 		while (token != 0)
       
   947 			{
       
   948 			TzGlobals::iIncludedRegions.push_back(token);
       
   949 			token = strtok(NULL,",");
       
   950 			}
       
   951 	}
       
   952 
       
   953 	TzGlobals::iInputFilePath = inputDir;
       
   954 
       
   955 	if (TzGlobals::iInputFilePath.empty())
       
   956 		{	
       
   957 		//Use current directory
       
   958 		TzGlobals::iInputFilePath += dataPath;
       
   959 		}
       
   960 
       
   961 	// Add a trailing backslash if it doesn't have one
       
   962 	int pathsize = TzGlobals::iInputFilePath.size();
       
   963 	if ((TzGlobals::iInputFilePath).find_last_of("\\") < pathsize-1)
       
   964 		{
       
   965 		TzGlobals::iInputFilePath.append("\\");
       
   966 		}
       
   967 
       
   968 	TzGlobals::iOutputFilePath = buffer;
       
   969 	TzGlobals::iOutputFilePath += "\\tzdb.dbz";
       
   970 
       
   971 	// region mask is not used at the moment
       
   972 	TzGlobals::iRegionMask = 0;
       
   973 
       
   974 	CTzCpHelpers::PrintStep("Using settings from ");
       
   975 	cout << TzGlobals::iIniFilePath.c_str() << endl;
       
   976 	CTzCpHelpers::PrintStep("Data directory is ");
       
   977 	cout << TzGlobals::iInputFilePath.c_str() << endl;
       
   978 	CTzCpHelpers::PrintStep("Start Year:");
       
   979 	cout << TzGlobals::iStartYear << endl;
       
   980 	}
       
   981 //============================================================================
       
   982 // CTZDocument::WriteConfigurationFile
       
   983 // Update the configuration file to reflect the new next available id
       
   984 // and display the time zone identity list
       
   985 //============================================================================
       
   986 void CTZDocument::WriteConfigurationFile()
       
   987 	{
       
   988 	//Update the next available numeric zone id
       
   989 	char tmp[256] = "";
       
   990 	sprintf(tmp,"%d",TzGlobals::iNextNumericZoneId);
       
   991 	WritePrivateProfileString("NextNumericZoneId","NextNumericZoneId",tmp,TzGlobals::iZoneIdIniFilePath.c_str());
       
   992 	WritePrivateProfileString("Regions","AvailableRegions",GetCommaSeparatedString(TzGlobals::iAvailableRegions).c_str(),TzGlobals::iIniFilePath.c_str());
       
   993 	WritePrivateProfileString("Regions","ExcludedRegions",GetCommaSeparatedString(TzGlobals::iExcludedRegions).c_str(),TzGlobals::iIniFilePath.c_str());
       
   994 	WritePrivateProfileString("Files","AvailableFiles",GetCommaSeparatedString(TzGlobals::iAvailableFiles).c_str(),TzGlobals::iIniFilePath.c_str());
       
   995 	// it is assumed that zones have been sorted by location ID before calling this
       
   996 	int numZones = iZonesTable->Zones().size();
       
   997 	string zoneString;
       
   998 	for (int i = 0; i < numZones; i++)
       
   999 		{
       
  1000 		char id[256] = "";
       
  1001 		sprintf(id,"%d",iZonesTable->Zones()[i]->iLocationId);
       
  1002 		zoneString = iZonesTable->Zones()[i]->iRegionNameRef->iString;
       
  1003 		if (zoneString.length() > 0)
       
  1004 			{
       
  1005 			zoneString += '/';
       
  1006 			}
       
  1007 		zoneString += iZonesTable->Zones()[i]->iZoneNameRef->iString;
       
  1008 		WritePrivateProfileString("ZoneIdentities",zoneString.c_str(),id,TzGlobals::iZoneIdIniFilePath.c_str());
       
  1009 		}
       
  1010 	}
       
  1011 
       
  1012 //============================================================================
       
  1013 // CTZDocument::DisplayData
       
  1014 // Display the data that have been parsed. Very useful for diagnostic purposes.
       
  1015 //============================================================================
       
  1016 void CTZDocument::DisplayData() const
       
  1017 	{
       
  1018 	//Have a look whats going on
       
  1019 	DisplayNodeList();
       
  1020 	DisplayRuleDefinitionTable();
       
  1021 	DisplayRuleSetTable();
       
  1022 	DisplayStringTable();
       
  1023 	DisplayZonesTable();
       
  1024 	DisplayTimeAlignmentTable();
       
  1025 	}
       
  1026 
       
  1027 //============================================================================
       
  1028 // End of file
       
  1029 //============================================================================