mirror of
https://github.com/DaedalusX64/daedalus.git
synced 2025-04-02 10:21:48 -04:00
437 lines
11 KiB
C++
437 lines
11 KiB
C++
/*
|
|
Copyright (C) 2001 CyRUS64 (http://www.boob.co.uk)
|
|
Copyright (C) 2006 StrmnNrmn
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU General Public License
|
|
as published by the Free Software Foundation; either version 2
|
|
of the License, or (at your option) any later version.
|
|
|
|
This program 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 General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
|
*/
|
|
|
|
|
|
#include "Base/Types.h"
|
|
|
|
|
|
#include <cstring>
|
|
#include <vector>
|
|
#include <map>
|
|
#include <algorithm>
|
|
#include <fstream>
|
|
#include <iostream>
|
|
|
|
|
|
#include "Utility/IniFile.h"
|
|
#include "Utility/StringUtil.h"
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//*****************************************************************************
|
|
class IIniFileProperty : public CIniFileProperty
|
|
{
|
|
public:
|
|
IIniFileProperty( const char * p_name, const char * p_value )
|
|
: mName( p_name )
|
|
, mValue( p_value )
|
|
{
|
|
}
|
|
|
|
virtual const char * GetName() const { return mName.c_str(); }
|
|
virtual const char * GetValue() const { return mValue.c_str(); }
|
|
|
|
virtual bool GetBooleanValue( bool default_value ) const
|
|
{
|
|
const char * str( mValue.c_str() );
|
|
|
|
if( strcasecmp( str, "yes" ) == 0 ||
|
|
strcasecmp( str, "true" ) == 0 ||
|
|
strcasecmp( str, "1" ) == 0 ||
|
|
strcasecmp( str, "on" ) == 0 )
|
|
{
|
|
return true;
|
|
}
|
|
if( strcasecmp( str, "no" ) == 0 ||
|
|
strcasecmp( str, "false" ) == 0 ||
|
|
strcasecmp( str, "0" ) == 0 ||
|
|
strcasecmp( str, "off" ) == 0 )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return default_value;
|
|
}
|
|
|
|
virtual int GetIntValue( int default_value ) const
|
|
{
|
|
int value;
|
|
|
|
if( sscanf( mValue.c_str(), "%d", &value ) != 1 )
|
|
{
|
|
value = default_value;
|
|
}
|
|
return value;
|
|
}
|
|
|
|
virtual float GetFloatValue( float default_value ) const
|
|
{
|
|
float value;
|
|
|
|
if( sscanf( mValue.c_str(), "%f", &value ) != 1 )
|
|
{
|
|
value = default_value;
|
|
}
|
|
return value;
|
|
}
|
|
|
|
private:
|
|
friend class IIniFileSection;
|
|
std::string mName;
|
|
std::string mValue;
|
|
};
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//*****************************************************************************
|
|
CIniFileProperty::~CIniFileProperty()
|
|
{
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//*****************************************************************************
|
|
class IIniFileSection : public CIniFileSection
|
|
{
|
|
public:
|
|
IIniFileSection( const char * p_name )
|
|
: mName( p_name )
|
|
{
|
|
}
|
|
|
|
~IIniFileSection();
|
|
|
|
|
|
virtual const char * GetName() const { return mName.c_str(); }
|
|
virtual bool FindProperty( const char * p_name, const CIniFileProperty ** p_property ) const;
|
|
|
|
void AddProperty( const IIniFileProperty * p_property );
|
|
|
|
private:
|
|
|
|
using PropertyVec = std::vector< const IIniFileProperty*>;
|
|
|
|
struct SCompareProperties
|
|
{
|
|
bool operator()( const IIniFileProperty * a, const IIniFileProperty * b ) const
|
|
{
|
|
return strcmp( a->mName.c_str(), b->mName.c_str() ) < 0;
|
|
}
|
|
bool operator()( const char * a, const IIniFileProperty * b ) const
|
|
{
|
|
return strcmp( a, b->mName.c_str() ) < 0;
|
|
}
|
|
bool operator()( const IIniFileProperty * a, const char * b ) const
|
|
{
|
|
return strcmp( a->mName.c_str(), b ) < 0;
|
|
}
|
|
};
|
|
|
|
std::string mName;
|
|
PropertyVec mProperties;
|
|
};
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//*****************************************************************************
|
|
CIniFileSection::~CIniFileSection()
|
|
{
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//*****************************************************************************
|
|
IIniFileSection::~IIniFileSection()
|
|
{
|
|
for( u32 i = 0; i < mProperties.size(); ++i )
|
|
{
|
|
delete mProperties[ i ];
|
|
}
|
|
|
|
mProperties.clear();
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//*****************************************************************************
|
|
bool IIniFileSection::FindProperty( const char * p_name, const CIniFileProperty ** p_property ) const
|
|
{
|
|
PropertyVec::const_iterator it( std::lower_bound( mProperties.begin(), mProperties.end(), p_name, SCompareProperties() ) );
|
|
if( it != mProperties.end() && strcmp( (*it)->mName.c_str(), p_name ) == 0 )
|
|
{
|
|
*p_property = *it;
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
*p_property = NULL;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
//*****************************************************************************
|
|
// Once added, this class takes responsibility for deleting the property
|
|
//*****************************************************************************
|
|
void IIniFileSection::AddProperty( const IIniFileProperty * p_property )
|
|
{
|
|
PropertyVec::iterator it( std::lower_bound( mProperties.begin(), mProperties.end(), p_property->GetName(), SCompareProperties() ) );
|
|
#ifdef DAEDALUS_ENABLE_ASSERTS
|
|
DAEDALUS_ASSERT( it == mProperties.end() || strcmp( (*it)->mName.c_str(), p_property->GetName() ) != 0, "This property already exists" );
|
|
#endif
|
|
mProperties.insert( it, p_property );
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//*****************************************************************************
|
|
class IIniFile : public CIniFile
|
|
{
|
|
public:
|
|
IIniFile();
|
|
virtual ~IIniFile();
|
|
|
|
//
|
|
// CIniFile implementation
|
|
//
|
|
virtual bool Open( const std::filesystem::path &filename );
|
|
|
|
virtual const CIniFileSection * GetDefaultSection() const;
|
|
|
|
virtual u32 GetNumSections() const;
|
|
virtual const CIniFileSection * GetSection( u32 section_idx ) const;
|
|
|
|
virtual const CIniFileSection * GetSectionByName( const char * section_name ) const;
|
|
|
|
private:
|
|
IIniFileSection * mpDefaultSection;
|
|
|
|
std::vector<IIniFileSection *> mSections;
|
|
};
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//*****************************************************************************
|
|
CIniFile::~CIniFile()
|
|
{
|
|
}
|
|
|
|
//*****************************************************************************
|
|
// Constructor
|
|
//*****************************************************************************
|
|
IIniFile::IIniFile()
|
|
: mpDefaultSection( NULL )
|
|
{
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//*****************************************************************************
|
|
IIniFile::~IIniFile()
|
|
{
|
|
delete mpDefaultSection;
|
|
|
|
for( u32 i = 0; i < mSections.size(); ++i )
|
|
{
|
|
delete mSections[ i ];
|
|
mSections[ i ] = NULL;
|
|
}
|
|
}
|
|
|
|
//*****************************************************************************
|
|
// Remove the specified characters from p_string
|
|
//*****************************************************************************
|
|
static bool trim( char * p_string, const char * p_trim_chars )
|
|
{
|
|
u32 num_trims = strlen( p_trim_chars );
|
|
char * pin = p_string;
|
|
char * pout = p_string;
|
|
bool found;
|
|
while ( *pin )
|
|
{
|
|
char c = *pin;
|
|
|
|
found = false;
|
|
for ( u32 i = 0; i < num_trims; i++ )
|
|
{
|
|
if ( p_trim_chars[ i ] == c )
|
|
{
|
|
// Skip
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( found )
|
|
{
|
|
pin++;
|
|
}
|
|
else
|
|
{
|
|
// Copy
|
|
*pout++ = *pin++;
|
|
}
|
|
}
|
|
*pout = '\0';
|
|
return true;
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//*****************************************************************************
|
|
std::unique_ptr<CIniFile> CIniFile::Create( const std::filesystem::path &filename )
|
|
{
|
|
auto p_file = std::make_unique<IIniFile>();
|
|
|
|
if( p_file != NULL )
|
|
{
|
|
if( p_file->Open( filename ) )
|
|
{
|
|
return p_file;
|
|
}
|
|
|
|
// delete p_file;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//*****************************************************************************
|
|
bool IIniFile::Open( const std::filesystem::path &filename )
|
|
{
|
|
const u32 BUFFER_LEN = 1024;
|
|
char readinfo[BUFFER_LEN+1];
|
|
const char trim_chars[]="{}[]"; //remove first and last character
|
|
std::ifstream inifile(filename);
|
|
|
|
if (!inifile)
|
|
{
|
|
std::cerr << "INI File: " << filename << " not found" << std::endl;
|
|
return false;
|
|
}
|
|
std::cout << "Loading INI File: " << filename << std::endl;
|
|
|
|
//
|
|
// By default start with the default section
|
|
//
|
|
mpDefaultSection = new IIniFileSection( "" );
|
|
IIniFileSection * p_current_section = mpDefaultSection;
|
|
readinfo[BUFFER_LEN] = '\0';
|
|
|
|
std::string line;
|
|
while (std::getline(inifile, line))
|
|
{
|
|
std::strncpy(readinfo, line.c_str(), BUFFER_LEN);
|
|
readinfo[BUFFER_LEN] = '\0';
|
|
|
|
Tidy(readinfo); // Strip Spaces from end of line
|
|
|
|
// Handle Comments
|
|
if (readinfo[0] == '/')
|
|
continue;
|
|
|
|
// Check that line isn't empty
|
|
if (*readinfo != 0 )
|
|
{
|
|
if (readinfo[0] == '{' || readinfo[0] == '[')
|
|
{
|
|
trim(readinfo, trim_chars);
|
|
|
|
p_current_section = new IIniFileSection(readinfo);
|
|
mSections.push_back(p_current_section);
|
|
}
|
|
else
|
|
{
|
|
char* key;
|
|
char* value;
|
|
char* equals_idx = std::strchr(readinfo, '=');
|
|
if( equals_idx != NULL)
|
|
{
|
|
*equals_idx = '\0';
|
|
key = &readinfo[0];
|
|
value = equals_idx+1;
|
|
}
|
|
else
|
|
{
|
|
key = &readinfo[0];
|
|
value = NULL;
|
|
}
|
|
Tidy( key );
|
|
Tidy( value );
|
|
#ifdef DAEDALUS_ENABLE_ASSERTS
|
|
DAEDALUS_ASSERT( p_current_section != NULL, "There is no current section" );
|
|
#endif
|
|
IIniFileProperty * p_property( new IIniFileProperty( key, value ) );
|
|
|
|
p_current_section->AddProperty( p_property );
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//*****************************************************************************
|
|
const CIniFileSection * IIniFile::GetDefaultSection() const
|
|
{
|
|
return mpDefaultSection;
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//*****************************************************************************
|
|
u32 IIniFile::GetNumSections() const
|
|
{
|
|
return mSections.size();
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//*****************************************************************************
|
|
const CIniFileSection * IIniFile::GetSection( u32 section_idx ) const
|
|
{
|
|
if( section_idx < mSections.size() )
|
|
{
|
|
return mSections[ section_idx ];
|
|
}
|
|
#ifdef DAEDALUS_DEBUG_CONSOLE
|
|
DAEDALUS_ERROR( "Invalid section index" );
|
|
#endif
|
|
return NULL;
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//*****************************************************************************
|
|
const CIniFileSection * IIniFile::GetSectionByName( const char * section_name ) const
|
|
{
|
|
// TODO: Could use a map for this if it starts to prove expensive
|
|
for( u32 i = 0; i < mSections.size(); ++i )
|
|
{
|
|
if( strcmp( mSections[ i ]->GetName(), section_name ) == 0 )
|
|
{
|
|
return mSections[ i ];
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|