void checkNeedMore() { // Here we will work around QXmlSimpleReader strangeness and self-closing tags. // The problem is that endElement() is called when the '/' is read, not when // the final '>' is read. This is a potential problem when obtaining unprocessed // bytes from StreamInput after this event, as the '>' character will end up // in the unprocessed chunk. To work around this, we need to advance StreamInput's // internal byte processing, but not the xml character data. This way, the '>' // will get processed and will no longer be in the unprocessed return, but // QXmlSimpleReader can still read it. To do this, we call StreamInput::readNext // with 'peek' mode. QChar c = in->readNext(true); // peek if(c == QXmlInputSource::EndOfData) { needMore = true; } else { // We'll assume the next char is a '>'. If it isn't, then // QXmlSimpleReader will deal with that problem on the next // parse. We don't need to take any action here. needMore = false; // there should have been a pending event Parser::Event *e = eventList.first(); if(!eventList.isEmpty()) { e->setActualString(e->actualString() + '>'); in->resetLastData(); } } }
bool XmlProtocol::processStep() { Parser::Event pe; notify = 0; transferItemList.clear(); if(state != Closing && (state == RecvOpen || stepAdvancesParser())) { // if we get here, then it's because we're in some step that advances the parser pe = xml.readNext(); if(!pe.isNull()) { // note: error/close events should be handled for ALL steps, so do them here switch(pe.type()) { case Parser::Event::DocumentOpen: { transferItemList += TransferItem(pe.actualString(), false); //stringRecv(pe.actualString()); break; } case Parser::Event::DocumentClose: { transferItemList += TransferItem(pe.actualString(), false); //stringRecv(pe.actualString()); if(incoming) { sendTagClose(); event = ESend; peerClosed = true; state = Closing; } else { event = EPeerClosed; } return true; } case Parser::Event::Element: { QDomElement e = elemDoc.importNode(pe.element(),true).toElement(); transferItemList += TransferItem(e, false); //elementRecv(pe.element()); break; } case Parser::Event::Error: { if(incoming) { // If we get a parse error during the initial element exchange, // flip immediately into 'open' mode so that we can report an error. if(state == RecvOpen) { sendTagOpen(); state = Open; } return handleError(); } else { event = EError; errorCode = ErrParse; return true; } } } } else { if(state == RecvOpen || stepRequiresElement()) { need = NNotify; notify |= NRecv; return false; } } } return baseStep(pe); }