1 /*
   2  * Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 #include "IniFile.h"
  27 #include "Helpers.h"
  28 
  29 #include <string>
  30 
  31 
  32 IniFile::IniFile() : ISectionalPropertyContainer() {
  33 }
  34 
  35 IniFile::~IniFile() {
  36     for (OrderedMap<TString, IniSectionData*>::iterator iterator =
  37             FMap.begin(); iterator != FMap.end(); iterator++) {
  38         JPPair<TString, IniSectionData*> *item = *iterator;
  39         delete item->second;
  40     }
  41 }
  42 
  43 bool IniFile::LoadFromFile(const TString FileName) {
  44     bool result = false;
  45     Platform& platform = Platform::GetInstance();
  46 
  47     std::list<TString> contents = platform.LoadFromFile(FileName);
  48 
  49     if (contents.empty() == false) {
  50         bool found = false;
  51 
  52         // Determine the if file is an INI file or property file.
  53         // Assign FDefaultSection if it is
  54         // an INI file. Otherwise FDefaultSection is NULL.
  55         for (std::list<TString>::const_iterator iterator = contents.begin();
  56                 iterator != contents.end(); iterator++) {
  57             TString line = *iterator;
  58 
  59             if (line[0] == ';') {
  60                 // Semicolon is a comment so ignore the line.
  61                 continue;
  62             }
  63             else {
  64                 if (line[0] == '[') {
  65                     found = true;
  66                 }
  67 
  68                 break;
  69             }
  70         }
  71 
  72         if (found == true) {
  73             TString sectionName;
  74 
  75             for (std::list<TString>::const_iterator iterator = contents.begin();
  76                     iterator != contents.end(); iterator++) {
  77                 TString line = *iterator;
  78 
  79                 if (line[0] == ';') {
  80                     // Semicolon is a comment so ignore the line.
  81                     continue;
  82                 }
  83                 else if (line[0] == '[' && line[line.length() - 1] == ']') {
  84                     sectionName = line.substr(1, line.size() - 2);
  85                 }
  86                 else if (sectionName.empty() == false) {
  87                     TString name;
  88                     TString value;
  89 
  90                     if (Helpers::SplitOptionIntoNameValue(
  91                             line, name, value) == true) {
  92                         Append(sectionName, name, value);
  93                     }
  94                 }
  95             }
  96 
  97             result = true;
  98         }
  99     }
 100 
 101     return result;
 102 }
 103 
 104 bool IniFile::SaveToFile(const TString FileName, bool ownerOnly) {
 105     bool result = false;
 106 
 107     std::list<TString> contents;
 108     std::vector<TString> keys = FMap.GetKeys();
 109 
 110     for (unsigned int index = 0; index < keys.size(); index++) {
 111         TString name = keys[index];
 112         IniSectionData *section;
 113 
 114         if (FMap.GetValue(name, section) == true && section != NULL) {
 115             contents.push_back(_T("[") + name + _T("]"));
 116             std::list<TString> lines = section->GetLines();
 117             contents.insert(contents.end(), lines.begin(), lines.end());
 118             contents.push_back(_T(""));
 119         }
 120     }
 121 
 122     Platform& platform = Platform::GetInstance();
 123     platform.SaveToFile(FileName, contents, ownerOnly);
 124     result = true;
 125     return result;
 126 }
 127 
 128 void IniFile::Append(const TString SectionName,
 129         const TString Key, TString Value) {
 130     if (FMap.ContainsKey(SectionName) == true) {
 131         IniSectionData* section;
 132 
 133         if (FMap.GetValue(SectionName, section) == true && section != NULL) {
 134             section->SetValue(Key, Value);
 135         }
 136     }
 137     else {
 138         IniSectionData *section = new IniSectionData();
 139         section->SetValue(Key, Value);
 140         FMap.Append(SectionName, section);
 141     }
 142 }
 143 
 144 void IniFile::AppendSection(const TString SectionName,
 145         OrderedMap<TString, TString> Values) {
 146     if (FMap.ContainsKey(SectionName) == true) {
 147         IniSectionData* section;
 148 
 149         if (FMap.GetValue(SectionName, section) == true && section != NULL) {
 150             section->Append(Values);
 151         }
 152     }
 153     else {
 154         IniSectionData *section = new IniSectionData(Values);
 155         FMap.Append(SectionName, section);
 156     }
 157 }
 158 
 159 bool IniFile::GetValue(const TString SectionName,
 160         const TString Key, TString& Value) {
 161     bool result = false;
 162     IniSectionData* section;
 163 
 164     if (FMap.GetValue(SectionName, section) == true && section != NULL) {
 165         result = section->GetValue(Key, Value);
 166     }
 167 
 168     return result;
 169 }
 170 
 171 bool IniFile::SetValue(const TString SectionName,
 172         const TString Key, TString Value) {
 173     bool result = false;
 174     IniSectionData* section;
 175 
 176     if (FMap.GetValue(SectionName, section) && section != NULL) {
 177         result = section->SetValue(Key, Value);
 178     }
 179     else {
 180         Append(SectionName, Key, Value);
 181     }
 182 
 183 
 184     return result;
 185 }
 186 
 187 bool IniFile::GetSection(const TString SectionName,
 188         OrderedMap<TString, TString> &Data) {
 189     bool result = false;
 190 
 191     if (FMap.ContainsKey(SectionName) == true) {
 192         IniSectionData* section = NULL;
 193 
 194         if (FMap.GetValue(SectionName, section) == true && section != NULL) {
 195             OrderedMap<TString, TString> data = section->GetData();
 196             Data.Append(data);
 197             result = true;
 198         }
 199     }
 200 
 201     return result;
 202 }
 203 
 204 bool IniFile::ContainsSection(const TString SectionName) {
 205     return FMap.ContainsKey(SectionName);
 206 }
 207 
 208 //----------------------------------------------------------------------------
 209 
 210 IniSectionData::IniSectionData() {
 211     FMap.SetAllowDuplicates(true);
 212 }
 213 
 214 IniSectionData::IniSectionData(OrderedMap<TString, TString> Values) {
 215     FMap = Values;
 216 }
 217 
 218 std::vector<TString> IniSectionData::GetKeys() {
 219     return FMap.GetKeys();
 220 }
 221 
 222 std::list<TString> IniSectionData::GetLines() {
 223     std::list<TString> result;
 224     std::vector<TString> keys = FMap.GetKeys();
 225 
 226     for (unsigned int index = 0; index < keys.size(); index++) {
 227         TString name = keys[index];
 228         TString value;
 229 
 230         if (FMap.GetValue(name, value) == true) {
 231             name = Helpers::ReplaceString(name, _T("="), _T("\\="));
 232             value = Helpers::ReplaceString(value, _T("="), _T("\\="));
 233 
 234             TString line = name + _T('=') + value;
 235             result.push_back(line);
 236         }
 237     }
 238 
 239     return result;
 240 }
 241 
 242 OrderedMap<TString, TString> IniSectionData::GetData() {
 243     OrderedMap<TString, TString> result = FMap;
 244     return result;
 245 }
 246 
 247 bool IniSectionData::GetValue(const TString Key, TString& Value) {
 248     return FMap.GetValue(Key, Value);
 249 }
 250 
 251 bool IniSectionData::SetValue(const TString Key, TString Value) {
 252     return FMap.SetValue(Key, Value);
 253 }
 254 
 255 void IniSectionData::Append(OrderedMap<TString, TString> Values) {
 256     FMap.Append(Values);
 257 }
 258 
 259 size_t IniSectionData::GetCount() {
 260     return FMap.Count();
 261 }