/*
- suPHP - (c)2002-2005 Sebastian Marsching <sebastian@marsching.com>
+ suPHP - (c)2002-2008 Sebastian Marsching <sebastian@marsching.com>
This file is part of suPHP.
#include <string>
#include <fstream>
#include <sstream>
+#include <vector>
#include "KeyNotFoundException.hpp"
using namespace suPHP;
-IniSection& suPHP::IniFile::getSection(std::string name)
+const IniSection& suPHP::IniFile::getSection(const std::string& name) const
throw (KeyNotFoundException) {
if (this->sections.find(name) != this->sections.end()) {
- return this->sections.find(name)->second;
+ return this->sections.find(name)->second;
} else {
- throw KeyNotFoundException("Section " + name + " not found",
- __FILE__, __LINE__);
+ throw KeyNotFoundException("Section " + name + " not found",
+ __FILE__, __LINE__);
}
}
-bool suPHP::IniFile::hasSection(std::string name) {
+bool suPHP::IniFile::hasSection(const std::string& name) const {
if (this->sections.find(name) != this->sections.end()) {
- return true;
+ return true;
} else {
- return false;
+ return false;
}
}
-IniSection& suPHP::IniFile::operator[](std::string name)
+const IniSection& suPHP::IniFile::operator[](const std::string& name) const
throw (KeyNotFoundException) {
return this->getSection(name);
}
-void suPHP::IniFile::parse(File file) throw (IOException, ParsingException) {
+void suPHP::IniFile::parse(const File& file) throw (IOException, ParsingException) {
SmartPtr<std::ifstream> is = file.getInputStream();
IniSection *current_section = NULL;
while (!is->eof() && !is->bad() && !is->fail()) {
- std::string line;
- std::string tstr;
- char dummy;
- int startpos = 0;
- int endpos = 0;
-
- // Read line from file
- getline(*is, line);
-
- tstr = line;
-
- // Find first char not being space or tab
- startpos = tstr.find_first_not_of(" \t");
- // Find last char not being space or tab
- endpos = tstr.find_last_not_of(" \t");
-
- // Skip empty line, only containing whitespace
- if (startpos == std::string::npos)
- continue;
-
- // Get trimmed string
- tstr = tstr.substr(startpos, endpos - startpos + 1);
-
- // Is line a comment (starting with ";")?
- if (tstr[0] == ';') {
- // Comments are not interessting => skip
- continue;
+ std::string line;
+ std::string tstr;
+ char dummy;
+ int startpos = 0;
+ int endpos = 0;
+
+ // Read line from file
+ getline(*is, line);
+
+ tstr = line;
+
+ // Find first char not being space or tab
+ startpos = tstr.find_first_not_of(" \t");
+ // Find last char not being space or tab
+ endpos = tstr.find_last_not_of(" \t");
+
+ // Skip empty line, only containing whitespace
+ if (startpos == std::string::npos)
+ continue;
+
+ // Get trimmed string
+ tstr = tstr.substr(startpos, endpos - startpos + 1);
+
+ // Is line a comment (starting with ";")?
+ if (tstr[0] == ';') {
+ // Comments are not interessting => skip
+ continue;
// Is line a section mark ("[section]")?
- } else if (tstr[0] == '[' && tstr[tstr.size()-1] == ']') {
- // Extract name of section
- std::string name = tstr.substr(1, tstr.size() - 2);
- // If section is not yet existing, create it
- if (!this->hasSection(name)) {
- std::pair<std::string, IniSection> p;
- IniSection sect;
- p.first = name;
- p.second = sect;
- this->sections.insert(p);
- }
- // Set current section
- current_section = &(this->getSection(name));
-
- // Is the line a key-value pair?
- } else if (tstr.find_first_of('=') != std::string::npos) {
- std::string name;
- std::string value;
- int eqpos = 0;
-
- // Check wheter we already have a section
- if (current_section == NULL) {
- throw ParsingException("Option line \"" + tstr +
- "\" before first section",
- __FILE__, __LINE__);
- }
-
- // Extract name
- eqpos = tstr.find_first_of('=');
- name = tstr.substr(0, eqpos);
- value = tstr.substr(eqpos + 1, tstr.size() - eqpos + 1);
- name = name.substr(0, name.find_last_not_of(" \t") + 1);
- value = value.substr(value.find_first_not_of(" \t"));
- if (value[0] == '"')
- value = value.substr(1);
- if (value[value.size()-1] == '"')
- value = value.substr(0, value.size()-1);
- current_section->putValue(name, value);
- // Line is something we do not know
- } else {
- throw ParsingException("Illegal line \"" + tstr + "\"",
- __FILE__, __LINE__);
- }
+ } else if (tstr[0] == '[' && tstr[tstr.size()-1] == ']') {
+ // Extract name of section
+ std::string name = tstr.substr(1, tstr.size() - 2);
+ // If section is not yet existing, create it
+ if (!this->hasSection(name)) {
+ std::pair<std::string, IniSection> p;
+ IniSection sect;
+ p.first = name;
+ p.second = sect;
+ this->sections.insert(p);
+ }
+ // Set current section
+ current_section = &(this->sections.find(name)->second);
+
+ // Is the line a key-value pair?
+ } else if (tstr.find_first_of('=') != std::string::npos) {
+ std::string name;
+ std::vector<std::string> values;
+ bool append_mode = false;
+
+ int eqpos = 0;
+
+ // Check wheter we already have a section
+ if (current_section == NULL) {
+ throw ParsingException("Option line \"" + tstr +
+ "\" before first section",
+ __FILE__, __LINE__);
+ }
+
+ // Extract name
+ eqpos = tstr.find_first_of('=');
+ if (eqpos == std::string::npos || eqpos < 1 || eqpos == tstr.length()-1) {
+ throw ParsingException("Malformed line: " + tstr, __FILE__, __LINE__);
+ }
+ if (tstr[eqpos-1] == '+') {
+ append_mode = true;
+ name = tstr.substr(0, eqpos-1);
+ } else {
+ name = tstr.substr(0, eqpos);
+ }
+
+ int temppos;
+ temppos = name.find_first_not_of(" \t");
+ if (temppos == std::string::npos) {
+ throw ParsingException("Malformed line: " + tstr, __FILE__, __LINE__);
+ }
+ name = name.substr(0, name.find_last_not_of(" \t") + 1);
+
+ bool in_quotes = false;
+ bool last_was_backslash = false;
+ int token_start = eqpos + 1;
+
+ for (int i=eqpos+1; i<tstr.length(); i++) {
+ bool current_is_backslash = false;
+ if (tstr[i] == '"') {
+ if (!last_was_backslash) {
+ in_quotes = !in_quotes;
+ }
+ } else if (tstr[i] == '\\') {
+ if (!last_was_backslash) {
+ current_is_backslash = true;
+ }
+ } else if (tstr[i] == ':') {
+ if (!in_quotes && !last_was_backslash) {
+ // Save token and begin new one
+ std::string token = tstr.substr(token_start, i - token_start);
+ try {
+ token = parseValue(token);
+ } catch (ParsingException e) {
+ throw ParsingException("Malformed line: " + tstr, __FILE__, __LINE__);
+ }
+ if (token.length() == 0) {
+ throw ParsingException("Malformed line: " + tstr, __FILE__, __LINE__);
+ }
+ values.push_back(token);
+ token_start = i + 1;
+ }
+ }
+ if (i == tstr.length() - 1) {
+ if (in_quotes) {
+ throw ParsingException("Unended quotes in line: " + tstr, __FILE__, __LINE__);
+ } else if (last_was_backslash) {
+ throw ParsingException("Multiline values are not supported in line: " + tstr, __FILE__, __LINE__);
+ }
+ std::string token = tstr.substr(token_start, i + 1 - token_start);
+ try {
+ token = parseValue(token);
+ } catch (ParsingException e) {
+ throw ParsingException("Malformed line: " + tstr, __FILE__, __LINE__);
+ }
+ if (token.length() == 0) {
+ throw ParsingException("Malformed line: " + tstr, __FILE__, __LINE__);
+ }
+ values.push_back(token);
+ }
+ last_was_backslash = current_is_backslash;
+ }
+
+ if (!append_mode) {
+ current_section->removeValues(name);
+ }
+ for (std::vector<std::string>::iterator i = values.begin(); i != values.end(); i++) {
+ current_section->putValue(name, *i);
+ }
+
+ // Line is something we do not know
+ } else {
+ throw ParsingException("Malformed line \"" + tstr + "\"",
+ __FILE__, __LINE__);
+ }
}
is->close();
}
+
+std::string suPHP::IniFile::parseValue(const std::string& value) const throw (ParsingException) {
+ bool in_quotes = false;
+ bool last_was_backslash = false;
+ std::string tempvalue;
+ std::string output;
+
+ int startpos = value.find_first_not_of(" \t");
+ int endpos = value.find_last_not_of(" \t");
+ if (startpos == std::string::npos) {
+ return "";
+ }
+ if (endpos == std::string::npos) {
+ tempvalue = value;
+ } else {
+ tempvalue = value.substr(startpos, endpos - startpos + 1);
+ }
+
+ for (int i=0; i<value.length(); i++) {
+ bool current_is_backslash = false;
+
+ if (tempvalue[i] == '"') {
+ if (last_was_backslash) {
+ output.append("\"");
+ } else {
+ if (!in_quotes && i != 0) {
+ throw ParsingException("Content preceding quoted content", __FILE__, __LINE__);
+ }
+ if (in_quotes && i != tempvalue.length() - 1) {
+ throw ParsingException("Content following quoted content", __FILE__, __LINE__);
+ }
+ in_quotes = !in_quotes;
+ }
+ } else if (tempvalue[i] == '\\') {
+ if (last_was_backslash) {
+ output.append("\\");
+ } else {
+ current_is_backslash = true;
+ }
+ } else if (tempvalue[i] == ':') {
+ output.append(":");
+ } else {
+ if (last_was_backslash) {
+ throw ParsingException("Illegal character after backslash", __FILE__, __LINE__);
+ }
+ output.append(tempvalue.substr(i, 1));
+ }
+
+ last_was_backslash = current_is_backslash;
+ }
+
+ return output;
+}