1 // CalendarTimezone.cpp - CalendarTimezone class functions
3 // (c) 2016-2017 Xestia Software Development.
5 // This file is part of Xestia Calendar.
7 // Xestia Calendar is free software: you can redistribute it and/or modify
8 // it under the terms of the GNU General Public License as published by the
9 // Free Software Foundation, version 3 of the license.
11 // Xestia Calendar is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
16 // You should have received a copy of the GNU General Public License along
17 // with Xestia Calendar. If not, see <http://www.gnu.org/licenses/>
19 #include "CalendarTimezone.h"
23 CalendarObjectValidResult CalendarTimezoneObject::ValidObject(){
25 bool validBegin = false;
26 bool validEnd = false;
27 bool validTimeZoneID = false;
31 // Look for BEGIN:VEVENT.
33 for (vector<string>::iterator iter = objectName.begin();
34 iter != objectName.end(); iter++){
36 if (objectName[seekCount] == "BEGIN" &&
37 objectData[seekCount] == "VTIMEZONE"){
39 if (validBegin == false){
42 return CALENDAROBJECTVALID_INVALIDFORMAT;
47 if (objectName[seekCount] == "END" &&
48 objectData[seekCount] == "VTIMEZONE" &&
51 return CALENDAROBJECTVALID_INVALIDFORMAT;
63 for (vector<string>::iterator iter = objectName.begin();
64 iter != objectName.end(); iter++){
67 propertyName = objectName[seekCount].substr(0,4);
70 catch(const out_of_range& oor){
74 if (propertyName == "TZID"){
76 if (validTimeZoneID == false){
77 validTimeZoneID = true;
79 return CALENDAROBJECTVALID_INVALIDFORMAT;
90 // Look for END:VEVENT.
92 for (vector<string>::iterator iter = objectName.begin();
93 iter != objectName.end(); iter++){
95 if (objectName[seekCount] == "END" &&
96 objectData[seekCount] == "VTIMEZONE"){
98 if (validEnd == false){
101 return CALENDAROBJECTVALID_INVALIDFORMAT;
110 // Check if the VEVENT is valid.
112 if (validBegin == true &&
114 validTimeZoneID == true){
116 return CALENDAROBJECTVALID_OK;
120 return CALENDAROBJECTVALID_INVALIDFORMAT;
126 void CalendarTimezoneObject::ProcessData(){
130 multimap<string,string> dataReceived;
131 map<string,string> propertyData;
132 string *propertyNameData = nullptr;
133 int objectSeekCount = 0;
135 // Process the data from TZID.
137 dataReceived = ProcessTextVectors(&objectName, &objectData, false, "TZID");
139 if (dataReceived.begin() != dataReceived.end()){
142 timeZoneDataTokens = dataReceived.begin()->first.substr(5);
145 catch(const out_of_range &oor){
146 // Do nothing as there is no data.
149 timeZoneData = dataReceived.begin()->second;
153 // Process the data from LAST-MODIFIED.
155 dataReceived = ProcessTextVectors(&objectName, &objectData, false, "LAST-MODIFIED");
157 if (dataReceived.begin() != dataReceived.end()){
160 lastModifiedTokens = dataReceived.begin()->first.substr(14);
163 catch(const out_of_range &oor){
164 // Do nothing as there is no data.
167 lastModifiedData = dataReceived.begin()->second;
171 // Process the data from TZURL.
173 dataReceived = ProcessTextVectors(&objectName, &objectData, false, "TZURL");
175 if (dataReceived.begin() != dataReceived.end()){
178 timeZoneURLTokens = dataReceived.begin()->first.substr(6);
181 catch(const out_of_range &oor){
182 // Do nothing as there is no data.
185 timeZoneURLData = dataReceived.begin()->second;
189 // Process data from each STANDARD and DAYLIGHT.
191 ProcessStandardDaylight();
195 for (vector<vector<string>>::iterator tzsiter = timezoneStandardName.begin();
196 tzsiter != timezoneStandardName.end(); tzsiter++){
198 bool dateTimeStartFound = false;
199 bool timeZoneOffsetToFound = false;
200 bool timeZoneOffsetFromFound = false;
202 TimezoneDataStruct newTZData;
204 // Process the data from DTSTART.
206 dataReceived = ProcessTextVectors(&timezoneStandardName[seekCount],
207 &timezoneStandardData[seekCount], false, "DTSTART");
209 if (dataReceived.begin() != dataReceived.end()){
212 newTZData.dateTimeStartTokens = dataReceived.begin()->first.substr(8);
215 catch(const out_of_range &oor){
216 // Do nothing as there is no data.
219 newTZData.dateTimeStartData = dataReceived.begin()->second;
220 dateTimeStartFound = true;
224 // Process the data from TZOFFSETFROM.
226 dataReceived = ProcessTextVectors(&timezoneStandardName[seekCount],
227 &timezoneStandardData[seekCount], false, "TZOFFSETFROM");
229 if (dataReceived.begin() != dataReceived.end()){
232 newTZData.timeZoneOffsetFromTokens = dataReceived.begin()->first.substr(13);
235 catch(const out_of_range &oor){
236 // Do nothing as there is no data.
239 newTZData.timeZoneOffsetFromData = dataReceived.begin()->second;
240 timeZoneOffsetFromFound = true;
244 // Process the data from TZOFFSETTO.
246 dataReceived = ProcessTextVectors(&timezoneStandardName[seekCount],
247 &timezoneStandardData[seekCount], false, "TZOFFSETTO");
249 if (dataReceived.begin() != dataReceived.end()){
252 newTZData.timeZoneOffsetToTokens = dataReceived.begin()->first.substr(11);
255 catch(const out_of_range &oor){
256 // Do nothing as there is no data.
259 newTZData.timeZoneOffsetToData = dataReceived.begin()->second;
260 timeZoneOffsetToFound = true;
264 // Process the data from RRULE.
266 dataReceived = ProcessTextVectors(&timezoneStandardName[seekCount],
267 &timezoneStandardData[seekCount], false, "RRULE");
269 if (dataReceived.begin() != dataReceived.end()){
272 newTZData.recurranceRuleDataTokens = dataReceived.begin()->first.substr(6);
275 catch(const out_of_range &oor){
276 // Do nothing as there is no data.
279 newTZData.recurranceRuleData = dataReceived.begin()->second;
283 // Process the data from COMMENT.
285 dataReceived = ProcessTextVectors(&timezoneStandardName[seekCount],
286 &timezoneStandardData[seekCount], true, "COMMENT");
290 for(multimap<string,string>::iterator propiter = dataReceived.begin();
291 propiter != dataReceived.end();
294 newTZData.commentListTokens.push_back("");
295 newTZData.commentListAltRep.push_back("");
296 newTZData.commentListLanguage.push_back("");
297 newTZData.commentList.push_back("");
299 bool TokenData = false;
300 string propertyTokens;
302 propertyNameData = (string*)&propiter->first;
304 propertyData = SplitValues(*propertyNameData);
306 for(map<string,string>::iterator propdataiter = propertyData.begin();
307 propdataiter != propertyData.end(); propdataiter++){
309 if (propdataiter->first == "ALTREP"){
311 newTZData.commentListAltRep[objectSeekCount] = propdataiter->second;
313 } else if (propdataiter->first == "LANGUAGE"){
315 newTZData.commentListLanguage[objectSeekCount] = propdataiter->second;
319 if (TokenData == false){
322 propertyTokens += ";";
325 propertyTokens += propdataiter->first;
326 propertyTokens += "=";
327 propertyTokens += propdataiter->second;
333 if (propertyTokens.size() > 0){
334 newTZData.commentListTokens[objectSeekCount] = propertyTokens;
337 newTZData.commentList[objectSeekCount] = propiter->second;
343 // Process the data from RDATE.
345 dataReceived = ProcessTextVectors(&timezoneStandardName[seekCount],
346 &timezoneStandardData[seekCount], true, "RDATE");
350 for(multimap<string,string>::iterator propiter = dataReceived.begin();
351 propiter != dataReceived.end();
354 newTZData.recurranceDateDataTokens.push_back("");
355 newTZData.recurranceDateDataValue.push_back("");
356 newTZData.recurranceDateDataTimeZoneParam.push_back("");
357 newTZData.recurranceDateData.push_back("");
359 bool TokenData = false;
360 string propertyTokens;
362 propertyNameData = (string*)&propiter->first;
364 propertyData = SplitValues(*propertyNameData);
366 for(map<string,string>::iterator dataiter = propertyData.begin();
367 dataiter != propertyData.end(); dataiter++){
369 if (dataiter->first == "VALUE"){
371 newTZData.recurranceDateDataValue[objectSeekCount] = dataiter->second;
373 } else if (dataiter->first == "TZID"){
375 newTZData.recurranceDateDataTimeZoneParam[objectSeekCount] = dataiter->second;
379 if (TokenData == false){
382 propertyTokens += ";";
385 propertyTokens += dataiter->first;
386 propertyTokens += "=";
387 propertyTokens += dataiter->second;
393 if (propertyTokens.size() > 0){
394 newTZData.recurranceDateDataTokens[objectSeekCount] = propertyTokens;
397 newTZData.recurranceDateData[objectSeekCount] = propiter->second;
403 // Process the data from TZNAME.
405 dataReceived = ProcessTextVectors(&timezoneStandardName[seekCount],
406 &timezoneStandardData[seekCount], true, "TZNAME");
410 for(multimap<string,string>::iterator propiter = dataReceived.begin();
411 propiter != dataReceived.end();
414 newTZData.timeZoneNameTokens.push_back("");
415 newTZData.timeZoneNameLanguage.push_back("");
416 newTZData.timeZoneNameData.push_back("");
418 bool TokenData = false;
419 string propertyTokens;
421 propertyNameData = (string*)&propiter->first;
423 propertyData = SplitValues(*propertyNameData);
425 for(map<string,string>::iterator dataiter = propertyData.begin();
426 dataiter != propertyData.end(); dataiter++){
428 if (dataiter->first == "LANGUAGE"){
430 newTZData.timeZoneNameLanguage[objectSeekCount] = dataiter->second;
434 if (TokenData == false){
437 propertyTokens += ";";
440 propertyTokens += dataiter->first;
441 propertyTokens += "=";
442 propertyTokens += dataiter->second;
448 if (propertyTokens.size() > 0){
449 newTZData.timeZoneNameTokens[objectSeekCount] = propertyTokens;
452 newTZData.timeZoneNameData[objectSeekCount] = propiter->second;
460 // Process data from X-*
462 for(vector<string>::iterator propiter = timezoneStandardName[seekCount].begin();
463 propiter != timezoneStandardName[seekCount].end(); ++propiter){
465 if (propiter->substr(0,2) == "X-" &&
466 propiter->size() > 2){
468 newTZData.xTokensData.push_back(timezoneStandardData[seekCount][objectSeekCount]);
469 newTZData.xTokensDataTokens.push_back(timezoneStandardName[seekCount][objectSeekCount]);
477 // Check if the required values were given and
478 // insert newTZData into the vector list of
479 // standard timezones.
481 if (dateTimeStartFound == true &&
482 timeZoneOffsetToFound == true &&
483 timeZoneOffsetFromFound == true){
485 timezoneStandardCollection.push_back(newTZData);
495 for (vector<vector<string>>::iterator tzsiter = timezoneDaylightName.begin();
496 tzsiter != timezoneDaylightName.end(); tzsiter++){
498 bool dateTimeStartFound = false;
499 bool timeZoneOffsetToFound = false;
500 bool timeZoneOffsetFromFound = false;
502 TimezoneDataStruct newTZData;
504 // Process the data from DTSTART.
506 dataReceived = ProcessTextVectors(&timezoneDaylightName[seekCount],
507 &timezoneDaylightData[seekCount], false, "DTSTART");
509 if (dataReceived.begin() != dataReceived.end()){
512 newTZData.dateTimeStartTokens = dataReceived.begin()->first.substr(8);
515 catch(const out_of_range &oor){
516 // Do nothing as there is no data.
519 newTZData.dateTimeStartData = dataReceived.begin()->second;
520 dateTimeStartFound = true;
524 // Process the data from TZOFFSETFROM.
526 dataReceived = ProcessTextVectors(&timezoneDaylightName[seekCount],
527 &timezoneDaylightData[seekCount], false, "TZOFFSETFROM");
529 if (dataReceived.begin() != dataReceived.end()){
532 newTZData.timeZoneOffsetFromTokens = dataReceived.begin()->first.substr(13);
535 catch(const out_of_range &oor){
536 // Do nothing as there is no data.
539 newTZData.timeZoneOffsetFromData = dataReceived.begin()->second;
540 timeZoneOffsetFromFound = true;
544 // Process the data from TZOFFSETTO.
546 dataReceived = ProcessTextVectors(&timezoneDaylightName[seekCount],
547 &timezoneDaylightData[seekCount], false, "TZOFFSETTO");
549 if (dataReceived.begin() != dataReceived.end()){
552 newTZData.timeZoneOffsetToTokens = dataReceived.begin()->first.substr(11);
555 catch(const out_of_range &oor){
556 // Do nothing as there is no data.
559 newTZData.timeZoneOffsetToData = dataReceived.begin()->second;
560 timeZoneOffsetToFound = true;
564 // Process the data from RRULE.
566 dataReceived = ProcessTextVectors(&timezoneDaylightName[seekCount],
567 &timezoneDaylightData[seekCount], false, "RRULE");
569 if (dataReceived.begin() != dataReceived.end()){
572 newTZData.recurranceRuleDataTokens = dataReceived.begin()->first.substr(6);
575 catch(const out_of_range &oor){
576 // Do nothing as there is no data.
579 newTZData.recurranceRuleData = dataReceived.begin()->second;
583 // Process the data from COMMENT.
585 dataReceived = ProcessTextVectors(&timezoneDaylightName[seekCount],
586 &timezoneDaylightData[seekCount], true, "COMMENT");
590 for(multimap<string,string>::iterator propiter = dataReceived.begin();
591 propiter != dataReceived.end();
594 newTZData.commentListTokens.push_back("");
595 newTZData.commentListAltRep.push_back("");
596 newTZData.commentListLanguage.push_back("");
597 newTZData.commentList.push_back("");
599 bool TokenData = false;
600 string propertyTokens;
602 propertyNameData = (string*)&propiter->first;
604 propertyData = SplitValues(*propertyNameData);
606 for(map<string,string>::iterator propdataiter = propertyData.begin();
607 propdataiter != propertyData.end(); propdataiter++){
609 if (propdataiter->first == "ALTREP"){
611 newTZData.commentListAltRep[objectSeekCount] = propdataiter->second;
613 } else if (propdataiter->first == "LANGUAGE"){
615 newTZData.commentListLanguage[objectSeekCount] = propdataiter->second;
619 if (TokenData == false){
622 propertyTokens += ";";
625 propertyTokens += propdataiter->first;
626 propertyTokens += "=";
627 propertyTokens += propdataiter->second;
633 if (propertyTokens.size() > 0){
634 newTZData.commentListTokens[objectSeekCount] = propertyTokens;
637 newTZData.commentList[objectSeekCount] = propiter->second;
643 // Process the data from RDATE.
645 dataReceived = ProcessTextVectors(&timezoneDaylightName[seekCount],
646 &timezoneDaylightData[seekCount], true, "RDATE");
650 for(multimap<string,string>::iterator propiter = dataReceived.begin();
651 propiter != dataReceived.end();
654 newTZData.recurranceDateDataTokens.push_back("");
655 newTZData.recurranceDateDataValue.push_back("");
656 newTZData.recurranceDateDataTimeZoneParam.push_back("");
657 newTZData.recurranceDateData.push_back("");
659 bool TokenData = false;
660 string propertyTokens;
662 propertyNameData = (string*)&propiter->first;
664 propertyData = SplitValues(*propertyNameData);
666 for(map<string,string>::iterator dataiter = propertyData.begin();
667 dataiter != propertyData.end(); dataiter++){
669 if (dataiter->first == "VALUE"){
671 newTZData.recurranceDateDataValue[objectSeekCount] = dataiter->second;
673 } else if (dataiter->first == "TZID"){
675 newTZData.recurranceDateDataTimeZoneParam[objectSeekCount] = dataiter->second;
679 if (TokenData == false){
682 propertyTokens += ";";
685 propertyTokens += dataiter->first;
686 propertyTokens += "=";
687 propertyTokens += dataiter->second;
693 if (propertyTokens.size() > 0){
694 newTZData.recurranceDateDataTokens[objectSeekCount] = propertyTokens;
697 newTZData.recurranceDateData[objectSeekCount] = propiter->second;
703 // Process the data from TZNAME.
705 dataReceived = ProcessTextVectors(&timezoneDaylightName[seekCount],
706 &timezoneDaylightData[seekCount], true, "TZNAME");
710 for(multimap<string,string>::iterator propiter = dataReceived.begin();
711 propiter != dataReceived.end();
714 newTZData.timeZoneNameTokens.push_back("");
715 newTZData.timeZoneNameLanguage.push_back("");
716 newTZData.timeZoneNameData.push_back("");
718 bool TokenData = false;
719 string propertyTokens;
721 propertyNameData = (string*)&propiter->first;
723 propertyData = SplitValues(*propertyNameData);
725 for(map<string,string>::iterator dataiter = propertyData.begin();
726 dataiter != propertyData.end(); dataiter++){
728 if (dataiter->first == "LANGUAGE"){
730 newTZData.timeZoneNameLanguage[objectSeekCount] = dataiter->second;
734 if (TokenData == false){
737 propertyTokens += ";";
740 propertyTokens += dataiter->first;
741 propertyTokens += "=";
742 propertyTokens += dataiter->second;
748 if (propertyTokens.size() > 0){
749 newTZData.timeZoneNameTokens[objectSeekCount] = propertyTokens;
752 newTZData.timeZoneNameData[objectSeekCount] = propiter->second;
760 // Process data from X-*
762 for(vector<string>::iterator propiter = timezoneDaylightName[seekCount].begin();
763 propiter != timezoneDaylightName[seekCount].end(); ++propiter){
765 if (propiter->substr(0,2) == "X-" &&
766 propiter->size() > 2){
768 newTZData.xTokensData.push_back(timezoneDaylightData[seekCount][objectSeekCount]);
769 newTZData.xTokensDataTokens.push_back(timezoneDaylightName[seekCount][objectSeekCount]);
777 // Check if the required values were given and
778 // insert newTZData into the vector list of
779 // daylight timezones.
781 if (dateTimeStartFound == true &&
782 timeZoneOffsetToFound == true &&
783 timeZoneOffsetFromFound == true){
785 timezoneDaylightCollection.push_back(newTZData);
795 void CalendarTimezoneObject::ProcessStandardDaylight(){
799 bool TZMode = false; // False = STANDARD, True = DAYLIGHT.
800 bool validBegin = false;
801 vector<string> timezoneObjectName;
802 vector<string> timezoneObjectData;
804 for (vector<string>::iterator iter = objectName.begin();
805 iter != objectName.end(); iter++){
807 // Check if the current name is BEGIN and
808 // data is either STANDARD or DAYLIGHT.
810 if (objectName[seekCount] == "BEGIN" &&
811 (objectData[seekCount] == "STANDARD" ||
812 objectData[seekCount] == "DAYLIGHT")){
814 if (validBegin == false){
820 if (objectData[seekCount] == "STANDARD"){
822 } else if (objectData[seekCount] == "DAYLIGHT") {
831 // Check if current name is END and
832 // data is either STANDARD or DAYLIGHT.
834 if (objectName[seekCount] == "END" &&
835 (objectData[seekCount] == "STANDARD" ||
836 objectData[seekCount] == "DAYLIGHT") &&
839 if (TZMode == false && timezoneObjectName.size() > 0){
840 timezoneStandardName.push_back(timezoneObjectName);
841 timezoneStandardData.push_back(timezoneObjectData);
843 timezoneDaylightName.push_back(timezoneObjectName);
844 timezoneDaylightData.push_back(timezoneObjectData);
847 timezoneObjectName.clear();
848 timezoneObjectData.clear();
854 if (validBegin == true){
856 timezoneObjectName.push_back(objectName[seekCount]);
857 timezoneObjectData.push_back(objectData[seekCount]);