#include #include bool ZIniReader::Read(const char* data, size_t length) { /* Algorithm: 1) Read a line, ignore blank lines and comment lines 2) If line is KVP 2.1) No section? -> Error 2.2) Section exists? -> Parse KVP 2.2.1) Takes form of K = V? -> Add KVP 2.2.2) Doesn't? -> Error 3) Else if section 3.1) If already seen section -> Error 3.2) Create section hashtable, insert it 4) Next line */ ClearData(); ErrorMessage.Clear(); ZHashMap* currentSection = NULL; size_t i = 0; //Current index into file data size_t lineStart = 0; //Start of line size_t lineLength; uint32_t lineNumber = 1; //Parse loop while(i < length) { char c = data[i]; i++; //Treat final character as EOL too if(i < length) { //Split on \n or \r if(c != 0x0A && c != 0x0D) continue; else //Found EOL character { //Line length does NOT include EOL character lineLength = i - 1 - lineStart; } } else //Final line, don't remove extra character lineLength = i - lineStart; //Line must be non-blank if(lineLength > 0 && data[lineStart] != '\n') { //Get pointer to start of line const char* line = &data[lineStart]; //Ignore comments if(line[0] != ';' && line [0] != '#') { //Section name if(line[0] == '[') { size_t j=1; //Start after '[' //Read until closing '] or EOL while(j* table = new(std::nothrow) ZHashMap(); if(table != NULL) { //Add mapping StringSectionMap.Put(sectionName, table); Sections.PushBack(table); SectionNames.PushBack(sectionName); //Save this as the current section currentSection = table; } else { SetError("Out of memory", lineNumber); return false; } } else if(!isspace(line[0])) //Not a space, not comment, not section -> KVP { //Did we find a section first? if(currentSection != NULL) { size_t j=0; //length of key //Scan until space, equals sign, or EOL while(jPut(key, ""); } else { ZString val(&line[j], lineLength-j); currentSection->Put(key, val); } } else { SetError("Values must be in a section", lineNumber); return false; } } else { SetError("Invalid line. Must be a section, comment, or value", lineNumber); return false; } } } //if(non-blank line) //Check for \r \n pattern if(c == '\r') //we expect a \n, but verify { if(i < length && data[i] == '\n') i++; } //Start on next line lineStart = i; lineNumber++; } return !Sections.Empty(); } /*************************************************************************/ const ZHashMap* ZIniReader::GetSection(const ZString& sectionName) { ZHashMap* >::Iterator it = StringSectionMap.Find(sectionName); if(it.HasCurrent()) return it.GetValue(); return NULL; } /*************************************************************************/ void ZIniReader::SetError(const char* message, uint32_t line) { ZStringAlgo::BuildPrintf(ErrorMessage, "Line %u: %s", line, message); //Clear all data ClearData(); } /*************************************************************************/ void ZIniReader::ClearData() { for(size_t i = 0; i < Sections.Size(); i++) delete Sections[i]; Sections.Clear(); SectionNames.Clear(); StringSectionMap.Clear(); } /*************************************************************************/ void ZIniReader::GetKVTree(ZKVTree& _kvtree) { for(size_t i = 0; i < Sections.Size(); i++) { ZHashMap* hmap = Sections[i]; ZHashMap::Iterator it = hmap->Begin(); for(; it != hmap->End(); ++it) { ZString key = SectionNames[i]+"."+it.GetKey(); ZString& value = it.GetValue(); _kvtree.Put(key, value); } } }