+// 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.
+
+ if (!FileExists(loadFilename)){
+ return CALENDAROBJECTLOAD_MISSING;
+ }
+
+ ifstream fileStream;
+ string receivedStringData = "";
+
+ fileStream.open(loadFilename, ifstream::in);
+
+ 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