libs/EDoc/TextPersistence.cpp

Go to the documentation of this file.
00001 /*******************************************************************************
00002 
00003    Copyright (C) 2007 by Brendon Costa
00004 
00005    This library is free software; you can redistribute it and/or modify 
00006    it under the terms of the "LGPL Like" License defined in the file COPYING 
00007    that should have been distributed along with this source.
00008 
00009    This library is distributed in the hope that it will be useful, 
00010    but WITHOUT ANY WARRANTY; without even the implied warranty of 
00011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
00012 
00013    You should have received a copy of the "LGPL Like" License 
00014    along with this library; see the file COPYING. if not, it can be 
00015    obtained from the EDoc++ website: 
00016    http://edoc.sourceforge.net/license.html
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          // Read the 1st 9 characters
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          // Reset the file pointer.
00078          file.seekg(0);
00079 
00080          // Read the first line and discard.
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       // Get the next line from the file.
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       // Get the first non comment line.
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       // Should start with start char.
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       // Find the end of key character.
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       // Now to remove the type information from the key if therre is any.
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       //std::cerr << "key: " << key << std::endl;
00283       //std::cerr << "value: " << value << std::endl;
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       // Note: This ignores any additional "debug" data on the rest of the line
00363       // and just reads the first int.
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 

Generated on Tue Jan 20 18:26:07 2009 for EDoc-0.2.1 by  doxygen 1.5.1