00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "config.h"
00020
00021 #include "EDoc/TextPersistence.h"
00022 #include "EDoc/persistence_data.h"
00023 #include "EDoc/exceptions.h"
00024
00025 #include <iostream>
00026
00027 #ifdef HAVE_STRING_H
00028 #include <string.h>
00029 #endif
00030
00031 #ifdef HAVE_ERRNO_H
00032 #include <errno.h>
00033 #endif
00034
00035 namespace EDoc
00036 {
00037
00038 TextPersistence::TextPersistence(bool reading_in, std::string filename_in) :
00039 reading(reading_in),
00040 line_count(0),
00041 filename(filename_in)
00042 {
00043 }
00044
00045 TextPersistence::~TextPersistence()
00046 {
00047 Close();
00048 }
00049
00050 void TextPersistence::Open()
00051 {
00052 if (reading)
00053 {
00054 file.open(filename.c_str(), std::ios::in);
00055
00056 char temp[10];
00057
00058 file.read(temp, 9);
00059 if (!file)
00060 {
00061 EDOC_THROW_EXCEPTION(FileIOException,
00062 "Failed reading file header.",
00063 "filename: " << filename
00064 << ", line: " << line_count
00065 << ", reason: " << strerror(errno));
00066 }
00067
00068 temp[9] = 0;
00069 if (strcmp(temp, "EDoc: TXT"))
00070 {
00071 EDOC_THROW_EXCEPTION(FileIOException,
00072 "File header was not valid.",
00073 "read: " << temp << ", expected: " << "EDoc: TXT"
00074 << ", line: " << line_count);
00075 }
00076
00077
00078 file.seekg(0);
00079
00080
00081 GetNextLine();
00082 }
00083 else
00084 {
00085 file.open(filename.c_str(), std::ios::out);
00086 file << "EDoc: TXT" << std::endl;
00087 file << std::endl;
00088 }
00089 }
00090
00091 void TextPersistence::Close()
00092 {
00093 file.close();
00094 }
00095
00096 bool TextPersistence::ContainsData(const std::string& data)
00097 {
00098 size_t len = data.size();
00099 for (size_t i = 0; i < len; i++)
00100 {
00101 if (!std::isspace(data[i]))
00102 {
00103 return true;
00104 }
00105 }
00106
00107 return false;
00108 }
00109
00110 std::string TextPersistence::GetNextLine(const char* key_in,
00111 const char* type_in)
00112 {
00113 if (!reading)
00114 {
00115 EDOC_THROW_EXCEPTION(BugException,
00116 "Reading from a write only persistence layer.",
00117 "key: " << key_in << ", type: " << type_in
00118 << ", line: " << line_count);
00119 }
00120
00121 std::string temp = "";
00122 while (!ContainsData(temp))
00123 {
00124 if (!file)
00125 {
00126 EDOC_THROW_EXCEPTION(EOFException,
00127 "End Of File encountered.",
00128 "key: " << key_in << ", type: " << type_in
00129 << ", line: " << line_count);
00130 }
00131 std::getline(file, temp);
00132 line_count++;
00133 }
00134
00135 EDOC_Finer("Read line: " << temp);
00136 return temp;
00137 }
00138
00139 std::string TextPersistence::ReadValue(const char* key_in,
00140 const char* type_in)
00141 {
00142
00143 std::string line;
00144
00145 size_t start_key = 0;
00146 size_t end_key = 0;
00147
00148 size_t start_value = 0;
00149
00150
00151 do
00152 {
00153 line = GetNextLine();
00154
00155 for(start_key = 0; start_key < line.size(); start_key++)
00156 {
00157 if (!std::isspace(line[start_key]))
00158 {
00159 break;
00160 }
00161 }
00162 if (start_key == line.size())
00163 {
00164 EDOC_THROW_EXCEPTION(BugException,
00165 "GetLine() returned a string with only spaces in it.",
00166
00167 "\n\nInput Key: " << key_in
00168 << "\nInput Type: " << type_in
00169 << "\nCurrent input line: line: " << line_count
00170 << "\nLine contents: " << line);
00171 }
00172 }
00173 while (line[start_key] == BJC_PERSIST_COMMENT_CHAR);
00174
00175
00176 if (line[start_key] != BJC_PERSIST_START_KEY_CHAR)
00177 {
00178 EDOC_THROW_EXCEPTION(FileIOException,
00179 "Key should start with $.",
00180
00181 "\n\nInput Key: " << key_in
00182 << "\nInput Type: " << type_in
00183 << "\nCurrent input line: line: " << line_count
00184 << "\nLine contents: " << line);
00185 }
00186
00187
00188 end_key = line.find(BJC_PERSIST_FINISH_KEY_CHAR, start_key + 1);
00189 if (end_key == std::string::npos)
00190 {
00191 EDOC_THROW_EXCEPTION(FileIOException,
00192 "Key should end with : char,",
00193
00194 "\n\nInput Key: " << key_in
00195 << "\nInput Type: " << type_in
00196 << "\nCurrent input line: line: " << line_count
00197 << "\nLine contents: " << line);
00198 }
00199
00200 if (line.size() <= end_key + 1)
00201 {
00202 EDOC_THROW_EXCEPTION(FileIOException,
00203 "Line contains no value field.",
00204
00205 "\n\nInput Key: " << key_in
00206 << "\nInput Type: " << type_in
00207 << "\nCurrent input line: line: " << line_count
00208 << "\nLine contents: " << line);
00209 }
00210
00211 if (line[end_key + 1] != ' ')
00212 {
00213 EDOC_THROW_EXCEPTION(FileIOException,
00214 "A space should always seperate key/value. I.e. Always place a "
00215 "space after the : char.",
00216
00217 "\n\nInput Key: " << key_in
00218 << "\nInput Type: " << type_in
00219 << "\nCurrent input line: line: " << line_count
00220 << "\nLine contents: " << line);
00221 }
00222
00223 start_value = end_key + 2;
00224 std::string value = line.substr(start_value);
00225
00226 if ((start_key + 2) >= end_key)
00227 {
00228 EDOC_THROW_EXCEPTION(FileIOException,
00229 "Not enough data.",
00230
00231 "\n\nInput Key: " << key_in
00232 << "\nInput Type: " << type_in
00233 << "\nCurrent input line: line: " << line_count
00234 << "\nLine contents: " << line);
00235 }
00236
00237 std::string key = line.substr(start_key + 1, (end_key - start_key - 1));
00238 if (!key.size())
00239 {
00240 EDOC_THROW_EXCEPTION(FileIOException,
00241 "Empty key.",
00242
00243 "\n\nInput Key: " << key_in
00244 << "\nInput Type: " << type_in
00245 << "\nCurrent input line: line: " << line_count
00246 << "\nLine contents: " << line);
00247 }
00248
00249
00250 if (key[key.size() -1] == ')')
00251 {
00252 size_t start_type = key.rfind('(');
00253 if (start_type == std::string::npos)
00254 {
00255 EDOC_THROW_EXCEPTION(FileIOException,
00256 "Key contains a ) char. No matching ( for providing a type.",
00257
00258 "\n\nInput Key: " << key_in
00259 << "\nInput Type: " << type_in
00260 << "\nCurrent input line: line: " << line_count
00261 << "\nLine contents: " << line);
00262 }
00263
00264 std::string type = key.substr(start_type + 1, key.size() -
00265 start_type - 2);
00266 key = key.substr(0, start_type);
00267
00268 if (type != type_in)
00269 {
00270 EDOC_THROW_EXCEPTION(FileIOException,
00271 "Mismatching types."
00272 << "\nExpected type: " << type_in
00273 << "\nReceived type: " << type,
00274
00275 "\n\nInput Key: " << key_in
00276 << "\nInput Type: " << type_in
00277 << "\nCurrent input line: line: " << line_count
00278 << "\nLine contents: " << line);
00279 }
00280 }
00281
00282
00283
00284 if (key != key_in)
00285 {
00286 EDOC_THROW_EXCEPTION(FileIOException,
00287 "Mismatching keys."
00288 << "\nExpected key: " << key_in
00289 << "\nReceived key: " << key,
00290
00291 "\n\nInput Key: " << key_in
00292 << "\nInput Type: " << type_in
00293 << "\nCurrent input line: line: " << line_count
00294 << "\nLine contents: " << line);
00295 }
00296
00297 return value;
00298 }
00299
00300 std::string TextPersistence::ReadString(const char* key)
00301 {
00302 return ReadValue(key, "string");
00303 }
00304
00305 bool TextPersistence::ReadBoolean(const char* key)
00306 {
00307 std::string value = ReadValue(key, "bool");
00308
00309 if (value == "true")
00310 {
00311 return true;
00312 }
00313 else if (value == "false")
00314 {
00315 return false;
00316 }
00317
00318 EDOC_THROW_EXCEPTION(FileIOException, "Invalid boolean value.",
00319 "key: " << key << ", value: " << value
00320 << ", line: " << line_count);
00321 }
00322
00323 uint8_t TextPersistence::ReadUInt8(const char* key)
00324 {
00325 std::istringstream stream(ReadValue(key, "uint8"));
00326 uint value = 0;
00327 stream >> value;
00328 if (!stream)
00329 {
00330 EDOC_THROW_EXCEPTION(FileIOException, "Invalid uint8 value.",
00331 "key: " << key << ", value: " << stream.str()
00332 << ", line: " << line_count);
00333 }
00334
00335 if ((value & 0xFF) != value)
00336 {
00337 EDOC_THROW_EXCEPTION(FileIOException, "Value to large for uint8.",
00338 "key: " << key << ", value: " << value
00339 << ", line: " << line_count);
00340 }
00341
00342 return value;
00343 }
00344
00345 int32_t TextPersistence::ReadInt32(const char* key)
00346 {
00347 std::istringstream stream(ReadValue(key, "int32"));
00348 int32_t value = 0;
00349 stream >> value;
00350 if (!stream)
00351 {
00352 EDOC_THROW_EXCEPTION(FileIOException, "Invalid int32 value.",
00353 "key: " << key << ", value: " << stream.str()
00354 << ", line: " << line_count);
00355 }
00356
00357 return value;
00358 }
00359
00360 uint32_t TextPersistence::ReadUInt32(const char* key)
00361 {
00362
00363
00364 std::istringstream stream(ReadValue(key, "uint32"));
00365 uint32_t value = 0;
00366 stream >> value;
00367 if (!stream)
00368 {
00369 EDOC_THROW_EXCEPTION(FileIOException, "Invalid uint32 value.",
00370 "key: " << key << ", value: " << stream.str()
00371 << ", line: " << line_count);
00372 }
00373
00374 return value;
00375 }
00376
00377 uint8_t TextPersistence::ReadRecordType()
00378 {
00379 return ReadUInt8(KEY_RECORD_TYPE);
00380 }
00381
00382 void TextPersistence::WriteString(const char* key, std::string value)
00383 {
00384 if (reading)
00385 {
00386 EDOC_THROW_EXCEPTION(BugException,
00387 "Writing to a read only persistence layer.",
00388 "key: " << key << ", value: " << value
00389 << ", line: " << line_count);
00390 }
00391
00392 file << BJC_PERSIST_START_KEY_CHAR
00393 << key << "(string)"
00394 << BJC_PERSIST_FINISH_KEY_CHAR
00395 << " " << value << std::endl;
00396 line_count++;
00397 }
00398
00399 void TextPersistence::WriteBoolean(const char* key, bool value_in)
00400 {
00401 std::string value = "false";
00402 if (value_in)
00403 {
00404 value = "true";
00405 }
00406
00407 if (reading)
00408 {
00409 EDOC_THROW_EXCEPTION(BugException,
00410 "Writing to a read only persistence layer.",
00411 "key: " << key << ", value: " << value
00412 << ", line: " << line_count);
00413 }
00414
00415 file << BJC_PERSIST_START_KEY_CHAR
00416 << key << "(bool)"
00417 << BJC_PERSIST_FINISH_KEY_CHAR
00418 << " " << value << std::endl;
00419 line_count++;
00420 }
00421
00422 void TextPersistence::WriteUInt8(const char* key, uint8_t value)
00423 {
00424 if (reading)
00425 {
00426 EDOC_THROW_EXCEPTION(BugException,
00427 "Writing to a read only persistence layer.",
00428 "key: " << key << ", value: " << (uint32_t)value
00429 << ", line: " << line_count);
00430 }
00431
00432 file << BJC_PERSIST_START_KEY_CHAR
00433 << key << "(uint8)"
00434 << BJC_PERSIST_FINISH_KEY_CHAR
00435 << " " << (uint32_t)value << std::endl;
00436 line_count++;
00437 }
00438
00439 void TextPersistence::WriteInt32(const char* key, int32_t value)
00440 {
00441 if (reading)
00442 {
00443 EDOC_THROW_EXCEPTION(BugException,
00444 "Writing to a read only persistence layer.",
00445 "key: " << key << ", value: " << value
00446 << ", line: " << line_count);
00447 }
00448
00449 file << BJC_PERSIST_START_KEY_CHAR
00450 << key << "(int32)"
00451 << BJC_PERSIST_FINISH_KEY_CHAR
00452 << " " << value << std::endl;
00453 line_count++;
00454 }
00455
00456 void TextPersistence::WriteUInt32(const char* key, uint32_t value)
00457 {
00458 if (reading)
00459 {
00460 EDOC_THROW_EXCEPTION(BugException,
00461 "Writing to a read only persistence layer.",
00462 "key: " << key << ", value: " << value
00463 << ", line: " << line_count);
00464 }
00465
00466 file << BJC_PERSIST_START_KEY_CHAR
00467 << key << "(uint32)"
00468 << BJC_PERSIST_FINISH_KEY_CHAR
00469 << " " << value << std::endl;
00470 line_count++;
00471 }
00472
00473 void TextPersistence::WriteUInt32Debug(const char* key, uint32_t value,
00474 std::string debug_text)
00475 {
00476 if (reading)
00477 {
00478 EDOC_THROW_EXCEPTION(BugException,
00479 "Writing to a read only persistence layer.",
00480 "key: " << key << ", value: " << value
00481 << ", line: " << line_count);
00482 }
00483
00484 file << BJC_PERSIST_START_KEY_CHAR
00485 << key << "(uint32)"
00486 << BJC_PERSIST_FINISH_KEY_CHAR
00487 << " " << value << " " << debug_text << std::endl;
00488 line_count++;
00489 }
00490
00491 void TextPersistence::WriteInt32Debug(const char* key, int32_t value,
00492 std::string debug_text)
00493 {
00494 if (reading)
00495 {
00496 EDOC_THROW_EXCEPTION(BugException,
00497 "Writing to a read only persistence layer.",
00498 "key: " << key << ", value: " << value
00499 << ", line: " << line_count);
00500 }
00501
00502 file << BJC_PERSIST_START_KEY_CHAR
00503 << key << "(int32)"
00504 << BJC_PERSIST_FINISH_KEY_CHAR
00505 << " " << value << " " << debug_text << std::endl;
00506 line_count++;
00507 }
00508
00509 void TextPersistence::WriteRecordType(uint8_t value)
00510 {
00511 file << std::endl;
00512 WriteUInt8(KEY_RECORD_TYPE, value);
00513 }
00514
00515 }
00516