1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015
|
/* ****************************************************************************
* eID Middleware Project.
* Copyright (C) 2008-2009 FedICT.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License version
* 3.0 as published by the Free Software Foundation.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, see
* http://www.gnu.org/licenses/.
**************************************************************************** */
//
// CDataFile Class Implementation
//
// The purpose of this class is to provide a simple, full featured means to
// store persistent data to a text file. It uses a simple key/value paradigm
// to achieve this. The class can read/write to standard Windows .ini files,
// and yet does not rely on any windows specific calls. It should work as
// well in a linux environment (with some minor adjustments) as it does in
// a Windows one.
//
//
// CDataFile
// The purpose of this class is to provide the means to easily store key/value
// pairs in a config file, separated by independent sections. Sections may not
// have duplicate keys, although two or more sections can have the same key.
// Simple support for comments is included. Each key, and each section may have
// it's own multiline comment.
//
// An example might look like this;
//
// [UserSettings]
// Name=Joe User
// Date of Birth=12/25/01
//
// ;
// ; Settings unique to this server
// ;
// [ServerSettings]
// Port=1200
// IP_Address=127.0.0.1
// MachineName=ADMIN
//
#include "datafile.h"
#include "eidErrors.h"
#include "MWException.h"
#include "Thread.h"
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <float.h>
#include <iostream>
#include <sstream>
#include <errno.h>
#include <limits.h>
#ifdef WIN32
#include <windows.h>
#endif
#include "Util.h"
// Compatibility Defines ////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////
#ifdef WIN32
#define snprintf _snprintf
#define vsnprintf _vsnprintf
#else
#define _snprintf_s snprintf
#define _vsnprintf_s vsnprintf
#endif
namespace eIDMW
{
CMutex CDataFile::sm_Mutex;
// CDataFile
// Our default constructor. If it can load the file, it will do so and populate
// the section list with the values from the file.
CDataFile::CDataFile(t_Str szFileName)
{
m_stream=NULL;
m_bDirty = false;
m_szFileName = szFileName;
m_Flags = (AUTOCREATE_SECTIONS | AUTOCREATE_KEYS);
}
CDataFile::CDataFile()
{
m_stream=NULL;
m_bDirty = false;
m_szFileName = t_Str(L"");
m_Sections.clear();
m_Flags = (AUTOCREATE_SECTIONS | AUTOCREATE_KEYS);
// m_Sections.push_back( *(new t_Section) );
}
// ~CDataFile
// Saves the file if any values have changed since the last save.
CDataFile::~CDataFile()
{
Close ();
}
// SetFileName
// Set's the m_szFileName member variable. For use when creating the CDataFile
// object by hand (-vs- loading it from a file
void CDataFile::SetFileName(t_Str szFileName)
{
if(CompareNoCase(szFileName, m_szFileName) != 0)
{
Close ();
}
m_szFileName = szFileName;
}
// Load without locking just fro read
bool CDataFile::Load()
{
return Load(false);
}
// Load with locking in order to write the file
bool CDataFile::LoadAndLock()
{
return Load(true);
}
// Load
// Attempts to load in the text file. If successful it will populate the
// Section list with the key/value pairs found in the file. Note that comments
// are saved so that they can be rewritten to the file later.
bool CDataFile::Load(bool bLock)
{
if ( m_szFileName.size() == 0 )
return false;
if ( m_stream )
return true; //The file is already open => nothing to do
CAutoMutex autoMutex(&sm_Mutex);
//We come here if the file is not open yet (m_stream==NULL)
//If the file is opened, it should be locked
size_t noOfKeys = KeyCount();
size_t noOfSections = SectionCount();
int err=0;
do
{
#ifdef WIN32
err = fopen_s(&m_stream, utilStringNarrow(m_szFileName).c_str(), "r");
#else
err=0;
m_stream = fopen(utilStringNarrow(m_szFileName).c_str(), "r");
if (m_stream == NULL) err=errno;
#endif
if (err != 0 && err != EACCES && err != ENOENT ) return false; // Added for unit testing
if(err==EACCES)
{
CThread::SleepMillisecs(100);
}
else if(err==ENOENT && bLock)
{
#ifdef WIN32
err = fopen_s(&m_stream, utilStringNarrow(m_szFileName).c_str(), "w");
#else
err=0;
m_stream = fopen(utilStringNarrow(m_szFileName).c_str(), "w");
if (m_stream == NULL) err=errno;
#endif
if (err != 0 && err != EACCES && err != ENOENT ) return false;
if(m_stream)
{
fclose(m_stream);
m_stream=NULL;
err=EACCES; //To re-open the file in read mode
}
else
{
return false;
}
}
} while(err==EACCES);
//If the lock is not needed, we don't have to create the file
if(m_stream==NULL)
return false;
if(bLock)
{
#ifdef WIN32
_lock_file(m_stream); //Lock the file to avoid other process to access it
#else
// on Linux/Mac we set an advisory lock, i.e. it prevents
// other processes from using the file only if they are collaborative
// and check for the lock, otherwise they can do whatever they like ..
m_tFl.l_whence = SEEK_SET; /* SEEK_SET, SEEK_CUR, SEEK_END */
m_tFl.l_start = 0; /* Offset from l_whence */
m_tFl.l_len = 0; /* length, 0 = to EOF */
m_tFl.l_pid = getpid(); /* our PID */
m_tFl.l_type = F_RDLCK; /* F_RDLCK, F_WRLCK, F_UNLCK */
if( fcntl(fileno(m_stream), F_SETLKW, &m_tFl) == -1)
{ /* set the lock, waiting if necessary */
printf("datafile::Load: fcntl %s\n",strerror(errno));
exit(1);
}
#endif
}
bool bDone = false;
bool bAutoKey = (m_Flags & AUTOCREATE_KEYS) == AUTOCREATE_KEYS;
bool bAutoSec = (m_Flags & AUTOCREATE_SECTIONS) == AUTOCREATE_SECTIONS;
t_Str szLine;
t_Str szComment;
wchar_t buffer[MAX_BUFFER_LEN];
t_Section* pSection = GetSection(L"");
// These need to be set, we'll restore the original values later.
m_Flags |= AUTOCREATE_KEYS;
m_Flags |= AUTOCREATE_SECTIONS;
while ( !bDone )
{
memset(buffer, 0, MAX_BUFFER_LEN);
wchar_t* tmp = fgetws( buffer, MAX_BUFFER_LEN, m_stream);
tmp=tmp; // avoid warning
szLine = buffer;
Trim(szLine);
bDone = ferror( m_stream ) || feof(m_stream);
if (!bDone)
{
if ( szLine.find_first_of(CommentIndicators) == 0 )
{
szComment = L"\n";
szComment += szLine;
}
else
if ( szLine.find_first_of('[') == 0 ) // new section
{
szLine.erase( 0, 1 );
szLine.erase( szLine.find_last_of(']'), 1 );
CreateSectionInt(szLine, szComment);
pSection = GetSectionInt(szLine);
szComment = t_Str(L"");
}
else
if ( szLine.size() > 0 ) // we have a key, add this key/value pair
{
t_Str szKey = GetNextWord(szLine);
t_Str szValue = szLine;
if ( szKey.size() > 0 && szValue.size() > 0 )
{
SetValueInt(szKey, szValue, szComment, pSection == NULL ? szLine : pSection->szName);
szComment = t_Str(L"");
}
}
}
}
// Restore the original flag values.
if ( !bAutoKey )
m_Flags &= ~AUTOCREATE_KEYS;
if ( !bAutoSec )
m_Flags &= ~AUTOCREATE_SECTIONS;
if(bLock)
{
//Reopen for writing and keep open for locking
#ifdef WIN32
err = freopen_s(&m_stream, utilStringNarrow(m_szFileName).c_str(), "w",m_stream);
if (err != 0) return false;
#else
m_stream = freopen(utilStringNarrow(m_szFileName).c_str(), "w",m_stream);
if (m_stream == NULL) return false;
m_tFl.l_type = F_UNLCK; /* F_RDLCK, F_WRLCK, F_UNLCK */
if( fcntl(fileno(m_stream), F_SETLKW, &m_tFl) == -1)
{ /* set the lock, waiting if necessary */
printf("datafile::Load: fcntl %s\n",strerror(errno));
exit(1);
}
m_tFl.l_type = F_WRLCK; /* F_RDLCK, F_WRLCK, F_UNLCK */
if( fcntl(fileno(m_stream), F_SETLKW, &m_tFl) == -1)
{ /* set the lock, waiting if necessary */
printf("datafile::Load: fcntl %s\n",strerror(errno));
exit(1);
}
#endif
}
else
{
fclose(m_stream);
m_stream=NULL;
}
noOfKeys = KeyCount();
noOfSections = SectionCount();
return true;
}
// Save
// Attempts to save the Section list and keys to the file. Note that if Load
// was never called (the CDataFile object was created manually), then you
// must set the m_szFileName variable before calling save.
bool CDataFile::Save()
{
if(m_szFileName.size() == 0)
return false;
if(!m_stream)
return false;
CAutoMutex autoMutex(&sm_Mutex);
size_t noOfKeys = KeyCount();
size_t noOfSections = SectionCount();
if ( noOfKeys == 0 && noOfSections == 0 )
{
// no point in saving
return false;
}
//std::wofstream outStream(utilStringNarrow(m_szFileName).c_str());
std::wstringstream outStream(m_szFileName.c_str());
if( ! outStream) return false;
SectionItor s_pos;
KeyItor k_pos;
t_Section Section;
t_Key Key;
for (s_pos = m_Sections.begin(); s_pos != m_Sections.end(); s_pos++)
{
Section = (*s_pos);
bool bWroteComment = false;
if ( Section.szComment.size() > 0 )
{
bWroteComment = true;
outStream<<"\n"<<CommentStr(Section.szComment)<<"\n";
// WriteLn(outStream, L"\n%ls", CommentStr(Section.szComment).c_str());
}
if ( Section.szName.size() > 0 )
{
outStream<< (bWroteComment ? L"" : L"\n")<<
"["<<Section.szName.c_str()<<"]"<<"\n";
}
for (k_pos = Section.Keys.begin(); k_pos != Section.Keys.end(); k_pos++)
{
Key = (*k_pos);
if ( Key.szKey.size() > 0 && Key.szValue.size() > 0 )
{
outStream<<(Key.szComment.size() > 0 ? L"\n" : L"")
<<CommentStr(Key.szComment)
<<(Key.szComment.size() > 0 ? L"\n" : L"")
<<Key.szKey
<<EqualIndicators[0]
<<Key.szValue
<<"\n";
}
}
}
outStream.flush();
//outStream.close();
#ifdef WIN32
fprintf_s(m_stream,"%ls",outStream.str().c_str());
#else
fprintf(m_stream,"%ls",outStream.str().c_str());
#endif
#ifdef WIN32
_unlock_file(m_stream);
#else
m_tFl.l_type = F_UNLCK; /* tell it to unlock the region */
if( fcntl(fileno(m_stream), F_SETLKW, &m_tFl) == -1)
{ /* set the lock, waiting if necessary */
printf("CDataFile::Close: fcntl %s\n",strerror(errno));
exit(1);
}
#endif
fclose(m_stream);
m_stream=NULL;
m_bDirty = false;
return true;
}
bool CDataFile::Close()
{
if(m_stream)
{
return Save();
}
else
{
return false;
}
}
// SetKeyComment
// Set the comment of a given key. Returns true if the key is not found.
bool CDataFile::SetKeyComment(t_Str szKey, t_Str szComment, t_Str szSection)
{
if(!LoadAndLock())
return false;
KeyItor k_pos;
t_Section* pSection;
if ( (pSection = GetSection(szSection)) == NULL )
return false;
for (k_pos = pSection->Keys.begin(); k_pos != pSection->Keys.end(); k_pos++)
{
if ( CompareNoCase( (*k_pos).szKey, szKey ) == 0 )
{
(*k_pos).szComment = szComment;
m_bDirty = true;
return true;
}
}
return false;
}
// SetSectionComment
// Set the comment for a given section. Returns false if the section
// was not found.
bool CDataFile::SetSectionComment(t_Str szSection, t_Str szComment)
{
if(!LoadAndLock())
return false;
SectionItor s_pos;
for (s_pos = m_Sections.begin(); s_pos != m_Sections.end(); s_pos++)
{
if ( CompareNoCase( (*s_pos).szName, szSection ) == 0 )
{
(*s_pos).szComment = szComment;
m_bDirty = true;
return true;
}
}
return false;
}
// SetValue
// Given a key, a value and a section, this function will attempt to locate the
// Key within the given section, and if it finds it, change the keys value to
// the new value. If it does not locate the key, it will create a new key with
// the proper value and place it in the section requested.
bool CDataFile::SetValue(t_Str szKey, t_Str szValue, t_Str szComment, t_Str szSection)
{
if(!LoadAndLock())
return false;
return SetValueInt(szKey,szValue,szComment,szSection);
}
bool CDataFile::SetValueInt(t_Str szKey, t_Str szValue, t_Str szComment, t_Str szSection)
{
t_Key* pKey = GetKey(szKey, szSection);
t_Section* pSection = GetSectionInt(szSection);
if (pSection == NULL)
{
if ( !(m_Flags & AUTOCREATE_SECTIONS) || !CreateSectionInt(szSection,L""))
return false;
pSection = GetSectionInt(szSection);
}
// Sanity check...
if ( pSection == NULL )
return false;
// if the key does not exist in that section, and the value passed
// is not t_Str(L"") then add the new key.
if ( pKey == NULL && szValue.size() > 0 && (m_Flags & AUTOCREATE_KEYS))
{
// pKey = new t_Key;
//
// pKey->szKey = szKey;
// pKey->szValue = szValue;
// pKey->szComment = szComment;
//
// m_bDirty = true;
//
// pSection->Keys.push_back(*pKey);
//
// delete pKey;
t_Key key(szKey,szValue,szComment);
pSection->Keys.push_back(key);
m_bDirty = true;
return true;
}
if ( pKey != NULL )
{
pKey->szValue = szValue;
pKey->szComment = szComment;
m_bDirty = true;
return true;
}
return false;
}
// SetFloat
// Passes the given float to SetValue as a string
bool CDataFile::SetFloat(t_Str szKey, float fValue, t_Str szComment, t_Str szSection)
{
char szStr[64];
_snprintf_s(szStr, 64, "%f", fValue);
return SetValue(szKey, utilStringWiden(szStr), szComment, szSection);
}
// SetInt
// Passes the given int to SetValue as a string
bool CDataFile::SetInt(t_Str szKey, int nValue, t_Str szComment, t_Str szSection)
{
char szStr[64];
_snprintf_s(szStr, 64, "%d", nValue);
return SetValue(szKey, utilStringWiden(szStr), szComment, szSection);
}
// SetLong
// Passes the given long to SetValue as a string
bool CDataFile::SetLong(t_Str szKey, long nValue, t_Str szComment, t_Str szSection)
{
char szStr[64];
_snprintf_s(szStr, 64, "%ld", nValue);
return SetValue(szKey, utilStringWiden(szStr), szComment, szSection);
}
// SetBool
// Passes the given bool to SetValue as a string
bool CDataFile::SetBool(t_Str szKey, bool bValue, t_Str szComment, t_Str szSection)
{
t_Str szValue = bValue ? L"True" : L"False";
return SetValue(szKey, szValue, szComment, szSection);
}
// GetValue
// Returns the key value as a t_Str object. A return value of
// t_Str(L"") indicates that the key could not be found.
t_Str CDataFile::GetValue(t_Str szKey, t_Str szSection)
{
t_Key* pKey = GetKey(szKey, szSection);
return (pKey == NULL) ? t_Str(L"") : pKey->szValue;
}
// GetString
// Returns the key value as a t_Str object. A return value of
// t_Str(L"") indicates that the key could not be found.
t_Str CDataFile::GetString(t_Str szKey, t_Str szSection)
{
return GetValue(szKey, szSection);
}
// GetFloat
// Returns the key value as a float type. Returns FLT_MIN if the key is
// not found.
float CDataFile::GetFloat(t_Str szKey, t_Str szSection)
{
t_Str szValue = GetValue(szKey, szSection);
if ( szValue.size() == 0 )
return FLT_MIN;
return (float)atof( utilStringNarrow(szValue).c_str() );
}
// GetInt
// Returns the key value as an integer type. Returns INT_MIN if the key is
// not found.
int CDataFile::GetInt(t_Str szKey, t_Str szSection)
{
t_Str szValue = GetValue(szKey, szSection);
if ( szValue.size() == 0 )
return INT_MIN;
return atoi( utilStringNarrow(szValue).c_str() );
}
// GetLong
// Returns the key value as a long type. Returns LONG_MIN if the key is
// not found.
int CDataFile::GetLong(t_Str szKey, t_Str szSection)
{
t_Str szValue = GetValue(szKey, szSection);
if ( szValue.size() == 0 )
return LONG_MIN;
return atol( utilStringNarrow(szValue).c_str() );
}
// GetBool
// Returns the key value as a bool type. Returns false if the key is
// not found.
bool CDataFile::GetBool(t_Str szKey, t_Str szSection)
{
bool bValue = false;
t_Str szValue = GetValue(szKey, szSection);
if ( szValue.find(L"1") == 0
|| CompareNoCase(szValue, L"true")
|| CompareNoCase(szValue, L"yes") )
{
bValue = true;
}
return bValue;
}
// DeleteSection
// Delete a specific section. Returns false if the section cannot be
// found or true when sucessfully deleted.
bool CDataFile::DeleteSection(t_Str szSection)
{
if(!LoadAndLock())
return false;
SectionItor s_pos;
for (s_pos = m_Sections.begin(); s_pos != m_Sections.end(); s_pos++)
{
if ( (*s_pos).szName.size() != 0 && CompareNoCase( (*s_pos).szName, szSection ) == 0 )
{
m_Sections.erase(s_pos);
return true;
}
}
return false;
}
// DeleteKey
// Delete a specific key in a specific section. Returns false if the key
// cannot be found or true when sucessfully deleted.
bool CDataFile::DeleteKey(t_Str szKey, t_Str szFromSection)
{
if(!LoadAndLock())
return false;
KeyItor k_pos;
t_Section* pSection;
if ( (pSection = GetSection(szFromSection)) == NULL )
return false;
for (k_pos = pSection->Keys.begin(); k_pos != pSection->Keys.end(); k_pos++)
{
if ( (*k_pos).szKey.size() != 0 && CompareNoCase( (*k_pos).szKey, szKey ) == 0 )
{
pSection->Keys.erase(k_pos);
return true;
}
}
return false;
}
// CreateKey
// Given a key, a value and a section, this function will attempt to locate the
// Key within the given section, and if it finds it, change the keys value to
// the new value. If it does not locate the key, it will create a new key with
// the proper value and place it in the section requested.
bool CDataFile::CreateKey(t_Str szKey, t_Str szValue, t_Str szComment, t_Str szSection)
{
bool bAutoKey = (m_Flags & AUTOCREATE_KEYS) == AUTOCREATE_KEYS;
bool bReturn = false;
m_Flags |= AUTOCREATE_KEYS;
bReturn = SetValue(szKey, szValue, szComment, szSection);
if ( !bAutoKey )
m_Flags &= ~AUTOCREATE_KEYS;
return bReturn;
}
// CreateSection
// Given a section name, this function first checks to see if the given section
// already exists in the list or not, if not, it creates the new section and
// assigns it the comment given in szComment. The function returns true if
// successfully created, or false otherwise.
bool CDataFile::CreateSection(t_Str szSection, t_Str szComment)
{
if(!LoadAndLock())
return false;
return CreateSection(szSection,szComment);
}
bool CDataFile::CreateSectionInt(t_Str szSection, t_Str szComment)
{
t_Section* pSection = GetSectionInt(szSection);
if ( pSection )
{
return false;
}
// pSection = new t_Section;
//
// pSection->szName = szSection;
// pSection->szComment = szComment;
// m_Sections.push_back(*pSection);
//
// delete pSection;
t_Section section;
section.szName = szSection;
section.szComment = szComment;
m_Sections.push_back(section);
m_bDirty = true;
return true;
}
// CreateSection
// Given a section name, this function first checks to see if the given section
// already exists in the list or not, if not, it creates the new section and
// assigns it the comment given in szComment. The function returns true if
// successfully created, or false otherwise. This version accpets a KeyList
// and sets up the newly created Section with the keys in the list.
bool CDataFile::CreateSection(t_Str szSection, t_Str szComment, KeyList Keys)
{
if(!LoadAndLock())
return false;
if ( !CreateSection(szSection, szComment) )
return false;
t_Section* pSection = GetSection(szSection);
if ( !pSection )
return false;
KeyItor k_pos;
pSection->szName = szSection;
for (k_pos = Keys.begin(); k_pos != Keys.end(); k_pos++)
{
t_Key* pKey = new t_Key;
pKey->szComment = (*k_pos).szComment;
pKey->szKey = (*k_pos).szKey;
pKey->szValue = (*k_pos).szValue;
pSection->Keys.push_back(*pKey);
}
m_Sections.push_back(*pSection);
m_bDirty = true;
return true;
}
// SectionCount
// Simply returns the number of sections in the list.
size_t CDataFile::SectionCount()
{
return m_Sections.size();
}
// KeyCount
// Returns the total number of keys contained within all the sections.
size_t CDataFile::KeyCount()
{
size_t nCounter = 0;
SectionItor s_pos;
for (s_pos = m_Sections.begin(); s_pos != m_Sections.end(); s_pos++)
nCounter += (*s_pos).Keys.size();
return nCounter;
}
// Protected Member Functions ///////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////
// GetKey
// Given a key and section name, looks up the key and if found, returns a
// pointer to that key, otherwise returns NULL.
t_Key* CDataFile::GetKey(t_Str szKey, t_Str szSection)
{
Load();
KeyItor k_pos;
t_Section* pSection;
// Since our default section has a name value of t_Str(L"") this should
// always return a valid section, wether or not it has any keys in it is
// another matter.
if ( (pSection = GetSection(szSection)) == NULL )
return NULL;
for (k_pos = pSection->Keys.begin(); k_pos != pSection->Keys.end(); k_pos++)
{
if ( CompareNoCase( (*k_pos).szKey, szKey ) == 0 )
return (t_Key*)&(*k_pos);
}
return NULL;
}
// GetSection
// Given a section name, locates that section in the list and returns a pointer
// to it. If the section was not found, returns NULL
t_Section* CDataFile::GetSection(t_Str szSection)
{
Load();
return GetSectionInt(szSection);
}
t_Section* CDataFile::GetSectionInt(t_Str szSection)
{
SectionItor s_pos;
for (s_pos = m_Sections.begin(); s_pos != m_Sections.end(); s_pos++)
{
if ( (*s_pos).szName.size() != 0 && CompareNoCase( (*s_pos).szName, szSection ) == 0 )
return (t_Section*)&(*s_pos);
}
return NULL;
}
t_Str CDataFile::CommentStr(t_Str szComment)
{
t_Str szNewStr = t_Str(L"");
Trim(szComment);
if ( szComment.size() == 0 )
return szComment;
if ( szComment.find_first_of(CommentIndicators) != 0 )
{
szNewStr = CommentIndicators[0];
szNewStr += L" ";
}
szNewStr += szComment;
return szNewStr;
}
// Utility Functions ////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////
// GetNextWord
// Given a key +delimiter+ value string, pulls the key name from the string,
// deletes the delimiter and alters the original string to contain the
// remainder. Returns the key
t_Str GetNextWord(t_Str& CommandLine)
{
size_t nPos = CommandLine.find_first_of(EqualIndicators);
t_Str sWord = t_Str(L"");
if ( nPos > 0 )
{
sWord = CommandLine.substr(0, nPos);
CommandLine.erase(0, nPos+1);
}
else
{
sWord = CommandLine;
CommandLine = t_Str(L"");
}
Trim(sWord);
return sWord;
}
// CompareNoCase
// it's amazing what features std::string lacks. This function simply
// does a lowercase compare against the two strings, returning 0 if they
// match.
int CompareNoCase(t_Str str1, t_Str str2)
{
#ifdef WIN32
return _stricmp(utilStringNarrow(str1).c_str(), utilStringNarrow(str2).c_str());
#else
return strcasecmp(utilStringNarrow(str1).c_str(), utilStringNarrow(str2).c_str());
#endif
}
// Trim
// Trims whitespace from both sides of a string.
void Trim(t_Str& szStr)
{
t_Str szTrimChars = WhiteSpace;
szTrimChars += EqualIndicators;
size_t nPos, rPos;
// trim left
nPos = szStr.find_first_not_of(szTrimChars);
if ( nPos > 0 )
szStr.erase(0, nPos);
// trim right and return
nPos = szStr.find_last_not_of(szTrimChars) + 1;
rPos = szStr.find_last_of(szTrimChars);
if ( rPos >= nPos && rPos > 0)
{
szStr.erase(nPos, rPos);
}
}
// WriteLn
// Writes the formatted output to the file stream, returning the number of
// bytes written.
int WriteLn(FILE * stream, wchar_t* fmt, ...)
{
if(!stream)
return 0;
wchar_t buf[MAX_BUFFER_LEN];
int nLength;
t_Str szMsg;
memset(buf, 0, MAX_BUFFER_LEN);
va_list args;
va_start (args, fmt);
#ifdef WIN32
#pragma message( "*** Check parameters for vsnprintf_s() ..." __FILE__ )
nLength = _vsnwprintf_s(buf, MAX_BUFFER_LEN, MAX_BUFFER_LEN, fmt, args);
#else
nLength = vswprintf(buf, MAX_BUFFER_LEN, fmt, args);
#endif
va_end (args);
if ( buf[nLength] != '\n' && buf[nLength] != '\r' )
buf[nLength++] = '\n';
size_t tmp = fwrite(buf, sizeof( wchar_t ), nLength, stream);
tmp = tmp; // avoid warning
return nLength;
}
} // namespace eIDMW
|