• Main Page
  • Related Pages
  • Modules
  • Namespaces
  • Classes
  • Files
  • File List
  • File Members

src/ConfigurationSettings.cpp

00001 /*
00002  *   This file is part of the Standard Portable Library (SPL).
00003  *
00004  *   SPL is free software: you can redistribute it and/or modify
00005  *   it under the terms of the GNU General Public License as published by
00006  *   the Free Software Foundation, either version 3 of the License, or
00007  *   (at your option) any later version.
00008  *
00009  *   SPL 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.  See the
00012  *   GNU General Public License for more details.
00013  *
00014  *   You should have received a copy of the GNU General Public License
00015  *   along with SPL.  If not, see <http://www.gnu.org/licenses/>.
00016  */
00017 #include <spl/configuration/ConfigurationSettings.h>
00018 #include <spl/Environment.h>
00019 #include <spl/Exception.h>
00020 #include <spl/text/StringBuffer.h>
00021 #include <spl/xml/XmlElement.h>
00022 
00023 #ifdef _WINDOWS
00024 #include <spl/configuration/windows/WinRegKey.h>
00025 #endif
00026 
00027 ConfigurationSettings::ConfigurationSettings()
00028 : m_sections(), m_filename()
00029 {
00030 }
00031 
00032 ConfigurationSettings::ConfigurationSettings(const String& filename)
00033 : m_sections(), m_filename()
00034 {
00035         Load(filename);
00036 }
00037 
00038 ConfigurationSettings::ConfigurationSettings(const ConfigurationSettings& config)
00039 : m_filename(config.m_filename), m_sections(config.m_sections)
00040 {
00041 }
00042 
00043 ConfigurationSettings::~ConfigurationSettings()
00044 {
00045 }
00046 
00047 ConfigurationSettings& ConfigurationSettings::operator =(const ConfigurationSettings& config)
00048 {
00049         m_filename = config.m_filename;
00050         m_sections = config.m_sections;
00051 
00052         return *this;
00053 }
00054 
00055 ConfigurationSection& ConfigurationSettings::Section(const String& name)
00056 {
00057         if (! m_sections.ContainsKey(name))
00058         {
00059                 m_sections.Set(name, ConfigurationSection(name));
00060         }
00061         return m_sections.GetRef(name);
00062 }
00063 
00064 void ConfigurationSettings::Load(const String& filename)
00065 {
00066         m_filename = filename;
00067         if ( m_filename.EndsWith(".ini") )
00068         {
00069                 TextReader reader(File::OpenText(filename));
00070                 DelimitedFilePtr ini = DelimitedFile::Parse(reader, '=');
00071                 Load(ini);
00072                 return;
00073         }
00074         else if ( m_filename.EndsWith( ".config" ) || m_filename.EndsWith( ".xml" ) )
00075         {
00076                 XmlDocumentPtr doc = XmlDocument::Parse(filename);
00077                 Load(doc);
00078                 return;
00079         }
00080         else
00081         {
00082                 throw new ConfigurationException("Unknown file type.");
00083         }
00084 }
00085 
00086 void ConfigurationSettings::Load(XmlDocument& appconfig)
00087 {
00088         m_sections.Clear();
00089 
00090         XmlElementPtr config = appconfig.RootElement();
00091         if ( config.IsNull() || ! config->Name().Equals("configuration") )
00092         {
00093                 throw new InvalidArgumentException("Invalid file format, expected <configuration>");
00094         }
00095         
00096         XmlNodePtr section = config->FirstChildElement();
00097         while(section.IsNotNull())
00098         {
00099                 XmlElementPtr node = section->FirstChildElement();
00100                 while ( node.IsNotNull() )
00101                 {
00102                         if (! node->Name().Equals("add"))
00103                         {
00104                                 throw new InvalidArgumentException("Expected <add> tag.");
00105                         }
00106 
00107                         XmlAttributePtr keynode = node->Attribute("key");
00108                         XmlAttributePtr valnode = node->Attribute("value");
00109 
00110                         if ( keynode.IsNull() || valnode.IsNull() )
00111                         {
00112                                 throw new InvalidArgumentException("Malformed <add> tag.");
00113                         }
00114 
00115                         StringPtr key = keynode->Value();
00116                         StringPtr val = valnode->Value();
00117 
00118                         Section(section->Name()).Set(*key, *val);
00119                         
00120                         node = node->NextSiblingElement();
00121                 }
00122 
00123                 section = section->NextSibling();
00124         }
00125 }
00126 
00127 void ConfigurationSettings::Load(const DelimitedFile& inifile)
00128 {
00129         m_sections.Clear();
00130 
00131         String section;
00132 
00133         for ( int r = 0; r < inifile.RowCount(); r++ )
00134         {
00135                 DataRowPtr row = inifile.RowAt(r);
00136                 if ( row->Count() == 0 )
00137                 {
00138                         continue;
00139                 }
00140                 StringPtr key = row->Cell(0)->ToString();
00141                 if (key->StartsWith('['))
00142                 {
00143                         //Section name
00144                         section = *key->Mid(1, key->Length() - 1);
00145                         ASSERT(! section.EndsWith(']'));
00146                         Section(section);
00147                         continue;
00148                 }
00149                 if ( row->Count() == 1 )
00150                 {
00151                         Section(section).Set(*key, String(""));
00152                 }
00153                 else if ( row->Count() == 2 )
00154                 {
00155                         Section(section).Set(*key, row->Cell(1)->ToString());
00156                 }
00157                 else
00158                 {
00159                         throw new InvalidArgumentException("Invalid file format, too many columns.");
00160                 }
00161         }
00162 }
00163 
00164 bool ConfigurationSettings::ContainsKey(const String& section, const String& key)
00165 {
00166         return Section(section).ContainsKey(key);
00167 }
00168 
00169 void ConfigurationSettings::Add(const String& section, const String& key, const String& value)
00170 {
00171         Section(section).Set(key, value);
00172 }
00173 
00174 StringPtr ConfigurationSettings::Value(const String& section, const String& key)
00175 {
00176         if ( ! m_sections.ContainsKey(section) )
00177         {
00178                 m_sections.Set(section, ConfigurationSection(section));
00179         }
00180         return m_sections.Get(section).Value(key);
00181 }
00182 
00183 List<StringPtr>& ConfigurationSettings::Values(const String& section, const String& key)
00184 {
00185         if ( ! m_sections.ContainsKey(section) )
00186         {
00187                 m_sections.Set(section, ConfigurationSection(section));
00188         }
00189         return m_sections.Get(section).Values(key);
00190 }
00191 
00192 StringPtr ConfigurationSettings::ToXmlString()
00193 {
00194         StringBuffer xml("<?xml version=\"1.0\"?>\n<configuration>\n");
00195 
00196         for (Hashtable<String, ConfigurationSection>::Iterator iter(m_sections.Begin()); iter.Next(); )
00197         {
00198                 xml.Append(iter.CurrentRef().ToXmlString());
00199         }
00200 
00201         xml.Append("</configuration>\n");
00202         return xml.ToString();
00203 }
00204 
00205 StringPtr ConfigurationSettings::ToIniString()
00206 {
00207         StringBuffer ini;
00208         for (Hashtable<String, ConfigurationSection>::Iterator iter(m_sections.Begin()); iter.Next(); )
00209         {
00210                 ini.Append(iter.CurrentRef().ToIniString());
00211         }
00212         return ini.ToString();
00213 }
00214 
00215 ConfigurationSettingsPtr ConfigurationSettings::LoadAppConfig()
00216 {
00217         ConfigurationSettingsPtr cfgp;
00218         String processName = Environment::ProcessName();
00219 
00220 #ifdef _WINDOWS
00221 
00222         // try the registery
00223         String path("Software\\SPL\\" + Environment::ProcessName());
00224         
00225         if (WinRegKey::KeyExists(WinRegKey::HiveLocalMachine, path))
00226         {
00227                 WinRegKey key(path, WinRegKey::HiveLocalMachine);
00228                 List<WinRegKey> sections(key.ListSubKeys());
00229                 
00230                 for(List<WinRegKey>::Iterator iter(sections.Begin()); iter.Next(); )
00231                 {
00232                         String sectionName(iter.CurrentRef().KeyName());
00233                         List<WinRegKey> subKeys(iter.CurrentRef().ListSubKeys());
00234                         
00235                         for(List<WinRegKey>::Iterator iterSub(subKeys.Begin()); iterSub.Next(); )
00236                         {
00237                                 cfgp->Add(sectionName, iterSub.CurrentRef().KeyName(), iterSub.CurrentRef().Value());
00238                         }
00239                 }
00240                 return cfgp;
00241         }
00242 
00243 #endif
00244 
00245         if (File::Exists(processName + ".ini"))
00246         {
00247                 cfgp = new ConfigurationSettings();
00248                 cfgp->Load(processName + ".ini");
00249         }
00250         else if (File::Exists(processName + ".xml"))
00251         {
00252                 cfgp = new ConfigurationSettings();
00253                 cfgp->Load(processName + ".xml");
00254         }
00255         
00256         return cfgp;
00257 }
00258 
00259 void ConfigurationSettings::SaveToIniFile(const String& filename)
00260 {
00261         ASSERT(filename.EndsWith(".ini"));
00262         
00263         if (File::Exists(filename))
00264         {
00265                 File::Delete(filename);
00266         }
00267         
00268         TextWriterPtr writer(File::CreateText(filename));
00269         
00270         for(Hashtable<String, ConfigurationSection>::Iterator iter(m_sections.Begin()); iter.Next(); )
00271         {
00272                 writer->Write(iter.CurrentRef().ToIniString());
00273         }
00274         
00275         writer->Close();
00276 }
00277 
00278 void ConfigurationSettings::SaveToXmlFile(const String& filename)
00279 {
00280         ASSERT(filename.EndsWith(".xml"));
00281 
00282         if (File::Exists(filename))
00283         {
00284                 File::Delete(filename);
00285         }
00286         
00287         TextWriterPtr writer(File::CreateText(filename));
00288         
00289         for(Hashtable<String, ConfigurationSection>::Iterator iter(m_sections.Begin()); iter.Next(); )
00290         {
00291                 writer->Write(iter.CurrentRef().ToXmlString());
00292         }
00293         
00294         writer->Close();
00295 }
00296 
00297 void ConfigurationSettings::SaveToRegistry()
00298 {
00299 #ifndef _WINDOWS
00300         throw new Exception("Not supported");
00301 #else
00302         String path("Software\\SPL\\" + Environment::ProcessName());
00303         if (!WinRegKey::KeyExists(WinRegKey::HiveLocalMachine, path))
00304         {
00305                 WinRegKey::Create(WinRegKey::HiveLocalMachine, path);
00306         }
00307         
00308         WinRegKey rootKey(path, WinRegKey::HiveLocalMachine);
00309         rootKey.OpenForReadWrite();
00310         
00311         for(Hashtable<String, ConfigurationSection>::Iterator iter(m_sections.Begin()); iter.Next(); )
00312         {
00313                 // create section key
00314                 String sectionPath = path + "\\" + iter.CurrentKeyRef();
00315                 WinRegKey sectionKey(WinRegKey::Create(WinRegKey::HiveLocalMachine, sectionPath));
00316                 sectionKey.OpenForReadWrite();
00317                 
00318                 for (Hashtable<String, List<StringPtr> >::Iterator viter(iter.CurrentRef().Begin()); viter.Next(); )
00319                 {
00320                         for (List<StringPtr>::Iterator liter(viter.CurrentRef().Begin()); liter.Next(); )
00321                         {
00322                                 sectionKey.SetSubKey(viter.CurrentKeyRef(), liter.CurrentRef());
00323                         }
00324                 }
00325                 sectionKey.Close();
00326         }
00327                 
00328         rootKey.Close();
00329 #endif
00330 }
00331 
00332 #ifdef DEBUG
00333 void ConfigurationSettings::ValidateMem() const
00334 {
00335         m_sections.ValidateMem();
00336         m_filename.ValidateMem();
00337 }
00338 
00339 void ConfigurationSettings::CheckMem() const
00340 {
00341         m_sections.CheckMem();
00342         m_filename.CheckMem();
00343 }
00344 #endif