1 // CalendarObject.cpp - CalendarObject 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 "CalendarObject.h"
20 #include "../../common/file.h"
24 CalendarObjectLoadResult CalendarObject::LoadFile(std::string loadFilename){
26 // Check if the file exists and return
27 // CALENDAROBJECTLOAD_CANNOTOPEN if not.
29 if (!FileExists(loadFilename)){
30 return CALENDAROBJECTLOAD_MISSING;
34 string receivedStringData = "";
36 fileStream.open(loadFilename, ifstream::in);
38 if (fileStream.rdstate() & ifstream::failbit){
39 return CALENDAROBJECTLOAD_CANNOTOPEN;
42 if (fileStream.rdstate() & ifstream::badbit){
43 return CALENDAROBJECTLOAD_CANNOTOPEN;
46 // Read the data into a string.
48 char *bufferRead = new char[256];
50 while (!fileStream.eof()){
52 fileStream.getline(bufferRead, 256);
53 receivedStringData.append(bufferRead);
54 receivedStringData.append("\n");
60 CalendarObjectLoadResult stringProcResult = CALENDAROBJECTLOAD_UNITTESTFAIL;
62 stringProcResult = LoadString(&receivedStringData);
64 return stringProcResult;
68 CalendarObjectLoadResult CalendarObject::LoadString(std::string *loadStringData){
71 bool skipMode = false;
72 bool colonFound = false;
73 bool quoteMode = false;
75 int stringDataSize = LoadStringData->size();
80 while (seekCount < stringDataSize){
82 // Check if character is blank or a tab and is the first character
85 if (((*loadStringData)[seekCount] == ' ' ||
86 (*loadStringData)[seekCount] == '\t')
89 // Character is on a new line and it is a space or
90 // tab. Ignore this character as it is not part
95 } else if ((*loadStringData)[seekCount] == '\"'){
97 if (quoteMode == false){
103 bufferChar = (*loadStringData)[seekCount];
105 if (colonFound == false){
106 propertyName += bufferChar;
108 propertyValue += bufferChar;
111 } else if (newLine == true){
113 // Character is on a new line but not a space or
114 // tab so check if the colon has been found
115 // and add the property name and value to
118 if (colonFound == true){
119 objectName.push_back(propertyName);
120 objectData.push_back(propertyValue);
125 propertyName.clear();
126 propertyValue.clear();
128 bufferChar = (*loadStringData)[seekCount];
129 propertyName += bufferChar;
131 } else if ((*loadStringData)[seekCount] == '\n'){
133 // Character is the new line character so mark
134 // the NewLine boolean as true.
138 } else if ((*loadStringData)[seekCount] == ':' &&
141 // Character is the colon. Set the colon
142 // found boolen to true.
144 bufferChar = (*loadStringData)[seekCount];
146 if (colonFound == true){
147 propertyValue += bufferChar;
154 // Character is not part of a new line and is not
155 // the new line character itself.
157 bufferChar = (*loadStringData)[seekCount];
159 if (colonFound == false){
160 propertyName += bufferChar;
162 propertyValue += bufferChar;
171 // Finish off processing any data that wasn't processed
172 // when the end of the string was reached.
174 if (colonFound == true &&
175 propertyName.size() > 0 &&
176 propertyValue.size() > 0){
178 objectName.push_back(propertyName);
179 objectData.push_back(propertyValue);
183 // Check that the object contains valid data.
185 CalendarObjectLoadResult stringProcResult = CALENDAROBJECTLOAD_UNITTESTFAIL;
186 CalendarObjectValidResult baseDataResult = ValidBaseObject();
187 CalendarObjectValidResult eventDataResult = ValidObject();
189 if (baseDataResult != CALENDAROBJECTVALID_OK ||
190 eventDataResult != CALENDAROBJECTVALID_OK){
192 stringProcResult = CALENDAROBJECTLOAD_INVALIDFORMAT;
196 stringProcResult = CALENDAROBJECTLOAD_OK;
203 return stringProcResult;
207 CalendarObjectValidResult CalendarObject::ValidBaseObject(){
209 bool validBegin = false;
210 bool validAlarmBegin = false;
211 bool validVersion = false;
212 bool validEnd = false;
214 vector<int> deleteLines;
215 vector<string> alarmObjectName;
216 vector<string> alarmObjectData;
218 // Check that the first line contains BEGIN:VCALENDAR
219 // and it only appears once.
221 for (vector<string>::iterator iter = objectName.begin();
222 iter != objectName.end(); iter++){
224 if (objectName[seekCount] == "BEGIN" &&
225 objectData[seekCount] == "VCALENDAR"){
227 if (validBegin == false){
230 return CALENDAROBJECTVALID_INVALIDFORMAT;
235 if (objectName[seekCount] == "END" &&
236 objectData[seekCount] == "VCALENDAR" &&
237 validBegin == false){
239 return CALENDAROBJECTVALID_INVALIDFORMAT;
241 } else if (objectName[seekCount] == "END" &&
242 objectData[seekCount] == "VALARM" &&
243 validAlarmBegin == false){
245 return CALENDAROBJECTVALID_INVALIDFORMAT;
247 } else if (objectName[seekCount] == "END" &&
248 objectData[seekCount] == "VCALENDAR" &&
249 validAlarmBegin == true){
251 return CALENDAROBJECTVALID_INVALIDFORMAT;
255 // Look for any VALARM sections.
257 if (validAlarmBegin == true){
259 alarmObjectName.push_back(objectName[seekCount]);
260 alarmObjectData.push_back(objectData[seekCount]);
261 deleteLines.push_back(seekCount);
265 if (objectName[seekCount] == "END" &&
266 objectData[seekCount] == "VALARM" &&
267 validAlarmBegin == true){
269 eventAlarmName.push_back(AlarmObjectName);
270 eventAlarmData.push_back(AlarmObjectData);
272 alarmObjectName.clear();
273 alarmObjectData.clear();
275 validAlarmBegin = false;
279 if (objectName[seekCount] == "BEGIN" &&
280 objectData[seekCount] == "VALARM" &&
283 if (validAlarmBegin == false){
284 validAlarmBegin = true;
286 return CALENDAROBJECTVALID_INVALIDFORMAT;
289 alarmObjectName.push_back(objectName[seekCount]);
290 alarmObjectData.push_back(objectData[seekCount]);
291 deleteLines.push_back(seekCount);
301 // Check that the last line contains END:VCALENDAR
302 // and it only appears once.
304 for (vector<string>::iterator iter = objectName.begin();
305 iter != objectName.end(); iter++){
307 if (objectName[seekCount] == "END" &&
308 objectData[seekCount] == "VCALENDAR"){
310 if (validEnd == false){
313 return CALENDAROBJECTVALID_INVALIDFORMAT;
324 // Check that the VERSION value contains 2.0 and that
325 // it only appears once.
327 for (vector<string>::iterator iter = objectName.begin();
328 iter != objectName.end(); iter++){
330 if (objectName[seekCount] == "VERSION" &&
331 objectData[seekCount] == "2.0"){
333 if (validVersion == false){
336 return CALENDAROBJECTVALID_INVALIDFORMAT;
345 // Remove lines that aren't needed as they have
346 // been moved to the EventAlarm section.
348 for (vector<int>::reverse_iterator deliter = deleteLines.rbegin();
349 deliter != deleteLines.rend(); deliter++){
351 objectName.erase(objectName.begin()+(*deliter));
352 objectData.erase(objectData.begin()+(*deliter));
356 if (validBegin == true &&
358 validVersion == true &&
359 validAlarmBegin == false){
361 return CALENDAROBJECTVALID_OK;
365 return CALENDAROBJECTVALID_INVALIDFORMAT;
371 void CalendarObject::ProcessBaseData(){
373 // Process the base object data.
375 multimap<string,string> dataReceived;
377 // Get the method (METHOD).
379 dataReceived = ProcessTextVectors(&objectName, &objectData, false, "METHOD");
381 if (dataReceived.begin() != dataReceived.end()){
384 methodTokens = dataReceived.begin()->first.substr(7);
387 catch(const out_of_range &oor){
388 // Do nothing as there is no data.
391 methodData = dataReceived.begin()->second;
395 // Get the calendar scale (CALSCALE).
397 dataReceived = ProcessTextVectors(&objectName, &objectData, false, "CALSCALE");
399 if (dataReceived.begin() != dataReceived.end()){
402 calendarScaleTokens = dataReceived.begin()->first.substr(9);
405 catch(const out_of_range &oor){
406 // Do nothing as there is no data.
409 calendarScaleData = dataReceived.begin()->second;