00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038 #include <cstdlib>
00039 #include <cstdio>
00040 #include <cstdarg>
00041 #include <cfloat>
00042 #include <cctype>
00043 #include <cstring>
00044 #include <climits>
00045 #include <vector>
00046 #include <string>
00047 #include <fstream>
00048
00049 #ifdef WIN32
00050 #include <windows.h>
00051 #endif
00052
00053 #include <blort/Tracker/CDataFile.h>
00054
00055
00057 #ifdef WIN32
00058 #define snprintf _snprintf
00059 #define vsnprintf _vsnprintf
00060 #endif
00061
00062 using namespace std;
00063
00064
00065
00066
00067 CDataFile::CDataFile(const t_Str& szFileName)
00068 {
00069 m_bDirty = false;
00070 m_szFileName = szFileName;
00071 m_Flags = (AUTOCREATE_SECTIONS | AUTOCREATE_KEYS);
00072 m_Sections.push_back( t_Section() );
00073
00074 Load(m_szFileName);
00075 }
00076
00077 CDataFile::CDataFile()
00078 {
00079 Clear();
00080 m_Flags = (AUTOCREATE_SECTIONS | AUTOCREATE_KEYS);
00081 m_Sections.push_back( t_Section() );
00082 }
00083
00084
00085
00086 CDataFile::~CDataFile()
00087 {
00088
00089
00090 }
00091
00092
00093
00094 void CDataFile::Clear()
00095 {
00096 m_bDirty = false;
00097 m_szFileName = t_Str("");
00098 m_Sections.clear();
00099 }
00100
00101
00102
00103
00104 void CDataFile::SetFileName(const t_Str& szFileName)
00105 {
00106 if (m_szFileName.size() != 0 && CompareNoCase(szFileName, m_szFileName) != 0)
00107 {
00108 m_bDirty = true;
00109
00110 Report(E_WARN, "[CDataFile::SetFileName] The filename has changed from <%s> to <%s>.",
00111 m_szFileName.c_str(), szFileName.c_str());
00112 }
00113
00114 m_szFileName = szFileName;
00115 }
00116
00117
00118
00119
00120
00121 bool CDataFile::Load(const t_Str& szFileName)
00122 {
00123 fstream File(szFileName.c_str(), ios::in);
00124
00125 if ( File.is_open() )
00126 {
00127 bool bDone = false;
00128 bool bAutoKey = (m_Flags & AUTOCREATE_KEYS) == AUTOCREATE_KEYS;
00129 bool bAutoSec = (m_Flags & AUTOCREATE_SECTIONS) == AUTOCREATE_SECTIONS;
00130
00131 t_Str szLine;
00132 t_Str szComment;
00133 char buffer[MAX_BUFFER_LEN];
00134 t_Section* pSection = GetSection("");
00135
00136
00137 m_Flags |= AUTOCREATE_KEYS;
00138 m_Flags |= AUTOCREATE_SECTIONS;
00139
00140 while ( !bDone )
00141 {
00142 memset(buffer, 0, MAX_BUFFER_LEN);
00143 File.getline(buffer, MAX_BUFFER_LEN);
00144
00145 szLine = buffer;
00146 Trim(szLine);
00147
00148 bDone = ( File.eof() || File.bad() || File.fail() );
00149
00150 if ( szLine.find_first_of(CommentIndicators) == 0 )
00151 {
00152 szComment += "\n";
00153 szComment += szLine;
00154 }
00155 else
00156 if ( szLine.find_first_of('[') == 0 )
00157 {
00158 szLine.erase( 0, 1 );
00159 szLine.erase( szLine.find_last_of(']'), 1 );
00160
00161 CreateSection(szLine, szComment);
00162 pSection = GetSection(szLine);
00163 szComment = t_Str("");
00164 }
00165 else
00166 if ( szLine.size() > 0 )
00167 {
00168 t_Str szKey = GetNextWord(szLine);
00169 t_Str szValue = szLine;
00170
00171 if ( szKey.size() > 0 && szValue.size() > 0 )
00172 {
00173 SetValue(szKey, szValue, szComment, pSection->szName);
00174 szComment = t_Str("");
00175 }
00176 }
00177 }
00178
00179
00180 if ( !bAutoKey )
00181 m_Flags &= ~AUTOCREATE_KEYS;
00182
00183 if ( !bAutoSec )
00184 m_Flags &= ~AUTOCREATE_SECTIONS;
00185 }
00186 else
00187 {
00188 Report(E_INFO, "[CDataFile::Load] Unable to open file. Does it exist?");
00189 return false;
00190 }
00191
00192 File.close();
00193
00194 return true;
00195 }
00196
00197
00198
00199
00200
00201
00202 bool CDataFile::Save()
00203 {
00204 if ( KeyCount() == 0 && SectionCount() == 0 )
00205 {
00206
00207 Report(E_INFO, "[CDataFile::Save] Nothing to save.");
00208 return false;
00209 }
00210
00211 if ( m_szFileName.size() == 0 )
00212 {
00213 Report(E_ERROR, "[CDataFile::Save] No filename has been set.");
00214 return false;
00215 }
00216
00217 fstream File(m_szFileName.c_str(), ios::out|ios::trunc);
00218
00219 if ( File.is_open() )
00220 {
00221 SectionItor s_pos;
00222 KeyItor k_pos;
00223 t_Section Section;
00224 t_Key Key;
00225
00226 for (s_pos = m_Sections.begin(); s_pos != m_Sections.end(); ++s_pos)
00227 {
00228 Section = (*s_pos);
00229 bool bWroteComment = false;
00230
00231 if ( Section.szComment.size() > 0 )
00232 {
00233 bWroteComment = true;
00234 WriteLn(File, "\n%s", CommentStr(Section.szComment).c_str());
00235 }
00236
00237 if ( Section.szName.size() > 0 )
00238 {
00239 WriteLn(File, "%s[%s]",
00240 bWroteComment ? "" : "\n",
00241 Section.szName.c_str());
00242 }
00243
00244 for (k_pos = Section.Keys.begin(); k_pos != Section.Keys.end(); ++k_pos)
00245 {
00246 Key = (*k_pos);
00247
00248 if ( Key.szKey.size() > 0 && Key.szValue.size() > 0 )
00249 {
00250 WriteLn(File, "%s%s%s%s%c%s",
00251 Key.szComment.size() > 0 ? "\n" : "",
00252 CommentStr(Key.szComment).c_str(),
00253 Key.szComment.size() > 0 ? "\n" : "",
00254 Key.szKey.c_str(),
00255 EqualIndicators[0],
00256 Key.szValue.c_str());
00257 }
00258 }
00259 }
00260
00261 }
00262 else
00263 {
00264 Report(E_ERROR, "[CDataFile::Save] Unable to save file.");
00265 return false;
00266 }
00267
00268 m_bDirty = false;
00269
00270 File.flush();
00271 File.close();
00272
00273 return true;
00274 }
00275
00276
00277
00278 bool CDataFile::SetKeyComment(const t_Str& szKey, const t_Str& szComment,
00279 const t_Str& szSection)
00280 {
00281 KeyItor k_pos;
00282 t_Section* pSection;
00283
00284 if ( (pSection = GetSection(szSection)) == NULL )
00285 return false;
00286
00287 for (k_pos = pSection->Keys.begin(); k_pos != pSection->Keys.end(); ++k_pos)
00288 {
00289 if ( CompareNoCase( (*k_pos).szKey, szKey ) == 0 )
00290 {
00291 (*k_pos).szComment = szComment;
00292 m_bDirty = true;
00293 return true;
00294 }
00295 }
00296
00297 return false;
00298
00299 }
00300
00301
00302
00303
00304 bool CDataFile::SetSectionComment(const t_Str& szSection, const t_Str& szComment)
00305 {
00306 SectionItor s_pos;
00307
00308 for (s_pos = m_Sections.begin(); s_pos != m_Sections.end(); ++s_pos)
00309 {
00310 if ( CompareNoCase( (*s_pos).szName, szSection ) == 0 )
00311 {
00312 (*s_pos).szComment = szComment;
00313 m_bDirty = true;
00314 return true;
00315 }
00316 }
00317
00318 return false;
00319 }
00320
00321
00322
00323
00324
00325
00326
00327 bool CDataFile::SetValue(const t_Str& szKey, const t_Str& szValue,
00328 const t_Str& szComment, const t_Str& szSection)
00329 {
00330 t_Key* pKey = GetKey(szKey, szSection);
00331 t_Section* pSection = GetSection(szSection);
00332
00333 if (pSection == NULL)
00334 {
00335 if ( !(m_Flags & AUTOCREATE_SECTIONS) || !CreateSection(szSection,""))
00336 return false;
00337
00338 pSection = GetSection(szSection);
00339 }
00340
00341
00342 if ( pSection == NULL )
00343 return false;
00344
00345
00346
00347 if ( pKey == NULL && szValue.size() > 0 && (m_Flags & AUTOCREATE_KEYS))
00348 {
00349 t_Key Key;
00350
00351 Key.szKey = szKey;
00352 Key.szValue = szValue;
00353 Key.szComment = szComment;
00354
00355 m_bDirty = true;
00356
00357 pSection->Keys.push_back(Key);
00358
00359 return true;
00360 }
00361
00362 if ( pKey != NULL )
00363 {
00364 pKey->szValue = szValue;
00365 pKey->szComment = szComment;
00366
00367 m_bDirty = true;
00368
00369 return true;
00370 }
00371
00372 return false;
00373 }
00374
00375
00376
00377 bool CDataFile::SetFloat(const t_Str& szKey, float fValue,
00378 const t_Str& szComment, const t_Str& szSection)
00379 {
00380 char szStr[64];
00381
00382 snprintf(szStr, 64, "%f", fValue);
00383
00384 return SetValue(szKey, szStr, szComment, szSection);
00385 }
00386
00387
00388
00389 bool CDataFile::SetInt(const t_Str& szKey, int nValue, const t_Str& szComment, const t_Str& szSection)
00390 {
00391 char szStr[64];
00392
00393 snprintf(szStr, 64, "%d", nValue);
00394
00395 return SetValue(szKey, szStr, szComment, szSection);
00396
00397 }
00398
00399
00400
00401 bool CDataFile::SetBool(const t_Str& szKey, bool bValue, const t_Str& szComment, const t_Str& szSection)
00402 {
00403 t_Str szValue = bValue ? "True" : "False";
00404
00405 return SetValue(szKey, szValue, szComment, szSection);
00406 }
00407
00408
00409
00410
00411 t_Str CDataFile::GetValue(const t_Str& szKey, const t_Str& szSection)
00412 {
00413 t_Key* pKey = GetKey(szKey, szSection);
00414
00415 return (pKey == NULL) ? t_Str("") : pKey->szValue;
00416 }
00417
00418
00419
00420
00421 t_Str CDataFile::GetString(const t_Str& szKey, const t_Str& szSection)
00422 {
00423 return GetValue(szKey, szSection);
00424 }
00425
00426
00427
00428
00429 float CDataFile::GetFloat(const t_Str& szKey, const t_Str& szSection)
00430 {
00431 t_Str szValue = GetValue(szKey, szSection);
00432
00433 if ( szValue.size() == 0 )
00434 return FLT_MIN;
00435 return (float)atof( szValue.c_str() );
00436 }
00437
00438
00439
00440
00441 int CDataFile::GetInt(const t_Str& szKey, const t_Str& szSection)
00442 {
00443 t_Str szValue = GetValue(szKey, szSection);
00444
00445 if ( szValue.size() == 0 )
00446 return INT_MIN;
00447
00448 return atoi( szValue.c_str() );
00449 }
00450
00451
00452
00453
00454 bool CDataFile::GetBool(const t_Str& szKey, const t_Str& szSection)
00455 {
00456 bool bValue = false;
00457 t_Str szValue = GetValue(szKey, szSection);
00458
00459 if ( szValue.find("1") == 0
00460 || CompareNoCase(szValue, "true") == 0
00461 || CompareNoCase(szValue, "yes") == 0 )
00462 {
00463 bValue = true;
00464 }
00465
00466 return bValue;
00467 }
00468
00469
00470
00471
00472 bool CDataFile::DeleteSection(const t_Str& szSection)
00473 {
00474 SectionItor s_pos;
00475
00476 for (s_pos = m_Sections.begin(); s_pos != m_Sections.end(); ++s_pos)
00477 {
00478 if ( CompareNoCase( (*s_pos).szName, szSection ) == 0 )
00479 {
00480 m_Sections.erase(s_pos);
00481 return true;
00482 }
00483 }
00484
00485 return false;
00486 }
00487
00488
00489
00490
00491 bool CDataFile::DeleteKey(const t_Str& szKey, const t_Str& szFromSection)
00492 {
00493 KeyItor k_pos;
00494 t_Section* pSection;
00495
00496 if ( (pSection = GetSection(szFromSection)) == NULL )
00497 return false;
00498
00499 for (k_pos = pSection->Keys.begin(); k_pos != pSection->Keys.end(); ++k_pos)
00500 {
00501 if ( CompareNoCase( (*k_pos).szKey, szKey ) == 0 )
00502 {
00503 pSection->Keys.erase(k_pos);
00504 return true;
00505 }
00506 }
00507
00508 return false;
00509 }
00510
00511
00512
00513
00514
00515
00516 bool CDataFile::CreateKey(const t_Str& szKey, const t_Str& szValue,
00517 const t_Str& szComment, const t_Str& szSection)
00518 {
00519 bool bAutoKey = (m_Flags & AUTOCREATE_KEYS) == AUTOCREATE_KEYS;
00520 bool bReturn = false;
00521
00522 m_Flags |= AUTOCREATE_KEYS;
00523
00524 bReturn = SetValue(szKey, szValue, szComment, szSection);
00525
00526 if ( !bAutoKey )
00527 m_Flags &= ~AUTOCREATE_KEYS;
00528
00529 return bReturn;
00530 }
00531
00532
00533
00534
00535
00536
00537
00538 bool CDataFile::CreateSection(const t_Str& szSection, const t_Str& szComment)
00539 {
00540 t_Section* pSection = GetSection(szSection);
00541
00542 if ( pSection )
00543 {
00544 Report(E_INFO, "[CDataFile::CreateSection] Section <%s> allready exists. Aborting.", szSection.c_str());
00545 return false;
00546 }
00547
00548 t_Section Section;
00549
00550 Section.szName = szSection;
00551 Section.szComment = szComment;
00552 m_Sections.push_back(Section);
00553 m_bDirty = true;
00554
00555 return true;
00556 }
00557
00558
00559
00560
00561
00562
00563
00564 bool CDataFile::CreateSection(const t_Str& szSection, const t_Str& szComment,
00565 const KeyList& Keys)
00566 {
00567 if ( !CreateSection(szSection, szComment) )
00568 return false;
00569
00570 t_Section* pSection = GetSection(szSection);
00571
00572 if ( !pSection )
00573 return false;
00574
00575 pSection->Keys = Keys;
00576
00577 m_bDirty = true;
00578
00579 return true;
00580 }
00581
00582
00583
00584 int CDataFile::SectionCount()
00585 {
00586 return m_Sections.size();
00587 }
00588
00589
00590
00591 int CDataFile::KeyCount()
00592 {
00593 int nCounter = 0;
00594 SectionItor s_pos;
00595
00596 for (s_pos = m_Sections.begin(); s_pos != m_Sections.end(); ++s_pos)
00597 nCounter += (*s_pos).Keys.size();
00598
00599 return nCounter;
00600 }
00601
00602
00603
00605
00606
00607
00608
00609 t_Key* CDataFile::GetKey(const t_Str& szKey, const t_Str& szSection)
00610 {
00611 KeyItor k_pos;
00612 t_Section* pSection;
00613
00614
00615
00616
00617 if ( (pSection = GetSection(szSection)) == NULL )
00618 return NULL;
00619
00620 for (k_pos = pSection->Keys.begin(); k_pos != pSection->Keys.end(); ++k_pos)
00621 {
00622 if ( CompareNoCase( (*k_pos).szKey, szKey ) == 0 )
00623 return (t_Key*)&(*k_pos);
00624 }
00625
00626 return NULL;
00627 }
00628
00629
00630
00631
00632 t_Section* CDataFile::GetSection(const t_Str& szSection)
00633 {
00634 SectionItor s_pos;
00635
00636 for (s_pos = m_Sections.begin(); s_pos != m_Sections.end(); ++s_pos)
00637 {
00638 if ( CompareNoCase( (*s_pos).szName, szSection ) == 0 )
00639 return (t_Section*)&(*s_pos);
00640 }
00641
00642 return NULL;
00643 }
00644
00645
00646 t_Str CDataFile::CommentStr(const t_Str& szComment)
00647 {
00648 t_Str szNewStr = szComment;
00649
00650 Trim(szNewStr);
00651
00652 if ( szNewStr.size() == 0 )
00653 return szNewStr;
00654
00655 if ( szNewStr.find_first_of(CommentIndicators) != 0 )
00656 {
00657 t_Str szPreStr;
00658 szPreStr += CommentIndicators[0];
00659 szPreStr += " ";
00660 szNewStr.insert(0, szPreStr);
00661 }
00662
00663 return szNewStr;
00664 }
00665
00666
00667
00668
00670
00671
00672
00673
00674
00675 t_Str GetNextWord(t_Str& CommandLine)
00676 {
00677 size_t nPos = CommandLine.find_first_of(EqualIndicators);
00678 t_Str sWord = t_Str("");
00679
00680 if ( nPos != string::npos )
00681 {
00682 sWord = CommandLine.substr(0, nPos);
00683 CommandLine.erase(0, nPos+1);
00684 }
00685 else
00686 {
00687 sWord = CommandLine;
00688 CommandLine = t_Str("");
00689 }
00690
00691 Trim(CommandLine);
00692 Trim(sWord);
00693 return sWord;
00694 }
00695
00696
00697
00698
00699
00700
00701 int CompareNoCase(const t_Str& str1, const t_Str& str2)
00702 {
00703 #ifdef WIN32
00704 return _stricmp(str1.c_str(), str2.c_str());
00705 #else
00706 return strcasecmp(str1.c_str(), str2.c_str());
00707 #endif
00708 }
00709
00710
00711
00712 void Trim(t_Str& szStr)
00713 {
00714 t_Str szTrimChars = WhiteSpace;
00715 szTrimChars += EqualIndicators;
00716
00717
00718 size_t nPos = szStr.find_first_not_of(szTrimChars);
00719 if(nPos != string::npos)
00720 {
00721 szStr.erase(0, nPos);
00722
00723 size_t rPos = szStr.find_last_not_of(szTrimChars);
00724 if (rPos != string::npos && rPos < szStr.size() - 1)
00725 szStr.erase(rPos + 1);
00726 }
00727 else
00728 {
00729 szStr.erase();
00730 }
00731 }
00732
00733
00734
00735
00736 int WriteLn(fstream& stream, const char* fmt, ...)
00737 {
00738 char buf[MAX_BUFFER_LEN];
00739 int nLength;
00740
00741 memset(buf, 0, MAX_BUFFER_LEN);
00742 va_list args;
00743
00744 va_start (args, fmt);
00745 nLength = vsnprintf(buf, MAX_BUFFER_LEN, fmt, args);
00746 va_end (args);
00747
00748
00749 if ( buf[nLength] != '\n' && buf[nLength] != '\r' )
00750 buf[nLength++] = '\n';
00751
00752
00753 stream.write(buf, nLength);
00754
00755 return nLength;
00756 }
00757
00758
00759
00760
00761
00762 void Report(e_DebugLevel DebugLevel, const char *fmt, ...)
00763 {
00764 char buf[MAX_BUFFER_LEN];
00765 int nLength;
00766 t_Str szMsg;
00767
00768 va_list args;
00769
00770 memset(buf, 0, MAX_BUFFER_LEN);
00771
00772 va_start (args, fmt);
00773 nLength = vsnprintf(buf, MAX_BUFFER_LEN, fmt, args);
00774 va_end (args);
00775
00776
00777 if ( buf[nLength] != '\n' && buf[nLength] != '\r' )
00778 buf[nLength++] = '\n';
00779
00780
00781 switch ( DebugLevel )
00782 {
00783 case E_DEBUG:
00784 szMsg = "<debug> ";
00785 break;
00786 case E_INFO:
00787 szMsg = "<info> ";
00788 break;
00789 case E_WARN:
00790 szMsg = "<warn> ";
00791 break;
00792 case E_ERROR:
00793 szMsg = "<error> ";
00794 break;
00795 case E_FATAL:
00796 szMsg = "<fatal> ";
00797 break;
00798 case E_CRITICAL:
00799 szMsg = "<critical> ";
00800 break;
00801 }
00802
00803
00804 szMsg += buf;
00805
00806
00807 #ifdef WIN32
00808 OutputDebugString(szMsg.c_str());
00809 #endif
00810
00811 printf("%s", szMsg.c_str());
00812
00813 }
00814