Home | News | Projects | Releases
Bugs | RFE | Repositories | Help
Win32: implement further UTF8 support
[xestiacalendar/.git] / source / objects / calendarobject / CalendarObject.cpp
index 00f13c8..76cb4e6 100644 (file)
@@ -1,9 +1,435 @@
+// CalendarObject.cpp - CalendarObject 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 <http://www.gnu.org/licenses/>
+
 #include "CalendarObject.h"
+#include "../../common/file.h"
+
+using namespace std;
+
+CalendarObjectLoadResult CalendarObject::LoadFile(std::string loadFilename){
+
+       // Check if the file exists and return 
+       // CALENDAROBJECTLOAD_CANNOTOPEN if not.
+       
+       ifstream fileStream;
+       string receivedStringData = "";
+       
+#ifndef WIN32
+
+       if (!FileExists(loadFilename)) {
+               return CALENDAROBJECTLOAD_MISSING;
+       }
+
+       fileStream.open(loadFilename, ifstream::in);
+
+#else
+
+       wstring loadFilename_utf16;
+
+       int len = MultiByteToWideChar(CP_UTF8, 0, &loadFilename[0], (int)loadFilename.size(), NULL, 0);
+
+       if (len > 0)
+       {
+               loadFilename_utf16.resize(len);
+               MultiByteToWideChar(CP_UTF8, 0, &loadFilename[0], (int)loadFilename.size(), &loadFilename_utf16[0], len);
+       }
+
+       if (!FileExists(loadFilename_utf16)) {
+               return CALENDAROBJECTLOAD_MISSING;
+       }
+
+       fileStream.open(loadFilename_utf16, ifstream::in);
+
+#endif
+
+       if (fileStream.rdstate() & ifstream::failbit){
+               return CALENDAROBJECTLOAD_CANNOTOPEN;
+       }
+
+       if (fileStream.rdstate() & ifstream::badbit){
+               return CALENDAROBJECTLOAD_CANNOTOPEN;
+       }
+       
+       // Read the data into a string.
+       
+       char *bufferRead = new char[256];
+       
+       while (!fileStream.eof()){
+               
+               fileStream.getline(bufferRead, 256);
+               receivedStringData.append(bufferRead);
+               receivedStringData.append("\n");
+               
+       }
+       
+       delete[] bufferRead;
+       
+       CalendarObjectLoadResult stringProcResult = CALENDAROBJECTLOAD_UNITTESTFAIL;
+       
+       stringProcResult = LoadString(&receivedStringData);
+       
+       return stringProcResult;
+       
+}
+
+CalendarObjectLoadResult CalendarObject::LoadString(std::string *loadStringData){
+
+       bool newLine = false;
+       bool skipMode = false;
+       bool colonFound = false;
+       bool quoteMode = false;
+       char bufferChar = 0;
+       int stringDataSize = loadStringData->size();
+       int seekCount = 0;
+       string propertyName;
+       string propertyValue;
+
+       while (seekCount < stringDataSize){
+               
+               // Check if character is blank or a tab and is the first character
+               // on a new line.
+               
+               if (((*loadStringData)[seekCount] == ' ' || 
+                       (*loadStringData)[seekCount] == '\t')
+                       && newLine == true){
+                       
+                       // Character is on a new line and it is a space or
+                       // tab. Ignore this character as it is not part
+                       // of the value.
+
+                       newLine = false;
+                               
+               } else if ((*loadStringData)[seekCount] == '\"'){
+                       
+                       if (quoteMode == false){
+                               quoteMode = true;
+                       } else {
+                               quoteMode = false;
+                       }
+                       
+                       bufferChar = (*loadStringData)[seekCount];
+                       
+                       if (colonFound == false){
+                               propertyName += bufferChar;
+                       } else {
+                               propertyValue += bufferChar;
+                       }
+                       
+               } else if (newLine == true){
+               
+                       // Character is on a new line but not a space or
+                       // tab so check if the colon has been found
+                       // and add the property name and value to
+                       // the lists.
+
+                       if (colonFound == true){
+                               objectName.push_back(propertyName);
+                               objectData.push_back(propertyValue);
+                       }
+                       
+                       colonFound = false;
+                       newLine = false;
+                       propertyName.clear();
+                       propertyValue.clear();
+                       
+                       bufferChar = (*loadStringData)[seekCount];
+                       propertyName += bufferChar;
+                       
+               } else if ((*loadStringData)[seekCount] == '\n'){
+               
+                       // Character is the new line character so mark
+                       // the NewLine boolean as true.
+                       
+                       newLine = true;
+                       
+               } else if ((*loadStringData)[seekCount] == ':' &&
+                               quoteMode == false){
+               
+                       // Character is the colon. Set the colon
+                       // found boolen to true.
+                       
+                       bufferChar = (*loadStringData)[seekCount];
+                                       
+                       if (colonFound == true){
+                               propertyValue += bufferChar;
+                       } else {
+                               colonFound = true;
+                       }
+                       
+               } else {
+                       
+                       // Character is not part of a new line and is not
+                       // the new line character itself.
+                       
+                       bufferChar = (*loadStringData)[seekCount];
+                       
+                       if (colonFound == false){
+                               propertyName += bufferChar;
+                       } else {
+                               propertyValue += bufferChar;
+                       }
+                       
+               }
+               
+               seekCount++;
+               
+       }
+       
+       // Finish off processing any data that wasn't processed
+       // when the end of the string was reached.
+       
+       if (colonFound == true && 
+               propertyName.size() > 0 &&
+               propertyValue.size() > 0){
+               
+               objectName.push_back(propertyName);
+               objectData.push_back(propertyValue);
+                       
+       }
+       
+       // Check that the object contains valid data.
+       
+       CalendarObjectLoadResult stringProcResult = CALENDAROBJECTLOAD_UNITTESTFAIL;
+       CalendarObjectValidResult baseDataResult = ValidBaseObject();
+       CalendarObjectValidResult eventDataResult = ValidObject();
+       
+       if (baseDataResult != CALENDAROBJECTVALID_OK || 
+               eventDataResult != CALENDAROBJECTVALID_OK){
+                       
+               stringProcResult = CALENDAROBJECTLOAD_INVALIDFORMAT;
+                       
+       } else {
+               
+               stringProcResult = CALENDAROBJECTLOAD_OK;
+               
+       }
+       
+       ProcessBaseData();
+       ProcessData();
+       
+       return stringProcResult;
+       
+}
+
+CalendarObjectValidResult CalendarObject::ValidBaseObject(){
+       
+       bool validBegin = false;
+       bool validAlarmBegin = false;
+       bool validVersion = false;
+       bool validEnd = false;
+       int seekCount = 0;
+       vector<int> deleteLines;
+       vector<string> alarmObjectName;
+       vector<string> alarmObjectData;
+       
+       // Check that the first line contains BEGIN:VCALENDAR
+       // and it only appears once.
+       
+       for (vector<string>::iterator iter = objectName.begin();
+               iter != objectName.end(); iter++){
+
+               if (objectName[seekCount] == "BEGIN" &&
+                       objectData[seekCount] == "VCALENDAR"){
+                       
+                       if (validBegin == false){
+                               validBegin = true;
+                       } else {
+                               return CALENDAROBJECTVALID_INVALIDFORMAT;
+                       }
+                               
+               }
+               
+               if (objectName[seekCount] == "END" &&
+                       objectData[seekCount] == "VCALENDAR" &&
+                       validBegin == false){
+               
+                       return CALENDAROBJECTVALID_INVALIDFORMAT;
+                               
+               } else if (objectName[seekCount] == "END" &&
+                       objectData[seekCount] == "VALARM" &&
+                       validAlarmBegin == false){
+
+                       return CALENDAROBJECTVALID_INVALIDFORMAT;
+                               
+               } else if (objectName[seekCount] == "END" &&
+                       objectData[seekCount] == "VCALENDAR" &&
+                       validAlarmBegin == true){
+
+                       return CALENDAROBJECTVALID_INVALIDFORMAT;
+                               
+               }
+               
+               // Look for any VALARM sections.
+               
+               if (validAlarmBegin == true){
+                       
+                       alarmObjectName.push_back(objectName[seekCount]);
+                       alarmObjectData.push_back(objectData[seekCount]);
+                       deleteLines.push_back(seekCount);
+                       
+               }
+               
+               if (objectName[seekCount] == "END" &&
+                       objectData[seekCount] == "VALARM" && 
+                       validAlarmBegin == true){
+                               
+                       eventAlarmName.push_back(alarmObjectName);
+                       eventAlarmData.push_back(alarmObjectData);
+                       
+                       alarmObjectName.clear();
+                       alarmObjectData.clear();
+
+                       validAlarmBegin = false;
+                               
+               }
+               
+               if (objectName[seekCount] == "BEGIN" &&
+                       objectData[seekCount] == "VALARM" && 
+                       validBegin == true){
+                               
+                       if (validAlarmBegin == false){
+                               validAlarmBegin = true;
+                       } else {
+                               return CALENDAROBJECTVALID_INVALIDFORMAT;
+                       }
+                       
+                       alarmObjectName.push_back(objectName[seekCount]);
+                       alarmObjectData.push_back(objectData[seekCount]);
+                       deleteLines.push_back(seekCount);
+                       
+               }
+               
+               seekCount++;
+                       
+       }
+       
+       seekCount = 0;
+       
+       // Check that the last line contains END:VCALENDAR
+       // and it only appears once.
+       
+       for (vector<string>::iterator iter = objectName.begin();
+               iter != objectName.end(); iter++){
+               
+               if (objectName[seekCount] == "END" &&
+                       objectData[seekCount] == "VCALENDAR"){
+                       
+                       if (validEnd == false){
+                               validEnd = true;
+                       } else {
+                               return CALENDAROBJECTVALID_INVALIDFORMAT;
+                       }
+                               
+               }
+                       
+               seekCount++;
+                       
+       }
+       
+       seekCount = 0;
+       
+       // Check that the VERSION value contains 2.0 and that
+       // it only appears once.
+       
+       for (vector<string>::iterator iter = objectName.begin();
+               iter != objectName.end(); iter++){
+               
+               if (objectName[seekCount] == "VERSION" &&
+                       objectData[seekCount] == "2.0"){
+                       
+                       if (validVersion == false){
+                               validVersion = true;
+                       } else {
+                               return CALENDAROBJECTVALID_INVALIDFORMAT;
+                       }
+                               
+               }
+               
+               seekCount++;
+                       
+       }
+
+       // Remove lines that aren't needed as they have
+       // been moved to the EventAlarm section.
+       
+       for (vector<int>::reverse_iterator deliter = deleteLines.rbegin();
+               deliter != deleteLines.rend(); deliter++){
+
+               objectName.erase(objectName.begin()+(*deliter));
+               objectData.erase(objectData.begin()+(*deliter));
+                       
+       }
 
-CalendarObjectLoadResult CalendarObject::LoadFile(){
+       if (validBegin == true && 
+               validEnd == true && 
+               validVersion == true &&
+               validAlarmBegin == false){
+       
+               return CALENDAROBJECTVALID_OK;
+                       
+       } else {
+               
+               return CALENDAROBJECTVALID_INVALIDFORMAT;
+               
+       }
+       
 }
 
-CalendarObjectLoadResult CalendarObject::LoadString(){
-  
+void CalendarObject::ProcessBaseData(){
+       
+       // Process the base object data.
+       
+       multimap<string,string> dataReceived;
+       
+       // Get the method (METHOD).
+       
+       dataReceived = ProcessTextVectors(&objectName, &objectData, false, "METHOD");
+       
+       if (dataReceived.begin() != dataReceived.end()){
+               
+               try {
+                       methodTokens = dataReceived.begin()->first.substr(7);
+               }
+               
+               catch(const out_of_range &oor){
+                       // Do nothing as there is no data.
+               }               
+               
+               methodData = dataReceived.begin()->second;
+               
+       }
+       
+       // Get the calendar scale (CALSCALE).
+       
+       dataReceived = ProcessTextVectors(&objectName, &objectData, false, "CALSCALE");
+       
+       if (dataReceived.begin() != dataReceived.end()){
+               
+               try {
+                       calendarScaleTokens = dataReceived.begin()->first.substr(9);
+               }
+               
+               catch(const out_of_range &oor){
+                       // Do nothing as there is no data.
+               }               
+               
+               calendarScaleData = dataReceived.begin()->second;
+               
+       }
+       
 }
\ No newline at end of file
Xestia Software Development
Yn Maystri
© 2006 - 2019 Xestia Software Development
Software

Xestia Address Book
Xestia Calendar
Development

Xestia Gelforn
Everything else

About
News
Privacy Policy