--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tzpcside/tzcompiler/Source/TZDocument.cpp Tue Feb 02 10:12:00 2010 +0200
@@ -0,0 +1,1029 @@
+// Copyright (c) 2004-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:
+// DST TZ Database Compiler
+//
+//
+
+#include "TzGlobals.h"
+
+#include <string>
+#include <sstream>
+#include <iostream>
+
+#include <algorithm>
+#include <direct.h>
+#include <iomanip>
+#include <sys/stat.h>
+
+#include "TZDocument.h"
+#include "TZScanner.h"
+#include "TzTables.h"
+
+#include "TzHelpers.h"
+
+using namespace std;
+
+//============================================================================
+// CTZDocument::CTZDocument
+// Constructor.
+//============================================================================
+CTZDocument::CTZDocument(MScanner& aScanner)
+: iScanner(aScanner)
+ {
+ //Create the root element
+ iRoot = new CTZElement();
+ iRoot->iParent = NULL;
+ iOpenedElement = iRoot;
+
+ //Create the tables
+ iRuleSetTable = new CTzCpRuleSetsTable(*this);
+ iRuleDefinitionTable = new CTzCpRuleDefinitionsTable(*this);
+ iStringTable = new CTzCpStringTable(*this);
+ iRegionsTable = new CTzCpRegionsTable(*this);
+ iRuleUseTable = new CTzCpRuleUsesTable(*this);
+ iZonesTable = new CTzCpZonesTable(*this);
+ iStdTimeAlignmentTable = new CTzCpStdTimeAlignmentsTable(*this);
+ iLinkTable = new CTzCpLinksTable(*this);
+
+ ReadConfigurationFile();
+ }
+//============================================================================
+// CTZDocument::~CTZDocument
+// Destructor
+//============================================================================
+CTZDocument::~CTZDocument()
+ {
+ WriteConfigurationFile();
+ if (iRoot)
+ delete iRoot;
+
+ delete iRuleSetTable;
+ delete iRuleUseTable;
+ delete iRuleDefinitionTable;
+ delete iStringTable;
+ delete iRegionsTable;
+ delete iZonesTable;
+ delete iStdTimeAlignmentTable;
+ delete iLinkTable;
+ }
+//============================================================================
+// CTZDocument::Scan
+// Delegates the actual file scanning to our CTzCpScanner object.
+// returns KErrNone if succesful, or any TzErrorCode
+//============================================================================
+int CTZDocument::Scan(const char* aFileName)
+ {
+ return iScanner.Scan(aFileName);
+ }
+//============================================================================
+// CTZDocument::AddRootChildElement
+// Adds a new element as a child of the root node
+//============================================================================
+void CTZDocument::CreateRootChildElement()
+ {
+ iOpenedElement = new CTZElement();
+ iOpenedElement->iParent = iRoot;
+ iRoot->NodeList().push_back(iOpenedElement);
+ }
+//============================================================================
+// CTZDocument::AddChildElement
+// Creates a new CTZElement as a child node of iOpenedElement.
+// iOpenedElement is then assigned to the new child node
+//============================================================================
+void CTZDocument::CreateChildElement()
+ {
+ iOpenedElement = iOpenedElement->CreateChildElement();
+ }
+
+//============================================================================
+// CTZDocument::AddAttribute
+// Adds an attribute to the current node
+//============================================================================
+void CTZDocument::AddAttribute(const char* aValue)
+ {
+ iOpenedElement->AddAttribute(aValue);
+ }
+//============================================================================
+// CTZDocument::CloseElement
+// Back up to the parent node
+//============================================================================
+void CTZDocument::CloseElement()
+ {
+ if (iOpenedElement != iRoot)
+ {
+ iOpenedElement = iOpenedElement->iParent;
+ }
+ }
+
+//============================================================================
+// CTZDocument::Assemble
+// Iterates through the nodes assembling each one into the relevant T-Classes
+//============================================================================
+void CTZDocument::AssembleL()
+ {
+ cout.width(30);
+ CTzCpHelpers::PrintStep("Assembling nodes");
+
+ CTZNode* tmpNode;
+
+ string currentRuleSetName;
+ string currentZoneName;
+
+ int size = iRoot->NodeList().size();
+ for (int i = 0;i < size; i++)
+ {
+ tmpNode = iRoot->NodeList()[i];
+ if (tmpNode->CheckNode())
+ {
+ if (strcmpi(KOlsonRuleTag,tmpNode->NodeList()[0]->iValue.c_str()) == 0)
+ AssembleRuleL(*tmpNode);
+ else if (strcmpi(KOlsonLinkTag,tmpNode->NodeList()[0]->iValue.c_str()) == 0)
+ iLinkTable->AssembleL(*tmpNode); // Assemble Links
+ else if (strcmpi(KOlsonZoneTag,tmpNode->NodeList()[0]->iValue.c_str()) == 0)
+ AssembleZoneL(*tmpNode);
+ }
+ }
+ }
+
+void CTZDocument::AssembleRuleL(CTZNode& aNode)
+ {
+ //Conditions tested here:
+ // 1: The 'To' year in a rule is >= the start year from the configuration file
+ // 2: The 'To' year in a rule is 'max'.
+ // 3: The 'To' year in a rule is 'only' but the from year is >= the start year from the configuration file
+ //If none of these conditions are met, just dump this rule (do nothing)
+
+ if ((atoi(aNode.NodeList()[ERuleFormatTo]->iValue.c_str()) >= TzGlobals::iStartYear) ||
+ (aNode.NodeList()[ERuleFormatTo]->iValue == "max") ||
+ (aNode.NodeList()[ERuleFormatTo]->iValue == "only" && atoi(aNode.NodeList()[ERuleFormatFrom]->iValue.c_str()) >= TzGlobals::iStartYear))
+ {
+ //==========================Rule Set==========================
+ //Get a RuleSet to add the RuleUse to
+ CTzCpRuleSet& aRuleSet = iRuleSetTable->AssembleL(aNode);
+
+ //=======================RuleDefinition=======================
+ //Assemble a rule definition from the node
+ CTzCpRuleDefinition& aRuleDefinition = iRuleDefinitionTable->AssembleL(aNode);
+
+ //=========================RuleLetter=========================
+ CTzCpString& aRuleLetter =iStringTable->AddString(aNode.NodeList()[ERuleFormatLetter]->iValue);
+
+ //==========================RuleUse===========================
+ CTzCpRuleUse& aRuleUse = iRuleUseTable->AssembleL(aNode);
+
+ aRuleUse.iRuleDefinitionPtr = &aRuleDefinition;
+ aRuleDefinition.IncrRefCount();
+
+ aRuleUse.iRuleLetterPtr = &aRuleLetter;
+ aRuleLetter.IncrRefCount();
+
+ //Add the RuleUse reference to the RuleSet
+ aRuleSet.AddRuleUse(aRuleUse);
+ aRuleUse.IncrRefCount();
+ }
+ }
+
+void CTZDocument::AssembleZoneL(CTZNode& aNode)
+ {
+ //Get indexes for the region and zone name strings in the string table
+ string currentZoneName = aNode.NodeList()[EZoneFormatName]->iValue;
+
+ int slashChar = currentZoneName.find('/',0);
+
+ //'Region' is first part of a zone identity. eg 'Europe' in 'Europe/London'
+ //'Zone' is second part of a zone identity. eg 'London' in 'Europe/London'
+ string regionName;
+ if (slashChar > 0)
+ {
+ regionName = currentZoneName.substr(0,slashChar);
+ }
+ else
+ {
+ regionName = "";
+ }
+ CTzCpString& regionNameRef = iStringTable->AddString(regionName);
+ CTzCpString& zoneNameRef = iStringTable->AddString(currentZoneName.substr(slashChar+1));
+
+ //Start building the zone
+ CTzCpZone* newZone = iZonesTable->GetZone(zoneNameRef,regionNameRef,true);
+ newZone->IncrRefCount();
+ regionNameRef.IncrRefCount();
+ zoneNameRef.IncrRefCount();
+
+ //Get the region
+ CTzCpRegion& aRegion = iRegionsTable->GetRegion(regionNameRef);
+ //Add the zone to the regions zone index
+
+ aRegion.iRegionalZonesIndex->AddZoneIndex(*newZone);
+ newZone->IncrRefCount();
+
+ //======================Time Alignments=======================
+ //Process the zones time alignments
+ //Check date range
+ if ((EZoneFormatUntilYear >= aNode.NodeList().size()) ||
+ (atoi(aNode.NodeList()[EZoneFormatUntilYear]->iValue.c_str()) >= TzGlobals::iStartYear))
+ {
+ CTzCpString& timeZoneFormatName = iStringTable->AddString(aNode.NodeList()[EZoneFormatFormat]->iValue);
+
+ CTzCpStdTimeAlignment& aNewAlignment = iStdTimeAlignmentTable->AddTimeAlignment(timeZoneFormatName);
+ timeZoneFormatName.IncrRefCount();
+
+ aNewAlignment.AssembleL(aNode);
+ aNewAlignment.iOffsetToTimeZoneFormatName = &timeZoneFormatName;
+ //Offset to ruleset
+ aNewAlignment.iRuleSet = iRuleSetTable->GetRuleSet(aNode.NodeList()[EZoneFormatRules]->iValue);
+ aNewAlignment.iRuleSet->IncrRefCount();
+
+ //Add the new time alignment to the zone
+ newZone->iTimeAlignments.push_back(&aNewAlignment);
+ aNewAlignment.IncrRefCount();
+ }
+ //Do the same for the zones other time alignments
+ //A node value of "" indicates a child node
+ int size = aNode.NodeList().size();
+ for (int j = 0;j < size; j++)
+ {
+ CTZNode* tmpNode2 = aNode.NodeList()[j];
+ if ( tmpNode2->CheckNode() && (tmpNode2->iValue == ""))
+ {
+ //Check date range
+ if ((EZoneFormatUntilYear >= tmpNode2->NodeList().size()) ||
+ (atoi(tmpNode2->NodeList()[EZoneFormatUntilYear]->iValue.c_str()) >= TzGlobals::iStartYear))
+ {
+ CTzCpString& timeZoneFormatName = iStringTable->AddString(tmpNode2->NodeList()[EZoneFormatFormat]->iValue);
+ CTzCpStdTimeAlignment& aNewAlignment = iStdTimeAlignmentTable->AddTimeAlignment(timeZoneFormatName);
+ timeZoneFormatName.IncrRefCount();
+
+ aNewAlignment.AssembleL(*tmpNode2);
+ aNewAlignment.iOffsetToTimeZoneFormatName = &timeZoneFormatName;
+ //Offset to ruleset
+ string ruleSetName = aNode.NodeList()[EZoneFormatRules]->iValue;
+ aNewAlignment.iRuleSet = iRuleSetTable->GetRuleSet(tmpNode2->NodeList()[EZoneFormatRules]->iValue);
+ aNewAlignment.iRuleSet->IncrRefCount();
+
+ //Add the new time alignment to the zone
+ newZone->iTimeAlignments.push_back(&aNewAlignment);
+ aNewAlignment.IncrRefCount();
+ }
+ }
+ }
+ }
+
+//============================================================================
+// CTZDocument::Link
+// Combines the format string from the stdtimealignment with the ruleuse
+// letter. The resulting string is added to the string table and the offset
+// to the string is stored back in the stdtimealignment.
+// We can expect four different formatting cases eg
+// 1: GMT/BST : Seperate the two strings and add to string table
+// 2: C%sT : Replace %s with letter string from rule use
+// 3: GMT : Add to string table if not already added
+// 4: - : Ignore (remove %s)
+//============================================================================
+void CTZDocument::Link()
+ {
+ CTzCpHelpers::PrintStep("Linking");
+ string formatString;
+
+ //Iterate through all the STDTimeAlignments
+ int size = iStdTimeAlignmentTable->TimeAlignments().size();
+ for (int x = 0; x < size;x++)
+ {
+ CTzCpStdTimeAlignment* aTimeAlignment = iStdTimeAlignmentTable->TimeAlignments()[x];
+ string alignmentString = aTimeAlignment->iOffsetToTimeZoneFormatName->iString;
+ //Get the ruleset
+ if (aTimeAlignment->iPersistedEntity.iOffsetToRuleSet != KMaxTUint16)
+ {
+ CTzCpRuleSet* aRuleSet = aTimeAlignment->iRuleSet;
+ if (aRuleSet->RuleUses().size() == 0)
+ {
+ //Use the alignment string - there are no rule uses here
+ CTzCpString& stringRef = iStringTable->AddString(alignmentString);
+ aTimeAlignment->iOffsetsToTimeZonesShortNames.push_back(&stringRef);
+ stringRef.IncrRefCount();
+ }
+ else
+ {
+ int size2 = aRuleSet->RuleUses().size();
+ for (int z = 0; z < size2; z++)
+ {
+
+ CTzCpRuleUse* aRuleUse = iRuleUseTable->RuleUses()[z];
+
+ //Test for the following condition:
+ // Rule Use 'To' field is >= Time alignment 'From' field - AND
+ // Rule Use 'From' field is <= Time Alignment 'To' field
+ //We assume that the time alignment start field is the end year of the
+ //previous time alignment unless x == 0
+ int timeAlignmentStartYear = (x == 0) ? 0 : iStdTimeAlignmentTable->TimeAlignments()[x-1]->iPersistedEntity.iUntilYear;
+
+ if ((aRuleUse->iPersistedEntity.iUntilYear >= timeAlignmentStartYear) &&
+ (aRuleUse->iPersistedEntity.iFromYear <= aTimeAlignment->iPersistedEntity.iUntilYear))
+ {
+ string letterString = aRuleUse->iRuleLetterPtr->iString;
+ int slashPos = alignmentString.find_first_of('/');
+ int insertPos = alignmentString.find_first_of('%');
+ if (slashPos != -1)
+ {
+ formatString = alignmentString.substr(0,slashPos);
+ CTzCpString& formatStringRef = iStringTable->AddString(formatString);
+ aTimeAlignment->iOffsetsToTimeZonesShortNames.push_back(&formatStringRef);
+ formatStringRef.IncrRefCount();
+
+ formatString= alignmentString.substr(slashPos+1);
+ CTzCpString& stringRef = iStringTable->AddString(formatString);
+ aTimeAlignment->iOffsetsToTimeZonesShortNames.push_back(&stringRef);
+ stringRef.IncrRefCount();
+ }
+
+ else if (insertPos != -1)
+ {
+ formatString = alignmentString.substr(0,insertPos);
+
+ CTzCpString& formatStringRef = iStringTable->AddString(formatString);
+ aTimeAlignment->iOffsetsToTimeZonesShortNames.push_back(&formatStringRef);
+ formatStringRef.IncrRefCount();
+
+ if (letterString[0] != '-')
+ {
+ formatString += letterString;
+ }
+ formatString += alignmentString.substr(insertPos+2);
+ CTzCpString& stringRef = iStringTable->AddString(formatString);
+ aTimeAlignment->iOffsetsToTimeZonesShortNames.push_back(&stringRef);
+ stringRef.IncrRefCount();
+ }
+ }
+ }
+ }
+ }
+ }
+
+ //Iterate through the links - discarding invalid ones
+ std::vector<CTzCpLink*>::iterator iter = iLinkTable->Links().begin();
+ while(iter != iLinkTable->Links().end())
+ {
+ CTzCpZone* zone = iLinkTable->FindZone((*iter)->iLinkString->iString);
+ if (zone == NULL)
+ {
+ //Cannot find a valid zone for this link - discard
+ iter = iLinkTable->Links().erase(iter);
+ }
+ else
+ {
+ (*iter)->iLinkedZoneOffset = zone;
+ ++iter;
+ }
+ }
+ }
+//============================================================================
+// CTZDocument:Exclude
+// Removes unwanted entities from the database. Unwanted regions are specified
+// in the compiler configuration file. Removing a region may cause certain
+// database entities to become unreferenced. Each entity has a reference
+// count, the entities will only be persisted if their reference count > 0.
+//============================================================================
+void CTZDocument::Exclude()
+ {
+ if (! TzGlobals::iIncludeAllRegions)
+ {
+ bool keep = false;
+ int size = iRegionsTable->Regions().size();
+ for (int x = 0; x < size; ++x)
+ {
+ CTzCpRegion& region = *iRegionsTable->Regions()[x];
+ TzGlobals::iAvailableRegions.push_back(region.iRegionNameRef->iString);
+
+ std::vector<string>::iterator it =
+ find(TzGlobals::iIncludedRegions.begin(),TzGlobals::iIncludedRegions.end(),region.iRegionNameRef->iString);
+
+ if (it == TzGlobals::iIncludedRegions.end())
+ {
+ //Need to remove this region from the region table,
+ //add it to the list of excluded regions and
+ //decrement all its zones reference counts by 1
+
+ TzGlobals::iExcludedRegions.push_back(region.iRegionNameRef->iString);
+ //Don't decrement the regions reference count - it will be 0 by default
+ region.iRegionNameRef->DecrRefCount();
+ region.iRegionalZonesIndex->DecrRefCount();
+ for (int y = 0; y < region.iRegionalZonesIndex->iZoneIndex.size();++y)
+ {
+ region.iRegionalZonesIndex->iZoneIndex[y]->DecrRefCount();
+ }
+ }
+ else
+ {
+ //Nothing really references a region, but we give it a reference count because we want to keep it
+ region.IncrRefCount();
+ }
+ }
+ }
+ else
+ {
+ //Using all the regions. We should still remove unreferenced database entries though
+ int size = iRegionsTable->Regions().size();
+ for (int x = 0; x < size; ++x)
+ {
+ CTzCpRegion& region = *iRegionsTable->Regions()[x];
+ TzGlobals::iAvailableRegions.push_back(region.iRegionNameRef->iString);
+ region.IncrRefCount();
+ }
+ }
+
+ iRegionsTable->RemoveUnreferencedEntities();
+ iZonesTable->RemoveUnreferencedEntities();
+ iStdTimeAlignmentTable->RemoveUnreferencedEntities();
+ iRuleSetTable->RemoveUnreferencedEntities();
+ iRuleUseTable->RemoveUnreferencedEntities();
+ iRuleDefinitionTable->RemoveUnreferencedEntities();
+ iStringTable->RemoveUnreferencedEntities();
+
+ }
+
+//============================================================================
+// CTZDocument::HandleScanError
+//============================================================================
+void CTZDocument::HandleScanError(const char* aFileName,int aLine,int aCol,char aChar)
+ {
+ stringstream os;
+ os << "Error in file " << aFileName << " line:\t" << aLine << "\tColumn:\t" << aCol << "\tUnexpected character:\t" << aChar;
+ iErrors.push_back(os.str());
+ }
+//============================================================================
+// CTZDocument::ExternaliseL
+// Persist the data model to a file to be included in rom
+//============================================================================
+void CTZDocument::ExternaliseL()
+ {
+ ofstream aFile(TzGlobals::iOutputFilePath.c_str(),ios::out | ios::binary);
+ if (aFile.bad())
+ {
+ //Can't open file for writing - Abort
+ throw TzGlobals::ETzAbortCreateDatabaseFile;
+ }
+ //Write header space at start of file
+ aFile.write((char*)&iDbHeader,sizeof(iDbHeader));
+
+ //Strings
+ iStringTable->ExternaliseL(aFile);
+
+ // add extra characters to make the file size so far a multiple of 4
+ // and avoid potential byte alignment problems
+ int filePos = aFile.tellp();
+ if (filePos % 4)
+ {
+ char padChar = 0;
+ for (int i = 4; i > filePos % 4; i--)
+ {
+ aFile.write(&padChar,sizeof(char));
+ }
+ }
+
+ //RuleDefinitions
+ iRuleDefinitionTable->ExternaliseL(aFile);
+ //RuleUses
+ iRuleUseTable->ExternaliseL(aFile);
+ //RuleSets
+ iRuleSetTable->ExternaliseL(aFile);
+ //StdTimeAlignments
+ iStdTimeAlignmentTable->ExternaliseL(aFile);
+ //Zones
+ iZonesTable->ExternaliseL(aFile);
+ //Regions
+ iRegionsTable->ExternaliseL(aFile);
+ //Links (must be externalised after zones)
+ iLinkTable->ExternaliseL(aFile);
+
+
+
+ //After externalising all the tables, the header should now be complete.
+ //Reset to the beginning of the file and rewrite the header.
+
+ iDbHeader.iReserved1 = 0;
+ iDbHeader.iReserved2 = 0;
+ iDbHeader.iReserved3 = 0;
+ iDbHeader.iVersion = KTzDbVersion;
+ iDbHeader.iStartYear = TzGlobals::iStartYear;
+ iDbHeader.iReserved4 = 0;
+ iDbHeader.iOffsetToDefaultZone = GetDefaultZoneOffset();
+ aFile.seekp(0);
+ aFile.write((char*)&iDbHeader,sizeof(iDbHeader));
+ aFile.close();
+ }
+//============================================================================
+// CTZDocument::GetDefaultZoneOffset
+// Finds the default zone specified in the configuration file, and returns the
+// offset to this zone in the zone table
+//============================================================================
+TUint16 CTZDocument::GetDefaultZoneOffset() const
+ {
+
+ string tmpString;
+ if (strcmpi("Not Set",TzGlobals::iDefaultZoneName) == 0)
+ {
+ tmpString = iZonesTable->Zones()[0]->iRegionNameRef->iString;
+ tmpString += "/";
+ tmpString += iZonesTable->Zones()[0]->iZoneNameRef->iString;
+ cout << "Default zone not set. Using " << tmpString << " instead." <<endl;
+ }
+ else
+ {
+ tmpString = TzGlobals::iDefaultZoneName;
+ cout <<"Setting Default zone to " << TzGlobals::iDefaultZoneName << endl;
+ }
+
+ //Get default zone
+ int slashChar = tmpString.find('/',0);
+
+ string regStr;
+ string zoneStr;
+ if (slashChar > 0)
+ {
+ regStr = tmpString.substr(0,slashChar);
+ zoneStr = tmpString.substr(slashChar+1);
+ }
+ else
+ {
+ regStr = "";
+ zoneStr = tmpString;
+ }
+
+ CTzCpString& regionName = iStringTable->AddString(tmpString.substr(0,slashChar));
+ CTzCpString& zoneName = iStringTable->AddString(tmpString.substr(slashChar+1));
+
+ CTzCpZone* defaultZone = iZonesTable->GetZone(zoneName,regionName,false);
+
+ if (defaultZone != NULL)
+ {
+ cout << "Found matching zone\t";
+ cout << defaultZone->iRegionNameRef->iString << " ";
+ cout << defaultZone->iZoneNameRef->iString << endl;
+ }
+ else
+ {
+ CTzCpString& firstZone = iStringTable->AddString(iZonesTable->Zones()[0]->iZoneNameRef->iString);
+ CTzCpString& firstRegion = iStringTable->AddString(iZonesTable->Zones()[0]->iRegionNameRef->iString);
+
+ defaultZone = iZonesTable->GetZone(firstZone,firstRegion,false);
+ cout << TzGlobals::iDefaultZoneName << " not found. Using ";
+ cout << defaultZone->iRegionNameRef->iString;
+ cout << "/";
+ cout << defaultZone->iZoneNameRef->iString << " instead" << endl;
+ }
+
+
+ return defaultZone->iOffset;
+ }
+//============================================================================
+// CTZDocument::DisplayNodeList
+// Prints out the node list to console
+//============================================================================
+void CTZDocument::DisplayNodeList() const
+ {
+ cout <<"Nodelist: "<< endl;
+ CTZNode* tmpNode;
+ CTZNode* tmpNode2;
+
+ int size = iRoot->NodeList().size();
+ for (int i = 0;i < size;i++)
+ {
+ tmpNode = iRoot->NodeList()[i];
+ int size2 = tmpNode->NodeList().size();
+ for (int j = 0; j < size2;j++)
+ {
+ tmpNode2 = tmpNode->NodeList()[j];
+
+ if (tmpNode2->iValue == "")
+ {
+ cout << endl << ".";
+ int size3 = tmpNode2->NodeList().size();
+ for (int k = 0; k < size3;k++)
+ {
+ cout << tmpNode2->NodeList()[k]->iValue << " ";
+ }
+ }
+ else
+ {
+ cout << tmpNode2->iValue << " ";
+ }
+ }
+ cout << endl;
+ }
+ }
+//============================================================================
+// CTZDocument::GetCommaSeperatedString
+// Creates a comma seperated string from a string vector
+//============================================================================
+string CTZDocument::GetCommaSeparatedString(vector<string>& aStringVector)
+ {
+ string tmpString;
+ int size = aStringVector.size();
+ for (int j = 0; j < size;j++)
+ {
+ tmpString.append(aStringVector[j]);
+ if (j < size-1)
+ {
+ tmpString.append(",");
+ }
+ }
+ return tmpString;
+ }
+//============================================================================
+// CTZDocument::DisplayRegionsTable
+// Prints out the regions table to console
+//============================================================================
+void CTZDocument::DisplayRegionsTable() const
+ {
+ int size = iRegionsTable->Regions().size();
+ for (int j = 0; j < size;j++)
+ {
+ cout << "Region " << j << ": " << iRegionsTable->Regions()[j]->iRegionNameRef->iString << endl;
+ }
+ }
+
+//============================================================================
+// CTZDocument::DisplayTimeAlignmentTable
+// Prints out the Time Alignment table to console
+//============================================================================
+void CTZDocument::DisplayTimeAlignmentTable() const
+ {
+ int size = iStdTimeAlignmentTable->TimeAlignments().size();
+ for (int j = 0; j < size;j++)
+ {
+ cout << "RuleSets " << j << ": " << iStdTimeAlignmentTable->TimeAlignments()[j]->iOffsetToTimeZoneFormatName->iString << endl;
+ }
+ }
+//============================================================================
+// CTZDocument::DisplayZonesTable
+// Prints out the zones table to console
+//============================================================================
+void CTZDocument::DisplayZonesTable() const
+ {
+ int size = iZonesTable->Zones().size();
+ for (int j = 0; j < size; j++)
+ {
+ cout << "Region " << ": " << iZonesTable->Zones()[j]->iRegionNameRef->iString;
+ cout << "\tZone: " << iZonesTable->Zones()[j]->iZoneNameRef->iString << endl;
+ }
+ }
+//============================================================================
+// CTZDocument::DisplayRuleSetTable
+// Prints out the ruleset table to console
+//============================================================================
+void CTZDocument::DisplayRuleSetTable() const
+ {
+ int size = iRuleSetTable->RuleSets().size();
+ for (int j = 0; j < size;j++)
+ {
+ cout << "RuleSet " << iRuleSetTable->RuleSets()[j]->Name() << ": " << iRuleSetTable->RuleSets()[j]->RuleUses().size() << " rules\tRef:\t" << iRuleSetTable->RuleSets()[j]->ReferenceCount()<< endl;
+ int size2 = iRuleSetTable->RuleSets()[j]->RuleUses().size();
+ for (int k = 0; k < size2;k++)
+ {
+ cout << "RuleUse:\tFrom: " << iRuleUseTable->RuleUses()[k]->iPersistedEntity.iFromYear;
+ cout << "\tTo: " << iRuleUseTable->RuleUses()[k]->iPersistedEntity.iFromYear << endl;
+ }
+ }
+ }
+//============================================================================
+// CTZDocument::DisplayRuleDefinitionTable
+// Prints out the rule definition table to console
+//============================================================================
+void CTZDocument::DisplayRuleDefinitionTable() const
+ {
+ int size = iRuleDefinitionTable->RuleDefinitions().size();
+ cout << size << " RULES DEFINED" << endl;
+ for (int z = 0; z < size; z++)
+ {
+ TTzRuleDefinition tmpDef = iRuleDefinitionTable->RuleDefinitions()[z]->iPersistedEntity;
+ cout << "Rule Definition: Saving: ";
+ cout << (int)(tmpDef.iStdTimeOffset);
+ cout << "\tTime: " << (int)(tmpDef.iTimeOfChange) << endl;
+ }
+ }
+//============================================================================
+// CTZDocument::DisplayStringTable
+// Prints out the string table to console
+//============================================================================
+void CTZDocument::DisplayStringTable() const
+ {
+ int size = iStringTable->Strings().size();
+ for (int x = 0; x < size;x++)
+ {
+ cout << iStringTable->Strings()[x]->iString << endl;
+ }
+ }
+//============================================================================
+// CTZDocument::AssignZoneIds
+// After all the zones have been assembled, we sort them alphabetically
+// then assign each zone an id. The id will be read from the configuration
+// file if the zone already exists. If this is a new zone, then the zone id
+// will be equal to the next available zone id from the configuration file,
+// and the next available zone id will be incremented.
+//============================================================================
+void CTZDocument::AssignZoneIds()
+ {
+ const int KMaxTzId = 0x3FFF; //Maximum numeric id that can be assigned to a zone
+ sort(iZonesTable->Zones().begin(),iZonesTable->Zones().end(),CTzCpZone::SZoneFullNameSort());
+ string fullZoneName;
+ int size = iZonesTable->Zones().size();
+ for (int i = 0; i < size;++i)
+ {
+ fullZoneName = iZonesTable->Zones()[i]->iRegionNameRef->iString;
+ if (fullZoneName.length() > 0)
+ {
+ fullZoneName += '/';
+ }
+ fullZoneName += iZonesTable->Zones()[i]->iZoneNameRef->iString;
+ int id = GetPrivateProfileInt("ZoneIdentities",fullZoneName.c_str(), KMaxTUint16, TzGlobals::iZoneIdIniFilePath.c_str());
+ if (id != KMaxTUint16)
+ {
+ iZonesTable->Zones()[i]->iLocationId = id;
+ }
+ else
+ {
+ iZonesTable->Zones()[i]->iLocationId = TzGlobals::iNextNumericZoneId;
+
+ if(TzGlobals::iNextNumericZoneId < KMaxTzId)
+ {
+ TzGlobals::iNextNumericZoneId += 8;
+ }
+ else
+ {
+ cout << "ERROR: All available numeric ids have been used" << endl;
+ throw TzGlobals::ETzAbortCreateDatabaseFile;
+ }
+ }
+ }
+ }
+
+//============================================================================
+// CTZDocument::VerifyZoneIds
+// Checks that each zone id from TzIdentities.ini is present in the compiled
+// database. If a zone is missing, a warning message is displayed. It is not
+// an error for a zone to not be included in the database. Possible causes
+// include a change in zone name in the Olsen data sources, or compilation
+// of a custom database using a limited region set.
+//============================================================================
+void CTZDocument::VerifyZoneIds()
+ {
+ //Get the filesize of TzIdentities.ini
+ struct stat results;
+ int iniFileSizeBytes;
+ if (stat(TzGlobals::iZoneIdIniFilePath.c_str(), &results) == 0)
+ {
+ iniFileSizeBytes = results.st_size;
+ }
+ else
+ {
+ //It is very unlikely that the above call will fail, as we have already processed
+ //the TzIdentities.ini file by this point
+ cout << "WARNING: Could not retrieve TzIdentities.ini file size. Missing zone warnings will NOT be generated" << endl;
+ return;
+ }
+
+ //Create a char[] the same size as TzIdentities.ini to store the zone names
+ char* zoneBuffer = NULL;
+ zoneBuffer = new char[iniFileSizeBytes];
+ for (int i=0; i<iniFileSizeBytes; i++)
+ {
+ zoneBuffer[i] = 0; // Initialize all elements to zero.
+ }
+
+ //Retrieve all the zone names from TzIdentities.ini
+ GetPrivateProfileString("ZoneIdentities",0,"",zoneBuffer,iniFileSizeBytes,TzGlobals::iZoneIdIniFilePath.c_str());
+
+ //zoneBuffer now contains all the zone names, seperated by null char
+ //Split zoneBuffer into seperate zone names
+ string tmpString;
+ int numZones = iZonesTable->Zones().size();
+ int slashChar;
+ string regStr;
+ string zoneStr;
+
+ for (int x = 0; x < iniFileSizeBytes; ++x)
+ {
+ if (zoneBuffer[x] != 0)
+ {
+ tmpString += zoneBuffer[x];
+ }
+ else
+ {
+ //tmpString contains a full zone name. See if it is in the database
+
+ slashChar = tmpString.find('/',0);
+ //Split into Region and Zone
+ if (slashChar > 0)
+ {
+ regStr = tmpString.substr(0,slashChar);
+ zoneStr = tmpString.substr(slashChar+1);
+ }
+ else
+ {
+ regStr = "";
+ zoneStr = tmpString;
+ }
+
+ CTzCpString& regionName = iStringTable->AddString(regStr);
+ CTzCpString& zoneName = iStringTable->AddString(zoneStr);
+
+ if (iZonesTable->GetZone(zoneName,regionName,false) == NULL)
+ {
+ cout << "WARNING: Zone " << tmpString.c_str() << " not included in dataset" << endl;
+ }
+
+ tmpString.erase();
+
+ //The last key is followed by 2 null chars.
+ //If we find this we reached the last zone and can stop the search
+ if (zoneBuffer[x+1] == 0)
+ {
+ break;
+ }
+ }
+ }
+
+ delete [] zoneBuffer; // Free memory zoneBuffer char[]
+ zoneBuffer = NULL;
+ }
+
+//============================================================================
+// CTzDocument::CopyDatabaseFileToOutputDirectory
+// Copies the created database file to the location specified in the
+// configuration file. If there is no location specified, does nothing
+//============================================================================
+void CTZDocument::CopyDatabaseFileToOutputDirectory() const
+ {
+ char outputDir[KMaxPathLength];
+ GetPrivateProfileString("TzCompilerConfiguration","OutputDirectory","",outputDir,KMaxPathLength,TzGlobals::iIniFilePath.c_str());
+
+ if (strcmpi("",outputDir))
+ {
+ //Check the output directory exists - make it if necessary
+ string mkdir = "mkdir ";
+ mkdir += outputDir;
+ system(mkdir.c_str());
+
+ string copyString;
+
+ copyString = "copy ";
+ copyString += TzGlobals::iOutputFilePath;
+ copyString += " ";
+ copyString += outputDir;
+
+ cout << copyString.c_str() << endl;
+ system(copyString.c_str());
+
+ }
+ }
+//============================================================================
+// CTZDocument::ReadConfigurationFile
+// Sets global variables from the configuration file.
+//============================================================================
+void CTZDocument::ReadConfigurationFile()
+ {
+ //Read the ini file to set up default parameters
+ char buffer[KMaxPathLength];
+ getcwd(buffer,KMaxPathLength);
+
+ cout.fill('.');
+ cout << setiosflags(ios::left);
+ std::string dataPath(buffer);
+ TzGlobals::iZoneIdIniFilePath = dataPath + "\\TZIdentities.ini";
+
+ dataPath += "\\Data";
+
+ char includeRegions[KMaxFiles];
+ char inputDir[KMaxPathLength];
+ char excludedFiles[KMaxFiles];
+
+
+ TzGlobals::iStartYear = GetPrivateProfileInt("TZCompilerConfiguration","EarliestDateOfInterest",KDefaultStartYear,TzGlobals::iIniFilePath.c_str());
+ if (TzGlobals::iStartYear < KMinStartYear || TzGlobals::iStartYear > KMaxStartYear)
+ {
+ TzGlobals::iStartYear = KDefaultStartYear; //invalid year was provided, set it to default value
+ }
+ int len = GetPrivateProfileString("TZCompilerConfiguration","DefaultZone","Not Set",TzGlobals::iDefaultZoneName,KMaxZoneNameLength,TzGlobals::iIniFilePath.c_str());
+ if (0 == len) //no DefaultZone was provided, set it to "Not Set"
+ {
+ strcpy(TzGlobals::iDefaultZoneName, "Not Set");
+ }
+ len = GetPrivateProfileString("TZCompilerConfiguration","IncludedRegions","All",includeRegions,KMaxFiles,TzGlobals::iIniFilePath.c_str());
+ if (0 == len) //no includeRegions was provided, set it to "All" - default value
+ {
+ strcpy(includeRegions, "All");
+ }
+ TzGlobals::iNextNumericZoneId = GetPrivateProfileInt("NextNumericZoneId","NextNumericZoneId",KFirstZoneNumericId,TzGlobals::iZoneIdIniFilePath.c_str());
+ GetPrivateProfileString("TzCompilerConfiguration","InputDirectory","",inputDir,KMaxPathLength,TzGlobals::iIniFilePath.c_str());
+ GetPrivateProfileString("Files","ExcludedFiles","",excludedFiles,KMaxFiles,TzGlobals::iIniFilePath.c_str());
+
+ //Set files to exclude
+ char* token;
+ token = strtok(excludedFiles,",");
+
+ while (token != 0)
+ {
+ TzGlobals::iExcludedFiles.push_back(token);
+ token = strtok(NULL,",");
+ }
+
+ if (strcmp(includeRegions, "All") != 0) //do not include all the regions
+ {
+ TzGlobals::iIncludeAllRegions = false;
+ token = strtok(includeRegions,",");
+
+ while (token != 0)
+ {
+ TzGlobals::iIncludedRegions.push_back(token);
+ token = strtok(NULL,",");
+ }
+ }
+
+ TzGlobals::iInputFilePath = inputDir;
+
+ if (TzGlobals::iInputFilePath.empty())
+ {
+ //Use current directory
+ TzGlobals::iInputFilePath += dataPath;
+ }
+
+ // Add a trailing backslash if it doesn't have one
+ int pathsize = TzGlobals::iInputFilePath.size();
+ if ((TzGlobals::iInputFilePath).find_last_of("\\") < pathsize-1)
+ {
+ TzGlobals::iInputFilePath.append("\\");
+ }
+
+ TzGlobals::iOutputFilePath = buffer;
+ TzGlobals::iOutputFilePath += "\\tzdb.dbz";
+
+ // region mask is not used at the moment
+ TzGlobals::iRegionMask = 0;
+
+ CTzCpHelpers::PrintStep("Using settings from ");
+ cout << TzGlobals::iIniFilePath.c_str() << endl;
+ CTzCpHelpers::PrintStep("Data directory is ");
+ cout << TzGlobals::iInputFilePath.c_str() << endl;
+ CTzCpHelpers::PrintStep("Start Year:");
+ cout << TzGlobals::iStartYear << endl;
+ }
+//============================================================================
+// CTZDocument::WriteConfigurationFile
+// Update the configuration file to reflect the new next available id
+// and display the time zone identity list
+//============================================================================
+void CTZDocument::WriteConfigurationFile()
+ {
+ //Update the next available numeric zone id
+ char tmp[256] = "";
+ sprintf(tmp,"%d",TzGlobals::iNextNumericZoneId);
+ WritePrivateProfileString("NextNumericZoneId","NextNumericZoneId",tmp,TzGlobals::iZoneIdIniFilePath.c_str());
+ WritePrivateProfileString("Regions","AvailableRegions",GetCommaSeparatedString(TzGlobals::iAvailableRegions).c_str(),TzGlobals::iIniFilePath.c_str());
+ WritePrivateProfileString("Regions","ExcludedRegions",GetCommaSeparatedString(TzGlobals::iExcludedRegions).c_str(),TzGlobals::iIniFilePath.c_str());
+ WritePrivateProfileString("Files","AvailableFiles",GetCommaSeparatedString(TzGlobals::iAvailableFiles).c_str(),TzGlobals::iIniFilePath.c_str());
+ // it is assumed that zones have been sorted by location ID before calling this
+ int numZones = iZonesTable->Zones().size();
+ string zoneString;
+ for (int i = 0; i < numZones; i++)
+ {
+ char id[256] = "";
+ sprintf(id,"%d",iZonesTable->Zones()[i]->iLocationId);
+ zoneString = iZonesTable->Zones()[i]->iRegionNameRef->iString;
+ if (zoneString.length() > 0)
+ {
+ zoneString += '/';
+ }
+ zoneString += iZonesTable->Zones()[i]->iZoneNameRef->iString;
+ WritePrivateProfileString("ZoneIdentities",zoneString.c_str(),id,TzGlobals::iZoneIdIniFilePath.c_str());
+ }
+ }
+
+//============================================================================
+// CTZDocument::DisplayData
+// Display the data that have been parsed. Very useful for diagnostic purposes.
+//============================================================================
+void CTZDocument::DisplayData() const
+ {
+ //Have a look whats going on
+ DisplayNodeList();
+ DisplayRuleDefinitionTable();
+ DisplayRuleSetTable();
+ DisplayStringTable();
+ DisplayZonesTable();
+ DisplayTimeAlignmentTable();
+ }
+
+//============================================================================
+// End of file
+//============================================================================