Ejemplo n.º 1
0
int MIniFile::FindSection(const char *sectionName)
{
	IniSection* pSection = 0;
	for(int i = 0; i != m_SectionList.size(); ++i)
	{
		pSection = m_SectionList[i];
		if(0 == pSection)
			continue;

		if(0 == strcmp(pSection->GetSectionName(),sectionName ))
		{
			return i;
		}
	}

	return -1;
}
Ejemplo n.º 2
0
IniKey* MIniFile::GetNextKey(const char* currentSectionName,const char* currentKeyName)
{
	IniSection* pSection = GetSection(currentSectionName);

	if (pSection != NULL)
	{

		IniKey* pKey = pSection->GetNextKey(currentKeyName);

		if (pKey != NULL)
		{
			return pKey;
		}
	}

	return 0;
}
Ejemplo n.º 3
0
int IniFile::setValue(const string &section, const string &key, const string &value, const string &comment /*=""*/)
{
    IniSection *sect = getSection(section);

    string comt = comment;

    if (comt != "") {
        comt = commentHead + comt;
    }

    if (sect == NULL) {
        //如果段不存在,新建一个
        sect = new IniSection();

        if (sect == NULL) {
            fprintf(stderr, "no enough memory!\n");
            exit(-1);
        }

        sect->name = section;
        if (sect->name == "") {
            // 确保空section在第一个
            sections_vt.insert(sections_vt.begin(), sect);
        } else {
            sections_vt.push_back(sect);
        }
    }

    for (IniSection::IniItem_it it = sect->begin(); it != sect->end(); ++it) {
        if (it->key == key) {
            it->value = value;
            it->comment = comt;
            return RET_OK;
        }
    }

    // not found key
    IniItem item;
    item.key = key;
    item.value = value;
    item.comment = comt;

    sect->items.push_back(item);

    return RET_OK;
}
Ejemplo n.º 4
0
bool IniFile::Save(){
  if (filename.isEmpty()) return false;
  file.setName(filename);
  if (! file.open(QIODevice::WriteOnly)){
#ifdef DEBUG
    cerr << "\nCannot write File: " << filename.latin1();
#else

#endif
    return false;
  }

  IniSection* section;
  IniVar* var;
  QString line;

  // Durchgehen und alles reinschreiben
  file.writeBlock(comment.latin1(),comment.length());
  for(section=sections.first();section!=0;section=sections.next()){
    line="\n[";
    line.append(section->getName());
    line.append("]\n");
    file.writeBlock(line.latin1(),line.length());
    line=section->getComment();
    if (!line.isEmpty()) {
      line += "\n";
      file.writeBlock(line.latin1(),line.length());
    }
    for(var=section->vars.first();var!=0;var=section->vars.next()){
      line=var->getName();
      if (! var->getValue().isEmpty()){
        line.append("=");
        line.append(var->getValue());
        line.append(var->getComment());
//      }else{
        line.append("\n");
      }
      file.writeBlock(line.latin1(),line.length());
    }
  }

  file.close();

  return true;
}
Ejemplo n.º 5
0
void CNrpHUDConfig::Load( const NrpText& fileName )
{
    INrpConfig::Load( fileName );

    IniFile rv( fileName );

    IniSection* fonts = rv.GetSection( SECTION_FONTS );
   
    assert( fonts );
    if( fonts )
    {
        const IniSection::KeyIndexA& keys = fonts->GetKeys();
        for( IniSection::KeyIndexA::const_iterator pIter = keys.begin();
             pIter != keys.end(); pIter++ )
             RegProperty<NrpText>( (*pIter)->GetShortKey().c_str(), (*pIter)->GetValue().c_str() );
    }
    else
        Log( HW ) << "Can't find section \"fonts\" in " << fileName << term;
}
Ejemplo n.º 6
0
bool IniFile::getSection(IniSection& _section,QString _name,bool _next){
  static QString lastname;
  IniSection* sec;
  if (_next==false || (_next==true && _name!=lastname) ) {
    lastname ="";
    sec=sections.first();

  }else{
    sec=sections.next();
  }

  lastname=_name;

  for(;sec!=0;sec=sections.next()){
      if (sec->getName()==_name){  // gefunden
        sec->copy(_section);
        return true;
      }
  }
  return false;
}
Ejemplo n.º 7
0
int IniFile::setValue(const string &section,const string &key,
					  const string &value,const string &comment /*=""*/)
{
	IniSection * sect = getSection(section);
	
	string comt = comment;
	if (comt != ""){
		comt = flags_[0] +comt;
	} 
	if(sect == NULL){
		sect = new IniSection();
		if(sect == NULL){
			fprintf(stderr,"no enough memory!\n");
			exit(-1);
		}
		sect->name = section;
		sections_[section] = sect;
	}
	
	for(IniSection::iterator it = sect->begin(); it != sect->end(); ++it){
		if(it->key == key){
			it->value = value;
			it->comment = comt;
			return RET_OK;
		}
	}

	//not found key
	IniItem item;
	item.key = key;
	item.value = value;
	item.comment = comt;

	sect->items.push_back(item);

	return RET_OK;

}
Ejemplo n.º 8
0
int IniFile::GetValues(const string &section, const string &key, vector<string> *values, vector<string> *comments)
{
    string value, comment;

    values->clear();
    comments->clear();

    IniSection *sect = getSection(section);

    if (sect != NULL) {
        for (IniSection::IniItem_it it = sect->begin(); it != sect->end(); ++it) {
            if (it->key == key) {
                value = it->value;
                comment = it->comment;

                values->push_back(value);
                comments->push_back(comment);
            }
        }
    }

    return (values->size() ? RET_OK : RET_ERR);
}
Ejemplo n.º 9
0
//向一个节中添加一个键,若没有这个节则新建一个节
int MIniFile::SetValue(const char* sectionName,const char* keyName,const char* value)
{
	IniSection* pSection = GetSection(sectionName);

	if (pSection != NULL)
	{
		IniKey* pKey = GetKey(sectionName,keyName);

		LineInfo* pLineInfo =NULL;

		if (pKey != NULL)
		{
			pKey->SetValue(value);
			pLineInfo =  FindLineInfo(pKey->m_nLineNo);

		}
		else
		{
			IniKey* pLastKey = pSection->GetLastKey();

			pKey = new IniKey(pSection);
			pSection->AddKey(pKey);
			pKey->SetKeyName(keyName);
			pKey->SetValue(value);

			if (pLastKey == NULL)
			{
				//该节没有键值对
				pKey->m_nLineNo = pSection->m_nLineNo + 1;
			}
			else
			{
				pKey->m_nLineNo = pLastKey->m_nLineNo+1;
			}

			pSection->m_nKeyCount++;
			pLineInfo = new LineInfo;
			pLineInfo->type = LINE_KEYPAIR;
			pLineInfo->nLineNo = pKey->m_nLineNo;

			AdjustAllLineInfo(pLineInfo);
		}

		pLineInfo->strMainData = "\t";
		pLineInfo->strMainData += pKey->m_Key;
		pLineInfo->strMainData += "\t=\t";
		pLineInfo->strMainData += pKey->m_Value;


	}
	else
	{
		//新增节和键
		pSection = new IniSection;
		IniKey* pKey = new IniKey(pSection);

		LineInfo* pSectionLineInfo = new LineInfo;
		LineInfo* pKeyLineInfo = new LineInfo;

		pSection->SetSectionName(sectionName);
		pKey->SetKeyName(keyName);
		pKey->SetValue(value);

		pSection->AddKey(pKey);

		pSection->m_nLineNo = m_nLineCount;
		pKey->m_nLineNo = m_nLineCount + 1;

		pSectionLineInfo->nLineNo = pSection->m_nLineNo;
		pSectionLineInfo->strMainData = "[";
		pSectionLineInfo->strMainData += sectionName;
		pSectionLineInfo->strMainData += "]";

		pKeyLineInfo->nLineNo = pKey->m_nLineNo;
		pKeyLineInfo->strMainData = "\t";
		pKeyLineInfo->strMainData += pKey->m_Key;
		pKeyLineInfo->strMainData += "\t=\t";
		pKeyLineInfo->strMainData += pKey->m_Value;

		AdjustAllLineInfo(pSectionLineInfo);
		AdjustAllLineInfo(pKeyLineInfo);

		AddSection(pSection);
	}

	m_bChange = true;

	return 0;
}
Ejemplo n.º 10
0
void MIniFile::Adjust()//
{
	LineInfo* pInfo = 0;
	for(int i = 0 ; i < m_LineInfoArray.size(); ++i)
	{
		pInfo = m_LineInfoArray[i];
		if(0 == pInfo)
		{
			continue;
		}

		if (pInfo->type != LINE_SECTION)
		{
			continue;
		}

		string helpStr;

		helpStr = pInfo->strMainData;

		helpStr = Trim(helpStr);

		string sectionName = helpStr.substr(1,helpStr.size() - 1);
		sectionName = sectionName.substr(0,sectionName.size() - 1);

		IniSection* pSection = new IniSection;
		pSection->SetSectionName(sectionName.c_str());
		pSection->m_nLineNo = pInfo->nLineNo;


		AddSection(pSection);

		int nIndex = i+1;
		if(nIndex == m_LineInfoArray.size())
		{
			break;
		}

		for(int j = nIndex; j < m_LineInfoArray.size(); ++j)
		{
			LineInfo* pKeyLine = m_LineInfoArray[j];

			if(0 == pKeyLine)
			{
				continue;
			}

			if (pKeyLine->type == LINE_SECTION)
			{
				break;
			}

			if (pKeyLine->type == LINE_OTHER)
			{
				continue;
			}

			//剩下的都是LINE_PAIR
			pSection->m_nKeyCount++;


			IniKey* pKey = new IniKey;
			pKey->m_nLineNo = pKeyLine->nLineNo;

			//MString keyName,value,help;
			string help = pKeyLine->strMainData;
			help = Trim(help);


			int iIndex = help.find('=');
			string keyName = help.substr(0,iIndex);
			string value = help.substr(iIndex + 1);
			keyName = Trim(keyName);
			value = Trim(value);

			pKey->m_Key = keyName.c_str();
			pKey->m_Value = value.c_str();

			pSection->AddKey(pKey);
		}
	}
}
Ejemplo n.º 11
0
void SelectTranslation(const WCHAR *exePath=NULL)
{
    LANGID langId = GetUserDefaultUILanguage();
    int idx = GetLanguageIndex(langId);
    if (-1 == idx) {
        // try a neutral language if the specific sublanguage isn't available
        langId = MAKELANGID(PRIMARYLANGID(langId), SUBLANG_NEUTRAL);
        idx = GetLanguageIndex(langId);
    }
    if (-1 != idx) {
        gTranslationIdx = idx;
        plogf("sp: Detected language %s (%d)", gLanguages[idx / gTranslationsCount], idx);
    }

    // try to extract the language used by SumatraPDF
    ScopedMem<WCHAR> path;
    if (exePath) {
        path.Set(path::GetDir(exePath));
        path.Set(path::Join(path, PREFS_FILE_NAME));
    }
    if (!file::Exists(path)) {
        path.Set(GetSpecialFolder(CSIDL_APPDATA));
        path.Set(path::Join(path, L"SumatraPDF\\" PREFS_FILE_NAME));
    }
    if (!file::Exists(path))
        return;
    plogf("sp: Found preferences at %S", path);
#ifndef USE_INI_SETTINGS
    ScopedMem<char> data(file::ReadAll(path, NULL));
    if (data) {
        BencObj *root = BencObj::Decode(data);
        if (root && root->Type() == BT_DICT) {
            BencDict *global = static_cast<BencDict *>(root)->GetDict("gp");
            BencString *string = global ? global->GetString("UILanguage") : NULL;
            if (string) {
                plogf("sp: UILanguage from preferences: %s", string->RawValue());
                for (int i = 0; gLanguages[i]; i++) {
                    if (str::Eq(gLanguages[i], string->RawValue())) {
                        gTranslationIdx = i * gTranslationsCount;
                        break;
                    }
                }
            }
        }
        delete root;
    }
#else
    IniFile ini(path);
    IniSection *section = ini.FindSection(NULL);
    IniLine *line = section ? section->FindLine("CurrLangCode") : NULL;
    if (line) {
        plogf("sp: UILanguage from preferences: %s", line->value);
        for (int i = 0; gLanguages[i]; i++) {
            if (str::Eq(gLanguages[i], line->value)) {
                gTranslationIdx = i * gTranslationsCount;
                break;
            }
        }
    }
#endif
}
Ejemplo n.º 12
0
void IniSection::copy (IniSection& _section){
  _section.setName(name);
  _section.setComment(comment);
  _section.vars=vars; // Operator von Qt ueberladen
  _section.vars.setAutoDelete(false);
}
Ejemplo n.º 13
0
int IniFile::KeyCount(const string& section)
{
	//Get the section
    IniSection* iniSection = GetSection(section);
    return iniSection->KeyCount();
}
Ejemplo n.º 14
0
void suPHP::Configuration::readFromFile(File& file) 
    throw (IOException, ParsingException) {
    IniFile ini;
    ini.parse(file);
    if (ini.hasSection("global")) {
        const IniSection& sect = ini.getSection("global");
        const std::vector<std::string> keys = sect.getKeys();
        std::vector<std::string>::const_iterator i;
        for (i = keys.begin(); i < keys.end(); i++) {
            std::string key = *i;
            std::string value = sect.getValue(key);

            if (key == "logfile")
                this->logfile = value;
            else if (key == "webserver_user")
                this->webserver_user = value;
            else if (key == "docroot") {
                this->docroots = sect.getValues(key);
            } else if (key == "allow_file_group_writeable")
                this->allow_file_group_writeable = this->strToBool(value);
            else if (key == "allow_directory_group_writeable")
                this->allow_directory_group_writeable = this->strToBool(value);
            else if (key == "allow_file_others_writeable")
                this->allow_file_others_writeable = this->strToBool(value);
            else if (key == "allow_directory_others_writeable")
                this->allow_directory_others_writeable = 
                    this->strToBool(value);
            else if (key == "check_vhost_docroot")
                this->check_vhost_docroot = this->strToBool(value);
            else if (key == "errors_to_browser")
                this->errors_to_browser = this->strToBool(value);
            else if (key == "env_path")
                this->env_path = value;
            else if (key == "loglevel")
                this->loglevel = this->strToLogLevel(value);
            else if (key == "min_uid")
                this->min_uid = Util::strToInt(value);
            else if (key == "min_gid")
                this->min_gid = Util::strToInt(value);
            else if (key == "umask")
                this->umask = Util::octalStrToInt(value);
            else if (key == "chroot")
                this->chroot_path = value;
            else 
                throw ParsingException("Unknown option \"" + key + 
                                       "\" in section [global]", 
                                       __FILE__, __LINE__);
        }
    }
    
    // Get handlers / interpreters
    if (ini.hasSection("handlers")) {
        IniSection sect = ini.getSection("handlers");
        const std::vector<std::string> keys = sect.getKeys();
        std::vector<std::string>::const_iterator i;
        for (i = keys.begin(); i < keys.end(); i++) {
            std::string key = *i;
            std::string value = sect.getValue(key);
            std::pair<std::string, std::string> p;
            p.first = key;
            p.second = value;
            this->handlers.insert(p);
        }
    }
    
}
Ejemplo n.º 15
0
bool IniReader::read(istream & is) {
	
	// The current section.
	IniSection * section = NULL;
	
	bool ok = true;
	
	// While lines remain to be extracted
	for(size_t line = 1; is.good(); line++) {
		
		// Get a line to process
		string str;
		getline(is, str);
		
		size_t start = str.find_first_not_of(WHITESPACE);
		if(start == string::npos) {
			// Empty line (only whitespace).
			continue;
		}
		
		if(str[start] == '#' || (start + 1 < str.length() && str[start] == '/' && str[start+1] == '/')) {
			// Whole line was commented, no need to do anything with it. Continue getting the next line.
			continue;
		}
		
		// Section header.
		if(str[start] == '[') {
			
			size_t end = str.find(']', start + 1);
			if(end == string::npos) {
				LogWarning << "invalid header @ line " << line << ": " << str;
				section = NULL;
				ok = false;
				continue;
			}
			
			string sectionName = str.substr(start + 1, end - start - 1);
			transform(sectionName.begin(), sectionName.end(), sectionName.begin(), ::tolower);
			
			LogDebug("found section: \"" << sectionName << "\"");
			section = &sections[sectionName];
			
			// Ignoring rest of the line, not verifying that it's only whitespace / comment
			
			continue;
		}
		
		if(!section) {
			LogWarning << "ignoring non-empty line " << line << " outside a section: " << str;
			ok = false;
			continue;
		}
		
		size_t nameEnd = str.find_first_not_of(ALPHANUM, start);
		if(nameEnd == string::npos) {
			ok = false;
			LogWarning << "missing '=' separator @ line " << line << ": " << str;
			continue;
		} else if(nameEnd == start) {
			ok = false;
			LogWarning << "empty key name @ line " << line << ": " << str;
			continue;
		}
		
		size_t separator = str.find_first_not_of(WHITESPACE, nameEnd);
		if(separator == string::npos || str[separator] != '=') {
			ok = false;
			LogWarning << "missing '=' separator @ line " << line << ": " << str;
			continue;
		}
		
		size_t valueStart = str.find_first_not_of(WHITESPACE, separator + 1);
		if(valueStart == string::npos) {
			// Empty value.
			section->addKey(str.substr(start, nameEnd - start), string());
			continue;
		}
		
		size_t valueEnd;
		if(str[valueStart] == '"') {
			valueStart++;
			valueEnd = str.find_last_of('"');
			arx_assert(valueEnd != string::npos);
			if(valueEnd < valueStart) {
				// The localisation files are broken (missing ending quote), so ignore this error.
				LogDebug("invalid quoted value @ line " << line << ": " << str);
				valueEnd = str.length();
			}
		} else {
			valueEnd = str.find_last_not_of(WHITESPACE) + 1;
			arx_assert(valueEnd != string::npos);
		}
		arx_assert(valueEnd >= valueStart);
		
		section->addKey(str.substr(start, nameEnd - start), str.substr(valueStart, valueEnd - valueStart));
		
		// Ignoring rest of the line, not verifying that it's only whitespace / comment
		
	}
	
	return ok;
}
Ejemplo n.º 16
0
bool IniSection::operator== (IniSection& _section){
  return name==_section.getName();
}
Ejemplo n.º 17
0
int IniParser::parseConfigFile (std::ifstream *configStream, const char *filename, bool parseFullLine)
{
	int ln = 0;
	IniSection *sect = NULL;
	std::string line;
	while (!configStream->fail ())
	{
		getline (*configStream, line);
		ln++;
		if (configStream->fail ())
			break;
		std::string::iterator top = line.begin ();
		while (isspace (*top) && top != line.end ())
			top++;
		// ignore blank lines and comments
		if (top == line.end () || *top == ';' || *top == '#')
			continue;
		// start new section..
		if (*top == '[')
		{
			size_t el = line.find (']');
			if (el == std::string::npos)
			{
				logStream (MESSAGE_ERROR) <<
					"cannot find end delimiter for section '" << line <<
					"' on line " << ln << " infile " << filename << "." << sendLog;
				return -1;
			}
			if (sect)
				push_back (sect);
			sect = new IniSection (line.substr (top - line.begin () + 1, el-1).c_str ());
		}
		else
		{
			if (!sect)
			{
				if (!addDefaultSection)
				{
					logStream (MESSAGE_ERROR) << "value without section on line " << ln << ": " << line <<  sendLog;
					return -1;
				}
				sect = new IniSection ("");
			}
			// now create value..
			enum { NAME, SUFF, VAL, VAL_QUT, VAL_END, LINE_END} pstate = NAME;
			std::string valName;
			std::string valSuffix;
			std::string val;
			std::string comment;
			std::string::iterator es = top;
			for (; es != line.end () && pstate != LINE_END;)
			{
				switch (pstate)
				{
					case NAME:
					case SUFF:
						if (*es == '.')
						{
							if (pstate == SUFF)
								valName += '.';
							valName += line.substr (top - line.begin (), es - top);
							pstate = SUFF;
							top = es + 1;
						}
						else if (*es == '=' || isspace (*es))
						{
							if (pstate == SUFF)
								valSuffix = line.substr (top - line.begin (), es - top);
							else
								valName = line.substr (top - line.begin (), es - top);
							pstate = VAL;
							while (*es != '=' && es != line.end ())
								es++;
							es++;
							while (es != line.end () && isspace (*es))
								es++;
							if (*es == '"')
							{
								pstate = VAL_QUT;
								top = es + 1;
							}
							else
							{
								top = es;
							}
						}
						break;
					case VAL:
						if (isspace (*es))
						{
							pstate = VAL_END;
							if (parseFullLine)
							{
								es  = line.end ();
								while (isspace (*es))
									es--;
							}	
							val = line.substr (top - line.begin (), es - top);
						}
						break;
					case VAL_QUT:
						if (*es == '"')
						{
							pstate = VAL_END;
							if (top == es)
								val = std::string ("");
							else
								val = line.substr (top - line.begin (), es - top);
						}
						break;
					case VAL_END:
						if (*es == ';' || *es == '#')
						{
							do
							{
								es++;
							}
							while (es != line.end () && isspace (*es));

							if (es != line.end ())
							{
								comment = line.substr (es - line.begin ());
								es = line.end ();
							}
							pstate = LINE_END;
						}
						break;
					case LINE_END:
						break;
				}
				if (es != line.end ())
					es++;
			}
			if (pstate == VAL_QUT)
			{
				logStream (MESSAGE_ERROR) << "missing \" on line " << ln
					<< " of file " << filename << sendLog;
				return -1;
			}
			if (pstate == VAL)
			{
				val = line.substr (top - line.begin (), es - top);
				pstate = VAL_END;
			}
			if (!(pstate == VAL_END || pstate == LINE_END))
			{
				logStream (MESSAGE_ERROR) << "invalid configuration line " << ln << " of file " << filename << sendLog;
				return -1;
			}
			#ifdef DEBUG_EXTRA
			std::cout << "Pushing " << valName << " " << valSuffix << " " << val << std::endl;
			#endif				 /* DEBUG_EXTRA */
			sect->push_back (IniValue (valName, valSuffix, val, comment));
			if (valName == "blocked_by")
			{
				sect->createBlockedBy (val);
			}
		}
	}
	if (sect)
		push_back (sect);
	return 0;
}
Ejemplo n.º 18
0
bool IniFile::Load(){
  sections.clear();
  char buffer[1024];
  QString line;
  IniSection* momsection;
  IniVar* momvar;
  bool beforeFirstSection=true;
  int LineType;
  QString str1,str2,str3;

  file.setName(filename);
  if (!file.exists()){
#ifdef DEBUG
    cerr << "\nFile doesn't exist: " << filename.latin1();
#else

#endif
    return false;
  }
  if (!file.open( QIODevice::ReadOnly)) {
#ifdef DEBUG
    cerr << "\nCannot read File: " << filename.latin1();
#else

#endif
    return false;
  }
  // Zeile für Zeile auslesen und zuordnen
  while( (file.readLine(buffer,1024))>0 ){
    line=QString(buffer);
    str1="";
    str2="";
    str3="";
    LineType=getLineType(line,str1,str2,str3);
    switch (LineType){
      case EMPTY:
      break;
      case COMMENT:
        if (beforeFirstSection){
          comment.append(str1);
        }else{
          momsection->addComment(str1);
        }
      break;
      case SECTION:
        beforeFirstSection=false;
        momsection=new IniSection(str1);
        sections.append(momsection);
      break;
      case VAR:
        if (beforeFirstSection){ // wird als Kommentar gewertet
          comment.append(str1);
        }else{                    // Normale Variable
          momvar=new IniVar(str1,str2,str3);
          momsection->vars.append(momvar);
        }
      break;
    }
  }

  file.close();

  bloaded=true;
  return true;
}
Ejemplo n.º 19
0
bool IniReader::read(std::istream & is) {
	
	// The current section
	IniSection * section = NULL;
	
	bool ok = true;
	
	bool readline = true;
	
	std::string str;
	
	// While lines remain to be extracted
	for(size_t line = 1; is.good(); line++) {
		
		// Get a line to process
		if(readline) {
			str.clear();
			getline(is, str);
		} else {
			readline = true;
		}
		
		size_t start = str.find_first_not_of(WHITESPACE);
		if(start == std::string::npos) {
			// Empty line (only whitespace)
			continue;
		}
		
		if(str[start] == '#'
		   || (start + 1 < str.length() && str[start] == '/' && str[start+1] == '/')) {
			// Whole line was commented, no need to do anything with it. Continue getting the next line
			continue;
		}
		
		// Section header
		if(str[start] == '[') {
			
			size_t end = str.find(']', start + 1);
			if(end == std::string::npos) {
				LogDebug("invalid header @ line " << line << ": " << str);
				end = str.find_first_not_of(ALPHANUM, start + 1);
				if(end == std::string::npos) {
					end = str.length();
				}
			}
			
			std::string sectionName = str.substr(start + 1, end - start - 1);
			transform(sectionName.begin(), sectionName.end(), sectionName.begin(), ::tolower);
			
			LogDebug("found section: \"" << sectionName << "\"");
			section = &sections[sectionName];
			
			// Ignoring rest of the line, not verifying that it's only whitespace / comment
			
			continue;
		}
		
		if(!section) {
			LogWarning << "Ignoring non-empty line " << line << " outside a section: " << str;
			ok = false;
			continue;
		}
		
		size_t nameEnd = str.find_first_not_of(ALPHANUM, start);
		if(nameEnd == std::string::npos) {
			ok = false;
			LogWarning << "Missing '=' separator @ line " << line << ": " << str;
			continue;
		} else if(nameEnd == start) {
			ok = false;
			LogWarning << "Empty key name @ line " << line << ": " << str;
			continue;
		}
		
		bool quoted = false;
		
		size_t separator = str.find_first_not_of(WHITESPACE, nameEnd);
		if(separator == std::string::npos || str[separator] != '=') {
			if(separator != std::string::npos && separator + 1 < str.length()
			   && str[separator] == '"' && str[separator + 1] == '=') {
				LogDebug("found '\"=' instead of '=\"' @ line " << line << ": " << str);
				quoted = true;
			} else {
				ok = false;
				LogWarning << "Missing '=' separator @ line " << line << ": " << str;
				continue;
			}
		}
		
		size_t valueStart = str.find_first_not_of(WHITESPACE, separator + 1);
		if(valueStart == std::string::npos) {
			// Empty value.
			section->addKey(str.substr(start, nameEnd - start), std::string());
			continue;
		}
		
		std::string key = str.substr(start, nameEnd - start);
		std::string value;
		
		if(quoted || str[valueStart] == '"') {
			valueStart++;
			size_t valueEnd = str.find_last_of('"');
			arx_assert(valueEnd != std::string::npos);
			
			if(valueEnd < valueStart) {
				
				// The localisation files are broken (missing ending quote)
				// But the spanish localisation files hae erroneous newlines in some values
				LogDebug("invalid quoted value @ line " << line << ": " << str);
				
				valueEnd = str.find_last_not_of(WHITESPACE) + 1;
				arx_assert(valueEnd >= valueStart);
				value = str.substr(valueStart, valueEnd - valueStart);
				
				// Add following lines until we find either a terminating quote,
				// an empty or commented line, a new section or a new key
				for(; is.good(); line++) {
					
					str.clear();
					getline(is, str);
					
					size_t start = str.find_first_not_of(WHITESPACE);
					if(start == std::string::npos) {
						// Empty line (only whitespace)
						break;
					}
					
					if(str[start] == '#'
					   || (start + 1 < str.length() && str[start] == '/' && str[start+1] == '/')) {
						// Whole line was commented
						break;
					}
					
					if(str[start] == '[') {
						// New section
						line--, readline = false;
						break;
					}
					
					size_t nameEnd = str.find_first_not_of(ALPHANUM, start);
					if(nameEnd != std::string::npos && nameEnd != start) {
						size_t separator = str.find_first_not_of(WHITESPACE, nameEnd);
						if(separator != std::string::npos && str[separator] == '=') {
							// New key
							line--, readline = false;
							break;
						}
					}
					
					// Replace newlines with spaces!
					value += ' ';
					
					size_t valueEnd = str.find_last_of('"');
					if(valueEnd != std::string::npos) {
						// End of multi-line value
						value += str.substr(start, valueEnd - start);
						break;
					}
					
					valueEnd = str.find_last_not_of(WHITESPACE) + 1;
					arx_assert(valueEnd > start);
					value += str.substr(start, valueEnd - start);
				}
				
			} else {
				value = str.substr(valueStart, valueEnd - valueStart);
			}
			
		} else {
			size_t valueEnd = str.find_last_not_of(WHITESPACE) + 1;
			arx_assert(valueEnd != std::string::npos);
			arx_assert(valueEnd >= valueStart);
			value = str.substr(valueStart, valueEnd - valueStart);
		}
		
		section->addKey(key, value);
		
		// Ignoring rest of the line, not verifying that it's only whitespace / comment
		
	}
	
	return ok;
}