void XMLWriter_File::ElementXMB(const XMBFile& file, XMBElement el) { XMLWriter_Element writer(*this, file.GetElementString(el.GetNodeName()).c_str()); XERO_ITER_ATTR(el, attr) writer.Attribute(file.GetAttributeString(attr.Name).c_str(), attr.Value); XERO_ITER_EL(el, child) ElementXMB(file, child); }
void CParamNode::ApplyLayer(const XMBFile& xmb, const XMBElement& element, const wchar_t* sourceIdentifier /*= NULL*/) { ResetScriptVal(); std::string name = xmb.GetElementString(element.GetNodeName()); // TODO: is GetElementString inefficient? CStrW value = element.GetText().FromUTF8(); bool hasSetValue = false; // Look for special attributes int at_disable = xmb.GetAttributeID("disable"); int at_replace = xmb.GetAttributeID("replace"); int at_op = xmb.GetAttributeID("op"); int at_datatype = xmb.GetAttributeID("datatype"); enum op { INVALID, ADD, MUL } op = INVALID; bool replacing = false; { XERO_ITER_ATTR(element, attr) { if (attr.Name == at_disable) { m_Childs.erase(name); return; } else if (attr.Name == at_replace) { m_Childs.erase(name); replacing = true; } else if (attr.Name == at_op) { if (std::wstring(attr.Value.begin(), attr.Value.end()) == L"add") op = ADD; else if (std::wstring(attr.Value.begin(), attr.Value.end()) == L"mul") op = MUL; else LOGWARNING("Invalid op '%ls'", attr.Value); } } } { XERO_ITER_ATTR(element, attr) { if (attr.Name == at_datatype && std::wstring(attr.Value.begin(), attr.Value.end()) == L"tokens") { CParamNode& node = m_Childs[name]; // Split into tokens std::vector<std::wstring> oldTokens; std::vector<std::wstring> newTokens; if (!replacing && !node.m_Value.empty()) // ignore the old tokens if replace="" was given boost::algorithm::split(oldTokens, node.m_Value, boost::algorithm::is_space(), boost::algorithm::token_compress_on); if (!value.empty()) boost::algorithm::split(newTokens, value, boost::algorithm::is_space(), boost::algorithm::token_compress_on); // Merge the two lists std::vector<std::wstring> tokens = oldTokens; for (size_t i = 0; i < newTokens.size(); ++i) { if (newTokens[i][0] == L'-') { std::vector<std::wstring>::iterator tokenIt = std::find(tokens.begin(), tokens.end(), newTokens[i].substr(1)); if (tokenIt != tokens.end()) tokens.erase(tokenIt); else LOGWARNING("[ParamNode] Could not remove token '%s' from node '%s'%s; not present in list nor inherited (possible typo?)", utf8_from_wstring(newTokens[i].substr(1)), name, sourceIdentifier ? (" in '" + utf8_from_wstring(sourceIdentifier) + "'").c_str() : ""); } else { if (std::find(oldTokens.begin(), oldTokens.end(), newTokens[i]) == oldTokens.end()) tokens.push_back(newTokens[i]); } } node.m_Value = boost::algorithm::join(tokens, L" "); hasSetValue = true; break; } } } // Add this element as a child node CParamNode& node = m_Childs[name]; if (op != INVALID) { // TODO: Support parsing of data types other than fixed; log warnings in other cases fixed oldval = node.ToFixed(); fixed mod = fixed::FromString(CStrW(value)); switch (op) { case ADD: node.m_Value = (oldval + mod).ToString().FromUTF8(); break; case MUL: node.m_Value = (oldval.Multiply(mod)).ToString().FromUTF8(); break; } hasSetValue = true; } if (!hasSetValue) node.m_Value = value; // We also need to reset node's script val, even if it has no children // or if the attributes change. node.ResetScriptVal(); // Recurse through the element's children XERO_ITER_EL(element, child) { node.ApplyLayer(xmb, child, sourceIdentifier); }