Document<Formatter>::Document(Formatter& formatter) { _elements.reserve(32); _attributes.reserve(64); _firstRootAttribute = ~0u; // Parse the input formatter, building a tree // of elements and a list of attributes. // We can start with several top-level elements unsigned lastEle = ~0u; unsigned lastAttrib = ~0u; for (;;) { switch (formatter.PeekNext()) { case Formatter::Blob::AttributeName: { Formatter::InteriorSection name, value; if (formatter.TryAttribute(name, value)) { _attributes.push_back(AttributeDesc{name, value, ~0u}); if (lastAttrib != ~0u) { _attributes[lastAttrib]._nextSibling = unsigned(_attributes.size()-1); } else { _firstRootAttribute = unsigned(_attributes.size()-1); } lastAttrib = unsigned(_attributes.size()-1); } } continue; case Formatter::Blob::BeginElement: { auto newEle = ParseElement(formatter); if (newEle == ~0u) break; if (lastEle != ~0u) _elements[lastEle]._nextSibling = newEle; lastEle = newEle; } continue; default: break; } break; } // Sometimes we serialize in some elements as a "Document" // In these cases, there may be more data in the file... // if (formatter.PeekNext() != Formatter::Blob::None) // Throw(FormatException( // "Unexpected trailing characters in StreamDOM", formatter.GetLocation())); }
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; } } } }