1 /*
   2  * Copyright (c) 2015, Oracle and/or its affiliates.
   3  * All rights reserved. Use is subject to license terms.
   4  *
   5  * This file is available and licensed under the following license:
   6  *
   7  * Redistribution and use in source and binary forms, with or without
   8  * modification, are permitted provided that the following conditions
   9  * are met:
  10  *
  11  *  - Redistributions of source code must retain the above copyright
  12  *    notice, this list of conditions and the following disclaimer.
  13  *  - Redistributions in binary form must reproduce the above copyright
  14  *    notice, this list of conditions and the following disclaimer in
  15  *    the documentation and/or other materials provided with the distribution.
  16  *  - Neither the name of Oracle Corporation nor the names of its
  17  *    contributors may be used to endorse or promote products derived
  18  *    from this software without specific prior written permission.
  19  *
  20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  23  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  24  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  25  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  26  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  30  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  31  */
  32 
  33 #include "IniFile.h"
  34 #include "Helpers.h"
  35 
  36 #include <string>
  37 
  38 
  39 IniFile::IniFile() : ISectionalPropertyContainer() {
  40 }
  41 
  42 IniFile::~IniFile() {
  43     std::vector<TString> keys = FMap.GetKeys();
  44 
  45     for (size_t index = 0; index < keys.size(); index++) {
  46         TString key = keys[index];
  47 
  48         IniSectionData* item;
  49 
  50         if (FMap.GetValue(key, item) == true) {
  51             if (item != NULL) {
  52                 delete item;
  53                 item = NULL;
  54             }
  55         }
  56     }
  57 }
  58 
  59 bool IniFile::LoadFromFile(const TString FileName) {
  60     bool result = false;
  61     Platform& platform = Platform::GetInstance();
  62 
  63     std::list<TString> contents = platform.LoadFromFile(FileName);
  64 
  65     if (contents.empty() == false) {
  66         bool found = false;
  67 
  68         // Determine the if file is an INI file or property file. Assign FDefaultSection if it is
  69         // an INI file. Otherwise FDefaultSection is NULL.
  70         for (std::list<TString>::const_iterator iterator = contents.begin(); iterator != contents.end(); iterator++) {
  71             TString line = *iterator;
  72 
  73             if (line[0] == ';') {
  74                 // Semicolon is a comment so ignore the line.
  75                 continue;
  76             }
  77             else {
  78                 if (line[0] == '[') {
  79                     found = true;
  80                 }
  81 
  82                 break;
  83             }
  84         }
  85 
  86         if (found == true) {
  87             TString sectionName;
  88 
  89             for (std::list<TString>::const_iterator iterator = contents.begin(); iterator != contents.end(); iterator++) {
  90                 TString line = *iterator;
  91 
  92                 if (line[0] == ';') {
  93                     // Semicolon is a comment so ignore the line.
  94                     continue;
  95                 }
  96                 else if (line[0] == '[' && line[line.length() - 1] == ']') {
  97                     sectionName = line.substr(1, line.size() - 2);
  98                 }
  99                 else if (sectionName.empty() == false) {
 100                     TString name;
 101                     TString value;
 102 
 103                     if (Helpers::SplitOptionIntoNameValue(line, name, value) == true) {
 104                         Append(sectionName, name, value);
 105                     }
 106                 }
 107             }
 108 
 109             result = true;
 110         }
 111     }
 112 
 113     return result;
 114 }
 115 
 116 bool IniFile::SaveToFile(const TString FileName, bool ownerOnly) {
 117     bool result = false;
 118 
 119     //if (GetReadOnly() == false && IsModified()) {
 120         std::list<TString> contents;
 121         std::vector<TString> keys = FMap.GetKeys();
 122 
 123         for (unsigned int index = 0; index < keys.size(); index++) {
 124             TString name = keys[index];
 125 
 126             //try {
 127                 IniSectionData *section;// = FMap[index];
 128 
 129                 if (FMap.GetValue(name, section) == true) {
 130                     contents.push_back(_T("[") + name + _T("]"));
 131                     std::list<TString> lines = section->GetLines();
 132                     contents.insert(contents.end(), lines.begin(), lines.end());
 133                     contents.push_back(_T(""));
 134                 }
 135 //            }
 136 //            catch (std::out_of_range) {
 137 //            }
 138         }
 139 
 140         Platform& platform = Platform::GetInstance();
 141         platform.SaveToFile(FileName, contents, ownerOnly);
 142 
 143         //SetModified(false);
 144         result = true;
 145     //}
 146 
 147     return result;
 148 }
 149 
 150 void IniFile::Append(const TString SectionName, const TString Key, TString Value) {
 151     if (FMap.ContainsKey(SectionName) == true) {
 152         IniSectionData* section;
 153 
 154         if (FMap.GetValue(SectionName, section) == true && section != NULL) {
 155             section->SetValue(Key, Value);
 156         }
 157     }
 158     else {
 159         IniSectionData *section = new IniSectionData();
 160         section->SetValue(Key, Value);
 161         FMap.Append(SectionName, section);
 162     }
 163 }
 164 
 165 void IniFile::AppendSection(const TString SectionName, OrderedMap<TString, TString> Values) {
 166     if (FMap.ContainsKey(SectionName) == true) {
 167         IniSectionData* section;
 168 
 169         if (FMap.GetValue(SectionName, section) == true && section != NULL) {
 170             section->Append(Values);
 171         }
 172     }
 173     else {
 174         IniSectionData *section = new IniSectionData(Values);
 175         FMap.Append(SectionName, section);
 176     }
 177 }
 178 
 179 bool IniFile::GetValue(const TString SectionName, const TString Key, TString& Value) {
 180     bool result = false;
 181     IniSectionData* section;
 182 
 183     if (FMap.GetValue(SectionName, section) == true && section != NULL) {
 184         result = section->GetValue(Key, Value);
 185     }
 186 
 187     return result;
 188 }
 189 
 190 bool IniFile::SetValue(const TString SectionName, const TString Key, TString Value) {
 191     bool result = false;
 192     IniSectionData* section;
 193 
 194     if (FMap.GetValue(SectionName, section) && section != NULL) {
 195         result = section->SetValue(Key, Value);
 196     }
 197     else {
 198         Append(SectionName, Key, Value);
 199     }
 200 
 201 
 202     return result;
 203 }
 204 
 205 bool IniFile::GetSection(const TString SectionName, OrderedMap<TString, TString> &Data) {
 206     bool result = false;
 207 
 208     if (FMap.ContainsKey(SectionName) == true) {
 209         IniSectionData* section;
 210 
 211         if (FMap.GetValue(SectionName, section) == true && section != NULL) {
 212             OrderedMap<TString, TString> data = section->GetData();
 213             Data.Append(data);
 214         }
 215     }
 216 
 217     return result;
 218 }
 219 
 220 bool IniFile::ContainsSection(const TString SectionName) {
 221     return FMap.ContainsKey(SectionName);
 222 }
 223 
 224 //--------------------------------------------------------------------------------------------------
 225 
 226 IniSectionData::IniSectionData() {
 227 }
 228 
 229 IniSectionData::IniSectionData(OrderedMap<TString, TString> Values) {
 230     FMap = Values;
 231 }
 232 
 233 std::vector<TString> IniSectionData::GetKeys() {
 234     return FMap.GetKeys();
 235 }
 236 
 237 std::list<TString> IniSectionData::GetLines() {
 238     std::list<TString> result;
 239     std::vector<TString> keys = FMap.GetKeys();
 240 
 241     for (unsigned int index = 0; index < keys.size(); index++) {
 242         TString name = keys[index];
 243         TString value;
 244 
 245         if (FMap.GetValue(name, value) == true) {
 246             TString line = name + _T('=') + value;
 247             result.push_back(line);
 248         }
 249     }
 250 
 251     return result;
 252 }
 253 
 254 OrderedMap<TString, TString> IniSectionData::GetData() {
 255     OrderedMap<TString, TString> result = FMap;
 256     return result;
 257 }
 258 
 259 bool IniSectionData::GetValue(const TString Key, TString& Value) {
 260     return FMap.GetValue(Key, Value);
 261 }
 262 
 263 bool IniSectionData::SetValue(const TString Key, TString Value) {
 264     return FMap.SetValue(Key, Value);
 265 }
 266 
 267 void IniSectionData::Append(OrderedMap<TString, TString> Values) {
 268     FMap.Append(Values);
 269 }
 270 
 271 size_t IniSectionData::GetCount() {
 272     return FMap.Count();
 273 }