void VersionInfoFactory::ParseOffsets(TiXmlElement * parent, VersionInfo* target, bool initial) { // we parse the groups iteratively instead of recursively // breadcrubs acts like a makeshift stack // first pair entry stores the current element of that level // second pair entry the group object from OffsetGroup typedef triple< TiXmlElement *, OffsetGroup *, INVAL_TYPE> groupTriple; vector< groupTriple > breadcrumbs; { TiXmlElement* pEntry; // we get the <Offsets>, look at the children pEntry = parent->FirstChildElement(); if(!pEntry) return; const char *cstr_invalid = parent->Attribute("valid"); INVAL_TYPE parent_inval = NOT_SET; if(cstr_invalid) { if(strcmp(cstr_invalid,"false") == 0) parent_inval = IS_INVALID; else if(strcmp(cstr_invalid,"true") == 0) parent_inval = IS_VALID; } OffsetGroup * currentGroup = reinterpret_cast<OffsetGroup *> (target); currentGroup->setInvalid(parent_inval); breadcrumbs.push_back(groupTriple(pEntry,currentGroup, parent_inval)); } // work variables OffsetGroup * currentGroup = 0; TiXmlElement * currentElem = 0; INVAL_TYPE parent_inval = NOT_SET; //cerr << "<Offsets>"<< endl; while(1) { // get current work variables currentElem = breadcrumbs.back().first; currentGroup = breadcrumbs.back().second; parent_inval = breadcrumbs.back().third; // we reached the end of the current group? if(!currentElem) { // go one level up breadcrumbs.pop_back(); // exit if no more work if(breadcrumbs.empty()) { break; } else { //cerr << "</group>" << endl; continue; } } if(!currentGroup) { groupTriple & gp = breadcrumbs.back(); gp.first = gp.first->NextSiblingElement(); continue; } // skip non-elements if (currentElem->Type() != TiXmlNode::ELEMENT) { groupTriple & gp = breadcrumbs.back(); gp.first = gp.first->NextSiblingElement(); continue; } // we have a valid current element and current group // get properties string type = currentElem->Value(); std::transform(type.begin(), type.end(), type.begin(), ::tolower); const char *cstr_name = currentElem->Attribute("name"); if(!cstr_name) { // ERROR, missing attribute } // evaluate elements const char *cstr_value = currentElem->Attribute("value"); const char *cstr_invalid = currentElem->Attribute("valid"); INVAL_TYPE child_inval = parent_inval; if(cstr_invalid) { if(strcmp(cstr_invalid,"false") == 0) child_inval = IS_INVALID; else if(strcmp(cstr_invalid,"true") == 0) child_inval = IS_VALID; } if(type == "group") { // create or get group OffsetGroup * og; if(initial) og = currentGroup->createGroup(cstr_name); else og = currentGroup->getGroup(cstr_name); // advance this level to the next element groupTriple & gp = breadcrumbs.back(); gp.first = currentElem->NextSiblingElement(); if(!og) { string fullname = currentGroup->getFullName() + cstr_name; throw Error::MissingMemoryDefinition("group", fullname); } // add a new level that will be processed in the next step breadcrumbs.push_back(groupTriple(currentElem->FirstChildElement(), og, child_inval)); og->setInvalid(child_inval); continue; } else if(type == "address") { if(child_inval == NOT_SET) child_inval = IS_VALID; if(initial) { currentGroup->createAddress(cstr_name); } else if(cstr_value) { currentGroup->setAddress(cstr_name, cstr_value, child_inval); } else { currentGroup->setAddressValidity(cstr_name, child_inval); } } else if(type == "offset") { if(child_inval == NOT_SET) child_inval = IS_VALID; if(initial) { currentGroup->createOffset(cstr_name); } else if(cstr_value) { currentGroup->setOffset(cstr_name, cstr_value, child_inval); } else { currentGroup->setOffsetValidity(cstr_name, child_inval); } } else if(type == "string") { if(child_inval == NOT_SET) child_inval = IS_VALID; if(initial) { currentGroup->createString(cstr_name); } else if(cstr_value) { currentGroup->setString(cstr_name, cstr_value, child_inval); } else { currentGroup->setStringValidity(cstr_name, child_inval); } } else if(type == "hexvalue") { if(child_inval == NOT_SET) child_inval = IS_VALID; if(initial) { currentGroup->createHexValue(cstr_name); } else if(cstr_value) { currentGroup->setHexValue(cstr_name, cstr_value, child_inval); } else { currentGroup->setHexValueValidity(cstr_name, child_inval); } } // advance to next element groupTriple & gp = breadcrumbs.back(); gp.first = currentElem->NextSiblingElement(); continue; } //cerr << "</Offsets>"<< endl; }