// CalendarTimezone.cpp - CalendarTimezone class functions
//
// (c) 2016-2017 Xestia Software Development.
//
// This file is part of Xestia Calendar.
//
// Xestia Calendar is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by the
// Free Software Foundation, version 3 of the license.
//
// Xestia Calendar is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License along
// with Xestia Calendar. If not, see
#include "CalendarTimezone.h"
using namespace std;
CalendarObjectValidResult CalendarTimezoneObject::ValidObject(){
bool validBegin = false;
bool validEnd = false;
bool validTimeZoneID = false;
int seekCount = 0;
string propertyName;
// Look for BEGIN:VEVENT.
for (vector::iterator iter = objectName.begin();
iter != objectName.end(); iter++){
if (objectName[seekCount] == "BEGIN" &&
objectData[seekCount] == "VTIMEZONE"){
if (validBegin == false){
validBegin = true;
} else {
return CALENDAROBJECTVALID_INVALIDFORMAT;
}
}
if (objectName[seekCount] == "END" &&
objectData[seekCount] == "VTIMEZONE" &&
validBegin == false){
return CALENDAROBJECTVALID_INVALIDFORMAT;
}
seekCount++;
}
seekCount = 0;
// Look for TZID.
for (vector::iterator iter = objectName.begin();
iter != objectName.end(); iter++){
try{
propertyName = objectName[seekCount].substr(0,4);
}
catch(const out_of_range& oor){
continue;
}
if (propertyName == "TZID"){
if (validTimeZoneID == false){
validTimeZoneID = true;
} else {
return CALENDAROBJECTVALID_INVALIDFORMAT;
}
}
seekCount++;
}
seekCount = 0;
// Look for END:VEVENT.
for (vector::iterator iter = objectName.begin();
iter != objectName.end(); iter++){
if (objectName[seekCount] == "END" &&
objectData[seekCount] == "VTIMEZONE"){
if (validEnd == false){
validEnd = true;
} else {
return CALENDAROBJECTVALID_INVALIDFORMAT;
}
}
seekCount++;
}
// Check if the VEVENT is valid.
if (validBegin == true &&
validEnd == true &&
validTimeZoneID == true){
return CALENDAROBJECTVALID_OK;
} else {
return CALENDAROBJECTVALID_INVALIDFORMAT;
}
}
void CalendarTimezoneObject::ProcessData(){
// Process the data.
multimap dataReceived;
map propertyData;
string *propertyNameData = nullptr;
int objectSeekCount = 0;
// Process the data from TZID.
dataReceived = ProcessTextVectors(&objectName, &objectData, false, "TZID");
if (dataReceived.begin() != dataReceived.end()){
try {
timeZoneDataTokens = dataReceived.begin()->first.substr(5);
}
catch(const out_of_range &oor){
// Do nothing as there is no data.
}
timeZoneData = dataReceived.begin()->second;
}
// Process the data from LAST-MODIFIED.
dataReceived = ProcessTextVectors(&objectName, &objectData, false, "LAST-MODIFIED");
if (dataReceived.begin() != dataReceived.end()){
try {
lastModifiedTokens = dataReceived.begin()->first.substr(14);
}
catch(const out_of_range &oor){
// Do nothing as there is no data.
}
lastModifiedData = dataReceived.begin()->second;
}
// Process the data from TZURL.
dataReceived = ProcessTextVectors(&objectName, &objectData, false, "TZURL");
if (dataReceived.begin() != dataReceived.end()){
try {
timeZoneURLTokens = dataReceived.begin()->first.substr(6);
}
catch(const out_of_range &oor){
// Do nothing as there is no data.
}
timeZoneURLData = dataReceived.begin()->second;
}
// Process data from each STANDARD and DAYLIGHT.
ProcessStandardDaylight();
int seekCount = 0;
for (vector>::iterator tzsiter = timezoneStandardName.begin();
tzsiter != timezoneStandardName.end(); tzsiter++){
bool dateTimeStartFound = false;
bool timeZoneOffsetToFound = false;
bool timeZoneOffsetFromFound = false;
TimezoneDataStruct newTZData;
// Process the data from DTSTART.
dataReceived = ProcessTextVectors(&timezoneStandardName[seekCount],
&timezoneStandardData[seekCount], false, "DTSTART");
if (dataReceived.begin() != dataReceived.end()){
try {
newTZData.dateTimeStartTokens = dataReceived.begin()->first.substr(8);
}
catch(const out_of_range &oor){
// Do nothing as there is no data.
}
newTZData.dateTimeStartData = dataReceived.begin()->second;
dateTimeStartFound = true;
}
// Process the data from TZOFFSETFROM.
dataReceived = ProcessTextVectors(&timezoneStandardName[seekCount],
&timezoneStandardData[seekCount], false, "TZOFFSETFROM");
if (dataReceived.begin() != dataReceived.end()){
try {
newTZData.timeZoneOffsetFromTokens = dataReceived.begin()->first.substr(13);
}
catch(const out_of_range &oor){
// Do nothing as there is no data.
}
newTZData.timeZoneOffsetFromData = dataReceived.begin()->second;
timeZoneOffsetFromFound = true;
}
// Process the data from TZOFFSETTO.
dataReceived = ProcessTextVectors(&timezoneStandardName[seekCount],
&timezoneStandardData[seekCount], false, "TZOFFSETTO");
if (dataReceived.begin() != dataReceived.end()){
try {
newTZData.timeZoneOffsetToTokens = dataReceived.begin()->first.substr(11);
}
catch(const out_of_range &oor){
// Do nothing as there is no data.
}
newTZData.timeZoneOffsetToData = dataReceived.begin()->second;
timeZoneOffsetToFound = true;
}
// Process the data from RRULE.
dataReceived = ProcessTextVectors(&timezoneStandardName[seekCount],
&timezoneStandardData[seekCount], false, "RRULE");
if (dataReceived.begin() != dataReceived.end()){
try {
newTZData.recurranceRuleDataTokens = dataReceived.begin()->first.substr(6);
}
catch(const out_of_range &oor){
// Do nothing as there is no data.
}
newTZData.recurranceRuleData = dataReceived.begin()->second;
}
// Process the data from COMMENT.
dataReceived = ProcessTextVectors(&timezoneStandardName[seekCount],
&timezoneStandardData[seekCount], true, "COMMENT");
objectSeekCount = 0;
for(multimap::iterator propiter = dataReceived.begin();
propiter != dataReceived.end();
++propiter){
newTZData.commentListTokens.push_back("");
newTZData.commentListAltRep.push_back("");
newTZData.commentListLanguage.push_back("");
newTZData.commentList.push_back("");
bool TokenData = false;
string propertyTokens;
propertyNameData = (string*)&propiter->first;
propertyData = SplitValues(*propertyNameData);
for(map::iterator propdataiter = propertyData.begin();
propdataiter != propertyData.end(); propdataiter++){
if (propdataiter->first == "ALTREP"){
newTZData.commentListAltRep[objectSeekCount] = propdataiter->second;
} else if (propdataiter->first == "LANGUAGE"){
newTZData.commentListLanguage[objectSeekCount] = propdataiter->second;
} else {
if (TokenData == false){
TokenData = true;
} else {
propertyTokens += ";";
}
propertyTokens += propdataiter->first;
propertyTokens += "=";
propertyTokens += propdataiter->second;
}
}
if (propertyTokens.size() > 0){
newTZData.commentListTokens[objectSeekCount] = propertyTokens;
}
newTZData.commentList[objectSeekCount] = propiter->second;
objectSeekCount++;
}
// Process the data from RDATE.
dataReceived = ProcessTextVectors(&timezoneStandardName[seekCount],
&timezoneStandardData[seekCount], true, "RDATE");
objectSeekCount = 0;
for(multimap::iterator propiter = dataReceived.begin();
propiter != dataReceived.end();
++propiter){
newTZData.recurranceDateDataTokens.push_back("");
newTZData.recurranceDateDataValue.push_back("");
newTZData.recurranceDateDataTimeZoneParam.push_back("");
newTZData.recurranceDateData.push_back("");
bool TokenData = false;
string propertyTokens;
propertyNameData = (string*)&propiter->first;
propertyData = SplitValues(*propertyNameData);
for(map::iterator dataiter = propertyData.begin();
dataiter != propertyData.end(); dataiter++){
if (dataiter->first == "VALUE"){
newTZData.recurranceDateDataValue[objectSeekCount] = dataiter->second;
} else if (dataiter->first == "TZID"){
newTZData.recurranceDateDataTimeZoneParam[objectSeekCount] = dataiter->second;
} else {
if (TokenData == false){
TokenData = true;
} else {
propertyTokens += ";";
}
propertyTokens += dataiter->first;
propertyTokens += "=";
propertyTokens += dataiter->second;
}
}
if (propertyTokens.size() > 0){
newTZData.recurranceDateDataTokens[objectSeekCount] = propertyTokens;
}
newTZData.recurranceDateData[objectSeekCount] = propiter->second;
objectSeekCount++;
}
// Process the data from TZNAME.
dataReceived = ProcessTextVectors(&timezoneStandardName[seekCount],
&timezoneStandardData[seekCount], true, "TZNAME");
objectSeekCount = 0;
for(multimap::iterator propiter = dataReceived.begin();
propiter != dataReceived.end();
++propiter){
newTZData.timeZoneNameTokens.push_back("");
newTZData.timeZoneNameLanguage.push_back("");
newTZData.timeZoneNameData.push_back("");
bool TokenData = false;
string propertyTokens;
propertyNameData = (string*)&propiter->first;
propertyData = SplitValues(*propertyNameData);
for(map::iterator dataiter = propertyData.begin();
dataiter != propertyData.end(); dataiter++){
if (dataiter->first == "LANGUAGE"){
newTZData.timeZoneNameLanguage[objectSeekCount] = dataiter->second;
} else {
if (TokenData == false){
TokenData = true;
} else {
propertyTokens += ";";
}
propertyTokens += dataiter->first;
propertyTokens += "=";
propertyTokens += dataiter->second;
}
}
if (propertyTokens.size() > 0){
newTZData.timeZoneNameTokens[objectSeekCount] = propertyTokens;
}
newTZData.timeZoneNameData[objectSeekCount] = propiter->second;
objectSeekCount++;
}
objectSeekCount = 0;
// Process data from X-*
for(vector::iterator propiter = timezoneStandardName[seekCount].begin();
propiter != timezoneStandardName[seekCount].end(); ++propiter){
if (propiter->substr(0,2) == "X-" &&
propiter->size() > 2){
newTZData.xTokensData.push_back(timezoneStandardData[seekCount][objectSeekCount]);
newTZData.xTokensDataTokens.push_back(timezoneStandardName[seekCount][objectSeekCount]);
}
objectSeekCount++;
}
// Check if the required values were given and
// insert newTZData into the vector list of
// standard timezones.
if (dateTimeStartFound == true &&
timeZoneOffsetToFound == true &&
timeZoneOffsetFromFound == true){
timezoneStandardCollection.push_back(newTZData);
}
seekCount++;
}
seekCount = 0;
for (vector>::iterator tzsiter = timezoneDaylightName.begin();
tzsiter != timezoneDaylightName.end(); tzsiter++){
bool dateTimeStartFound = false;
bool timeZoneOffsetToFound = false;
bool timeZoneOffsetFromFound = false;
TimezoneDataStruct newTZData;
// Process the data from DTSTART.
dataReceived = ProcessTextVectors(&timezoneDaylightName[seekCount],
&timezoneDaylightData[seekCount], false, "DTSTART");
if (dataReceived.begin() != dataReceived.end()){
try {
newTZData.dateTimeStartTokens = dataReceived.begin()->first.substr(8);
}
catch(const out_of_range &oor){
// Do nothing as there is no data.
}
newTZData.dateTimeStartData = dataReceived.begin()->second;
dateTimeStartFound = true;
}
// Process the data from TZOFFSETFROM.
dataReceived = ProcessTextVectors(&timezoneDaylightName[seekCount],
&timezoneDaylightData[seekCount], false, "TZOFFSETFROM");
if (dataReceived.begin() != dataReceived.end()){
try {
newTZData.timeZoneOffsetFromTokens = dataReceived.begin()->first.substr(13);
}
catch(const out_of_range &oor){
// Do nothing as there is no data.
}
newTZData.timeZoneOffsetFromData = dataReceived.begin()->second;
timeZoneOffsetFromFound = true;
}
// Process the data from TZOFFSETTO.
dataReceived = ProcessTextVectors(&timezoneDaylightName[seekCount],
&timezoneDaylightData[seekCount], false, "TZOFFSETTO");
if (dataReceived.begin() != dataReceived.end()){
try {
newTZData.timeZoneOffsetToTokens = dataReceived.begin()->first.substr(11);
}
catch(const out_of_range &oor){
// Do nothing as there is no data.
}
newTZData.timeZoneOffsetToData = dataReceived.begin()->second;
timeZoneOffsetToFound = true;
}
// Process the data from RRULE.
dataReceived = ProcessTextVectors(&timezoneDaylightName[seekCount],
&timezoneDaylightData[seekCount], false, "RRULE");
if (dataReceived.begin() != dataReceived.end()){
try {
newTZData.recurranceRuleDataTokens = dataReceived.begin()->first.substr(6);
}
catch(const out_of_range &oor){
// Do nothing as there is no data.
}
newTZData.recurranceRuleData = dataReceived.begin()->second;
}
// Process the data from COMMENT.
dataReceived = ProcessTextVectors(&timezoneDaylightName[seekCount],
&timezoneDaylightData[seekCount], true, "COMMENT");
objectSeekCount = 0;
for(multimap::iterator propiter = dataReceived.begin();
propiter != dataReceived.end();
++propiter){
newTZData.commentListTokens.push_back("");
newTZData.commentListAltRep.push_back("");
newTZData.commentListLanguage.push_back("");
newTZData.commentList.push_back("");
bool TokenData = false;
string propertyTokens;
propertyNameData = (string*)&propiter->first;
propertyData = SplitValues(*propertyNameData);
for(map::iterator propdataiter = propertyData.begin();
propdataiter != propertyData.end(); propdataiter++){
if (propdataiter->first == "ALTREP"){
newTZData.commentListAltRep[objectSeekCount] = propdataiter->second;
} else if (propdataiter->first == "LANGUAGE"){
newTZData.commentListLanguage[objectSeekCount] = propdataiter->second;
} else {
if (TokenData == false){
TokenData = true;
} else {
propertyTokens += ";";
}
propertyTokens += propdataiter->first;
propertyTokens += "=";
propertyTokens += propdataiter->second;
}
}
if (propertyTokens.size() > 0){
newTZData.commentListTokens[objectSeekCount] = propertyTokens;
}
newTZData.commentList[objectSeekCount] = propiter->second;
objectSeekCount++;
}
// Process the data from RDATE.
dataReceived = ProcessTextVectors(&timezoneDaylightName[seekCount],
&timezoneDaylightData[seekCount], true, "RDATE");
objectSeekCount = 0;
for(multimap::iterator propiter = dataReceived.begin();
propiter != dataReceived.end();
++propiter){
newTZData.recurranceDateDataTokens.push_back("");
newTZData.recurranceDateDataValue.push_back("");
newTZData.recurranceDateDataTimeZoneParam.push_back("");
newTZData.recurranceDateData.push_back("");
bool TokenData = false;
string propertyTokens;
propertyNameData = (string*)&propiter->first;
propertyData = SplitValues(*propertyNameData);
for(map::iterator dataiter = propertyData.begin();
dataiter != propertyData.end(); dataiter++){
if (dataiter->first == "VALUE"){
newTZData.recurranceDateDataValue[objectSeekCount] = dataiter->second;
} else if (dataiter->first == "TZID"){
newTZData.recurranceDateDataTimeZoneParam[objectSeekCount] = dataiter->second;
} else {
if (TokenData == false){
TokenData = true;
} else {
propertyTokens += ";";
}
propertyTokens += dataiter->first;
propertyTokens += "=";
propertyTokens += dataiter->second;
}
}
if (propertyTokens.size() > 0){
newTZData.recurranceDateDataTokens[objectSeekCount] = propertyTokens;
}
newTZData.recurranceDateData[objectSeekCount] = propiter->second;
objectSeekCount++;
}
// Process the data from TZNAME.
dataReceived = ProcessTextVectors(&timezoneDaylightName[seekCount],
&timezoneDaylightData[seekCount], true, "TZNAME");
objectSeekCount = 0;
for(multimap::iterator propiter = dataReceived.begin();
propiter != dataReceived.end();
++propiter){
newTZData.timeZoneNameTokens.push_back("");
newTZData.timeZoneNameLanguage.push_back("");
newTZData.timeZoneNameData.push_back("");
bool TokenData = false;
string propertyTokens;
propertyNameData = (string*)&propiter->first;
propertyData = SplitValues(*propertyNameData);
for(map::iterator dataiter = propertyData.begin();
dataiter != propertyData.end(); dataiter++){
if (dataiter->first == "LANGUAGE"){
newTZData.timeZoneNameLanguage[objectSeekCount] = dataiter->second;
} else {
if (TokenData == false){
TokenData = true;
} else {
propertyTokens += ";";
}
propertyTokens += dataiter->first;
propertyTokens += "=";
propertyTokens += dataiter->second;
}
}
if (propertyTokens.size() > 0){
newTZData.timeZoneNameTokens[objectSeekCount] = propertyTokens;
}
newTZData.timeZoneNameData[objectSeekCount] = propiter->second;
objectSeekCount++;
}
objectSeekCount = 0;
// Process data from X-*
for(vector::iterator propiter = timezoneDaylightName[seekCount].begin();
propiter != timezoneDaylightName[seekCount].end(); ++propiter){
if (propiter->substr(0,2) == "X-" &&
propiter->size() > 2){
newTZData.xTokensData.push_back(timezoneDaylightData[seekCount][objectSeekCount]);
newTZData.xTokensDataTokens.push_back(timezoneDaylightName[seekCount][objectSeekCount]);
}
objectSeekCount++;
}
// Check if the required values were given and
// insert newTZData into the vector list of
// daylight timezones.
if (dateTimeStartFound == true &&
timeZoneOffsetToFound == true &&
timeZoneOffsetFromFound == true){
timezoneDaylightCollection.push_back(newTZData);
}
seekCount++;
}
}
void CalendarTimezoneObject::ProcessStandardDaylight(){
int seekCount = 0;
bool TZMode = false; // False = STANDARD, True = DAYLIGHT.
bool validBegin = false;
vector timezoneObjectName;
vector timezoneObjectData;
for (vector::iterator iter = objectName.begin();
iter != objectName.end(); iter++){
// Check if the current name is BEGIN and
// data is either STANDARD or DAYLIGHT.
if (objectName[seekCount] == "BEGIN" &&
(objectData[seekCount] == "STANDARD" ||
objectData[seekCount] == "DAYLIGHT")){
if (validBegin == false){
validBegin = true;
} else {
}
if (objectData[seekCount] == "STANDARD"){
TZMode = false;
} else if (objectData[seekCount] == "DAYLIGHT") {
TZMode = true;
}
seekCount++;
continue;
}
// Check if current name is END and
// data is either STANDARD or DAYLIGHT.
if (objectName[seekCount] == "END" &&
(objectData[seekCount] == "STANDARD" ||
objectData[seekCount] == "DAYLIGHT") &&
validBegin == true){
if (TZMode == false && timezoneObjectName.size() > 0){
timezoneStandardName.push_back(timezoneObjectName);
timezoneStandardData.push_back(timezoneObjectData);
} else {
timezoneDaylightName.push_back(timezoneObjectName);
timezoneDaylightData.push_back(timezoneObjectData);
}
timezoneObjectName.clear();
timezoneObjectData.clear();
validBegin = false;
}
if (validBegin == true){
timezoneObjectName.push_back(objectName[seekCount]);
timezoneObjectData.push_back(objectData[seekCount]);
}
seekCount++;
}
}