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;