unsigned Document<Formatter>::ParseElement(Formatter& formatter) { Formatter::InteriorSection section; if (!formatter.TryBeginElement(section)) return ~0u; unsigned e = ~0u; { ElementDesc newElement; newElement._name = section; newElement._firstAttribute = ~0u; newElement._firstChild = ~0u; newElement._nextSibling = ~0u; _elements.push_back(newElement); e = (unsigned)_elements.size()-1; } auto lastChild = ~0u; auto lastAttribute = ~0u; for (;;) { auto next = formatter.PeekNext(); if (next == Formatter::Blob::BeginElement) { auto newElement = ParseElement(formatter); if (lastChild == ~0u) { _elements[e]._firstChild = newElement; } else { _elements[lastChild]._nextSibling = newElement; } lastChild = newElement; } else if (next == Formatter::Blob::AttributeName) { Formatter::InteriorSection name; Formatter::InteriorSection value; if (!formatter.TryAttribute(name, value)) Throw(FormatException( "Error while reading attribute in StreamDOM", formatter.GetLocation())); AttributeDesc attrib; attrib._name = name; attrib._value = value; attrib._nextSibling = ~0u; _attributes.push_back(attrib); auto a = (unsigned)_attributes.size()-1; if (lastAttribute == ~0u) { _elements[e]._firstAttribute = a; } else { _attributes[lastAttribute]._nextSibling = a; } lastAttribute = a; } else if (next == Formatter::Blob::EndElement) { break; } else { Throw(FormatException( StringMeld<128>() << "Got unexpected blob type (" << unsigned(next) << ") while parsing element in StreamDOM", formatter.GetLocation())); } } if (!formatter.TryEndElement()) Throw(FormatException( "Expected end element in StreamDOM", formatter.GetLocation())); return e; }
void AccessorDeserialize( Formatter& formatter, void* obj, const ClassAccessors& props) { using Blob = Formatter::Blob; using CharType = Formatter::value_type; auto charTypeCat = ImpliedTyping::TypeOf<CharType>()._type; for (;;) { switch (formatter.PeekNext()) { case Blob::AttributeName: { typename Formatter::InteriorSection name, value; if (!formatter.TryAttribute(name, value)) Throw(FormatException("Error in begin element", formatter.GetLocation())); auto arrayBracket = std::find(name._start, name._end, '['); if (arrayBracket == name._end) { if (!props.TryOpaqueSet( obj, Hash64(name._start, name._end), value._start, ImpliedTyping::TypeDesc(charTypeCat, uint16(value._end - value._start)), true)) { LogWarning << "Failure while assigning property during deserialization -- " << Conversion::Convert<std::string>(std::basic_string<CharType>(name._start, name._end)); } } else { auto arrayIndex = XlAtoUI32((const char*)(arrayBracket+1)); if (!props.TryOpaqueSet( obj, Hash64(name._start, arrayBracket), arrayIndex, value._start, ImpliedTyping::TypeDesc(charTypeCat, uint16(value._end - value._start)), true)) { LogWarning << "Failure while assigning array property during deserialization -- " << Conversion::Convert<std::string>(std::basic_string<CharType>(name._start, name._end)); } } } break; case Blob::EndElement: case Blob::None: return; case Blob::BeginElement: { typename Formatter::InteriorSection eleName; if (!formatter.TryBeginElement(eleName)) Throw(FormatException("Error in begin element", formatter.GetLocation())); auto created = props.TryCreateChild(obj, Hash64(eleName._start, eleName._end)); if (created.first) { AccessorDeserialize(formatter, created.first, *created.second); } else { LogWarning << "Couldn't find a match for element name during deserialization -- " << Conversion::Convert<std::string>(std::basic_string<CharType>(eleName._start, eleName._end)); formatter.SkipElement(); } if (!formatter.TryEndElement()) Throw(FormatException("Expecting end element", formatter.GetLocation())); break; } } } }